More cleaning up, add preliminary MDEC API

This commit is contained in:
spicyjpeg 2024-09-15 22:42:20 +02:00
parent d6b66d4f18
commit a747dabd76
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
27 changed files with 1374 additions and 266 deletions

View File

@ -24,36 +24,12 @@ project(
HOMEPAGE_URL "https://github.com/spicyjpeg/573in1" HOMEPAGE_URL "https://github.com/spicyjpeg/573in1"
) )
include(cmake/options.cmake)
## Source files
set( set(
RELEASE_INFO "${PROJECT_NAME} ${PROJECT_VERSION} - (C) 2022-2024 spicyjpeg" ps1Sources
CACHE STRING "Executable description and version string (optional)"
)
set(
RELEASE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}"
CACHE STRING "CD-ROM image and release package file name"
)
string(TOUPPER "${RELEASE_NAME}" _cdVolumeName)
string(REGEX REPLACE "[^0-9A-Z_]" "_" _cdVolumeName "${_cdVolumeName}")
set(
CD_VOLUME_NAME "${_cdVolumeName}"
CACHE STRING "CD-ROM image volume label"
)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
find_program(
CHDMAN_PATH chdman
PATHS
"C:/Program Files/MAME"
"C:/Program Files (x86)/MAME"
"/opt/mame"
DOC "Path to MAME chdman tool (optional)"
)
## Files common to all executables
add_library(
common OBJECT
#src/libc/crt0.c #src/libc/crt0.c
src/libc/cxxsupport.cpp src/libc/cxxsupport.cpp
src/libc/malloc.c src/libc/malloc.c
@ -66,75 +42,61 @@ add_library(
src/ps1/system.s src/ps1/system.s
src/ps1/unhandledexc.c src/ps1/unhandledexc.c
) )
target_include_directories( set(
common PUBLIC vendorSources
src src/vendor/ff.c
src/libc src/vendor/ffunicode.c
src/vendor/miniz.c
src/vendor/printf.c
src/vendor/qrcodegen.c
) )
target_compile_options(
common PUBLIC set(
-Wall commonSources
-Wextra src/common/args.cpp
-Wno-unused-parameter src/common/gpu.cpp
$<$<COMPILE_LANGUAGE:CXX>: src/common/gpufont.cpp
-Wno-pmf-conversions src/common/io.cpp
> src/common/ioboard.cpp
src/common/mdec.cpp
src/common/mdec.s
src/common/pad.cpp
src/common/rom.cpp
src/common/romdrivers.cpp
src/common/spu.cpp
) )
target_compile_definitions( set(
common PUBLIC fsSources
VERSION="${PROJECT_VERSION}"
EXTERNAL_DATA_DIR="hdd:/${PROJECT_NAME}"
)
link_libraries(common)
function(addPS1Executable name address stackTop)
add_executable(${name} ${ARGN})
target_link_options(${name} PRIVATE -Ttext=0x${address})
add_custom_command(
TARGET ${name} POST_BUILD
BYPRODUCTS "${name}.psexe"
COMMAND
"${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/tools/convertExecutable.py"
-r "${RELEASE_INFO}"
-s 0x${stackTop}
"$<TARGET_FILE:${name}>"
"${name}.psexe"
VERBATIM
)
endfunction()
## Main executable
# IMPORTANT: these addresses assume the boot executable's size (including code,
# heap and stack allocations as well as the resource archive) is <576 KB
# (0x90000 bytes).
addPS1Executable(
main 800a0000 801dfff0
src/common/fs/fat.cpp src/common/fs/fat.cpp
src/common/fs/file.cpp src/common/fs/file.cpp
src/common/fs/iso9660.cpp src/common/fs/iso9660.cpp
src/common/fs/misc.cpp src/common/fs/misc.cpp
src/common/fs/zip.cpp src/common/fs/zip.cpp
)
set(
storageSources
src/common/storage/ata.cpp src/common/storage/ata.cpp
src/common/storage/atapi.cpp src/common/storage/atapi.cpp
src/common/storage/device.cpp src/common/storage/device.cpp
)
set(
utilSources
src/common/util/hash.cpp src/common/util/hash.cpp
src/common/util/log.cpp src/common/util/log.cpp
src/common/util/misc.cpp src/common/util/misc.cpp
src/common/util/string.cpp src/common/util/string.cpp
src/common/util/string.s src/common/util/string.s
src/common/util/tween.cpp src/common/util/tween.cpp
src/common/args.cpp )
src/common/gpu.cpp
src/common/gpufont.cpp set(
src/common/io.cpp mainSources
src/common/ioboard.cpp ${ps1Sources}
src/common/pad.cpp ${vendorSources}
src/common/rom.cpp ${commonSources}
src/common/romdrivers.cpp ${fsSources}
src/common/spu.cpp ${storageSources}
${utilSources}
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
@ -155,82 +117,109 @@ addPS1Executable(
src/main/uibase.cpp src/main/uibase.cpp
src/main/uicommon.cpp src/main/uicommon.cpp
src/main/uimodals.cpp src/main/uimodals.cpp
src/vendor/ff.c
src/vendor/ffunicode.c
src/vendor/miniz.c
src/vendor/printf.c
src/vendor/qrcodegen.c
) )
target_compile_definitions( set(
main PRIVATE launcherSources
# Logging options ${ps1Sources}
ENABLE_APP_LOGGING=1 ${storageSources}
ENABLE_CART_IO_LOGGING=1 ${utilSources}
ENABLE_CART_DATA_LOGGING=1
ENABLE_IO_LOGGING=1
ENABLE_ROM_LOGGING=1
ENABLE_STORAGE_LOGGING=1
ENABLE_FS_LOGGING=1
# Security cartridge driver options
#ENABLE_DUMMY_CART_DRIVER=1
ENABLE_X76F041_CART_DRIVER=1
#ENABLE_X76F100_CART_DRIVER=1
ENABLE_ZS01_CART_DRIVER=1
# Misc. options
ENABLE_LOG_BUFFER=1
#ENABLE_ARGV=1
#ENABLE_PCDRV=1
ENABLE_PS1_CONTROLLER=1
ENABLE_AUTOBOOT=1
)
## Boot stub and executable launchers
# NOTE: in order to make sure -Os is passed after -Og or -O3 (see
# cmake/setup.cmake) and thus overrides it, it must be added to a separate
# target rather than directly to the executables.
add_library(bootFlags INTERFACE)
target_compile_options(bootFlags INTERFACE -Os)
target_compile_definitions(
bootFlags INTERFACE
$<$<CONFIG:Debug>:
#ENABLE_ARGV=1
#ENABLE_LOGGING=1
NDEBUG=1
>
)
function(addLauncher address stackTop)
addPS1Executable(
launcher${address} ${address} ${stackTop}
src/common/storage/ata.cpp
src/common/storage/atapi.cpp
src/common/storage/device.cpp
src/common/util/hash.cpp
src/common/util/misc.cpp
src/common/args.cpp src/common/args.cpp
src/common/io.cpp src/common/io.cpp
src/launcher/exchandler.s src/launcher/exchandler.s
src/launcher/main.cpp src/launcher/main.cpp
src/libc/crt0.c src/libc/crt0.c
src/vendor/printf.c
) )
target_link_libraries(launcher${address} PRIVATE bootFlags) set(
bootStubSources
${ps1Sources}
${utilSources}
src/boot/crt0.s
src/boot/main.cpp
src/common/io.cpp
)
## Flags and compile-time options
set(
commonOptions
-Wall
-Wextra
-Wno-unused-parameter
$<$<COMPILE_LANGUAGE:CXX>:
-Wno-pmf-conversions
-Wno-delete-non-virtual-dtor
>
)
add_library(mainFlags INTERFACE)
add_library(subExecutableFlags INTERFACE)
target_include_directories(mainFlags INTERFACE src src/libc)
target_include_directories(subExecutableFlags INTERFACE src src/libc)
# NOTE: in order to make sure -Os is passed after -Og or -O3 (see
# cmake/setup.cmake) and thus overrides it, it must be added to a separate
# target rather than directly to the executables.
target_compile_options(mainFlags INTERFACE ${commonOptions})
target_compile_options(subExecutableFlags INTERFACE ${commonOptions} -Os)
target_compile_definitions(
mainFlags INTERFACE
${mainOptions}
VERSION="${PROJECT_VERSION}"
EXTERNAL_DATA_DIR="hdd:/${PROJECT_NAME}"
)
target_compile_definitions(
subExecutableFlags INTERFACE
${subExecutableOptions}
NDEBUG=1
)
## Main executables
function(addPS1Executable name address stackTop)
add_executable (${name} ${ARGN})
target_link_options(${name} PRIVATE -Ttext=0x${address})
add_custom_command(
TARGET ${name} POST_BUILD
BYPRODUCTS "${name}.psexe"
COMMAND
"${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/tools/convertExecutable.py"
-r "${RELEASE_INFO}"
-s 0x${stackTop}
"$<TARGET_FILE:${name}>"
"${name}.psexe"
VERBATIM
)
endfunction() endfunction()
# IMPORTANT: these addresses assume the launcher's total size (including code, # IMPORTANT: these addresses assume the boot executable's size (including code,
# heap and stack allocations, but excluding the executable header) is <12 KB # heap and stack allocations as well as the resource archive, but excluding the
# (0x3000 bytes). # executable header) is 576 KB (0x90000 bytes) or less, and that each launcher's
addLauncher(801fd000 801ffff0) # size is 12 KB (0x3000 bytes) or less.
addLauncher(803fd000 803ffff0) addPS1Executable(main 800a0000 801dfff0 ${mainSources})
addPS1Executable(launcher801fd000 801fd000 801ffff0)
addPS1Executable(launcher803fd000 803fd000 803ffff0)
## Boot stub and resource archive add_library(launcher OBJECT ${launcherSources})
add_library(bootStub OBJECT ${bootStubSources})
target_link_libraries(main PUBLIC mainFlags)
target_link_libraries(launcher PUBLIC subExecutableFlags)
target_link_libraries(bootStub PUBLIC subExecutableFlags)
target_link_libraries(launcher801fd000 PUBLIC launcher)
target_link_libraries(launcher803fd000 PUBLIC launcher)
## Boot stubs and resource archives
file(GLOB_RECURSE assetList RELATIVE "${PROJECT_SOURCE_DIR}" assets/*) file(GLOB_RECURSE assetList RELATIVE "${PROJECT_SOURCE_DIR}" assets/*)
configure_file(assets/about.txt about.txt NEWLINE_STYLE LF) configure_file(assets/about.txt about.txt NEWLINE_STYLE LF)
function(addBootStub name resourceName) function(addBuildVariant name resourceName)
configure_file(${resourceName}.json ${resourceName}.json ESCAPE_QUOTES) configure_file(${resourceName}.json ${resourceName}.json ESCAPE_QUOTES)
add_custom_command( add_custom_command(
@ -250,23 +239,17 @@ function(addBootStub name resourceName)
VERBATIM VERBATIM
) )
addPS1Executable( addPS1Executable(${name} 80010000 0)
${name} 80010000 0
src/boot/crt0.s
src/boot/main.cpp
src/common/util/misc.cpp
src/common/util/string.cpp
src/common/io.cpp
)
addBinaryFile( addBinaryFile(
${name} _resourceArchive _resourceArchiveLength ${name} _resourceArchive _resourceArchiveLength
"${PROJECT_BINARY_DIR}/${resourceName}.zip" "${PROJECT_BINARY_DIR}/${resourceName}.zip"
) )
target_link_libraries(${name} PRIVATE bootFlags)
target_link_libraries(${name} PUBLIC bootStub)
endfunction() endfunction()
addBootStub("${RELEASE_NAME}" resources) addBuildVariant("${RELEASE_NAME}" resources)
addBootStub("${RELEASE_NAME}-tiny" resourcestiny) addBuildVariant("${RELEASE_NAME}-tiny" resourcestiny)
## CD-ROM image ## CD-ROM image

145
cmake/options.cmake Normal file
View File

@ -0,0 +1,145 @@
# 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/>.
cmake_minimum_required(VERSION 3.25)
## External tools
find_package(Python3 REQUIRED COMPONENTS Interpreter)
find_program(
CHDMAN_PATH chdman
PATHS
"C:/Program Files/MAME"
"C:/Program Files (x86)/MAME"
"/opt/mame"
DOC "Path to MAME chdman tool for generating CHD image (optional)"
)
## Release information
set(
RELEASE_INFO "${PROJECT_NAME} ${PROJECT_VERSION} - (C) 2022-2024 spicyjpeg"
CACHE STRING "Executable description and version string, placed in the \
executable header (optional)"
)
set(
RELEASE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}"
CACHE STRING "CD-ROM image and release package file name"
)
string(TOUPPER "${RELEASE_NAME}" _cdVolumeName)
string(REGEX REPLACE "[^0-9A-Z_]" "_" _cdVolumeName "${_cdVolumeName}")
set(
CD_VOLUME_NAME "${_cdVolumeName}"
CACHE STRING "CD-ROM image volume label"
)
## Compile-time options
set(
ENABLE_LOG_BUFFER ON
CACHE BOOL "Buffer the last few log messages in memory and enable the \
on-screen log window"
)
set(
ENABLE_APP_LOGGING ON
CACHE BOOL "Log messages from application code"
)
set(
ENABLE_CART_IO_LOGGING ON
CACHE BOOL "Log messages from security cartridge drivers"
)
set(
ENABLE_CART_DATA_LOGGING ON
CACHE BOOL "Log messages from security cartridge data parsers and builders"
)
set(
ENABLE_IO_LOGGING ON
CACHE BOOL "Log messages from System 573 and I/O board drivers"
)
set(
ENABLE_ROM_LOGGING ON
CACHE BOOL "Log messages from ROM/flash drivers"
)
set(
ENABLE_STORAGE_LOGGING ON
CACHE BOOL "Log messages from IDE/ATAPI and other block device drivers"
)
set(
ENABLE_FS_LOGGING ON
CACHE BOOL "Log messages from filesystem drivers"
)
set(
ENABLE_DUMMY_CART_DRIVER OFF
CACHE BOOL "Enable support for simulating a dummy security cartridge (if \
data/test.573 is present in the resource archive)"
)
set(
ENABLE_X76F041_CART_DRIVER ON
CACHE BOOL "Enable support for X76F041 security cartridges"
)
set(
ENABLE_X76F100_CART_DRIVER OFF
CACHE BOOL "Enable support for X76F100 security cartridges"
)
set(
ENABLE_ZS01_CART_DRIVER ON
CACHE BOOL "Enable support for ZS01 security cartridges"
)
set(
ENABLE_ARGV_PARSER OFF
CACHE BOOL "Pass any command-line arguments given to the boot stub (using \
\$a0 and \$a1 as argc/argv) to the main executable"
)
set(
ENABLE_AUTOBOOT ON
CACHE BOOL "Enable support for automatic launching of executables on IDE \
and flash devices (if enabled via DIP switches)"
)
set(
ENABLE_PCDRV OFF
CACHE BOOL "Enable support for browsing the debugger or emulator's host \
filesystem through the PCDRV API"
)
set(
ENABLE_PS1_CONTROLLER ON
CACHE BOOL "Enable support for PS1/PS2 controllers wired to the SIO0 header"
)
set(
mainOptions
$<$<BOOL:${ENABLE_LOG_BUFFER} >:ENABLE_LOG_BUFFER=1>
$<$<BOOL:${ENABLE_APP_LOGGING} >:ENABLE_APP_LOGGING=1>
$<$<BOOL:${ENABLE_CART_IO_LOGGING} >:ENABLE_CART_IO_LOGGING=1>
$<$<BOOL:${ENABLE_CART_DATA_LOGGING} >:ENABLE_CART_DATA_LOGGING=1>
$<$<BOOL:${ENABLE_IO_LOGGING} >:ENABLE_IO_LOGGING=1>
$<$<BOOL:${ENABLE_ROM_LOGGING} >:ENABLE_ROM_LOGGING=1>
$<$<BOOL:${ENABLE_STORAGE_LOGGING} >:ENABLE_STORAGE_LOGGING=1>
$<$<BOOL:${ENABLE_FS_LOGGING} >:ENABLE_FS_LOGGING=1>
$<$<BOOL:${ENABLE_DUMMY_CART_DRIVER} >:ENABLE_DUMMY_CART_DRIVER=1>
$<$<BOOL:${ENABLE_X76F041_CART_DRIVER}>:ENABLE_X76F041_CART_DRIVER=1>
$<$<BOOL:${ENABLE_X76F100_CART_DRIVER}>:ENABLE_X76F100_CART_DRIVER=1>
$<$<BOOL:${ENABLE_ZS01_CART_DRIVER} >:ENABLE_ZS01_CART_DRIVER=1>
$<$<BOOL:${ENABLE_AUTOBOOT} >:ENABLE_AUTOBOOT=1>
$<$<BOOL:${ENABLE_PCDRV} >:ENABLE_PCDRV=1>
$<$<BOOL:${ENABLE_PS1_CONTROLLER} >:ENABLE_PS1_CONTROLLER=1>
)
set(
subExecutableOptions
$<$<BOOL:${ENABLE_ARGV_PARSER}>:ENABLE_ARGV_PARSER=1>
)

View File

@ -90,7 +90,7 @@ int main(int argc, const char **argv) {
util::hexValueToString(&_lengthArg[16], _resourceArchiveLength, 8); util::hexValueToString(&_lengthArg[16], _resourceArchiveLength, 8);
loader.addArgument(_lengthArg); loader.addArgument(_lengthArg);
#ifdef ENABLE_ARGV #ifdef ENABLE_ARGV_PARSER
for (; argc > 0; argc--) { for (; argc > 0; argc--) {
if (!loader.copyArgument(*(argv++))) if (!loader.copyArgument(*(argv++)))
break; break;

View File

@ -246,17 +246,17 @@ bool FATProvider::createDirectory(const char *path) {
} }
File *FATProvider::openFile(const char *path, uint32_t flags) { File *FATProvider::openFile(const char *path, uint32_t flags) {
auto _file = new FATFile(); auto file = new FATFile();
auto error = f_open(&_fs, &(_file->_fd), path, uint8_t(flags)); auto error = f_open(&_fs, &(file->_fd), path, uint8_t(flags));
if (error) { if (error) {
LOG_FS("%s: %s", _FATFS_ERROR_NAMES[error], path); LOG_FS("%s: %s", _FATFS_ERROR_NAMES[error], path);
delete _file; delete file;
return nullptr; return nullptr;
} }
_file->size = f_size(&(_file->_fd)); file->size = f_size(&(file->_fd));
return _file; return file;
} }
/* FatFs library API glue */ /* FatFs library API glue */

View File

@ -52,56 +52,54 @@ Directory::~Directory(void) {
/* Base file and asset provider classes */ /* Base file and asset provider classes */
uint32_t currentSPUOffset = spu::DUMMY_BLOCK_END;
Provider::~Provider(void) { Provider::~Provider(void) {
close(); close();
} }
size_t Provider::loadData(util::Data &output, const char *path) { size_t Provider::loadData(util::Data &output, const char *path) {
auto _file = openFile(path, READ); auto file = openFile(path, READ);
if (!_file) if (!file)
return 0; return 0;
assert(_file->size <= SIZE_MAX); assert(file->size <= SIZE_MAX);
if (!output.allocate(size_t(_file->size))) { if (!output.allocate(size_t(file->size))) {
_file->close(); file->close();
delete _file; delete file;
return 0; return 0;
} }
size_t actualLength = _file->read(output.ptr, output.length); size_t actualLength = file->read(output.ptr, output.length);
_file->close(); file->close();
delete _file; delete file;
return actualLength; return actualLength;
} }
size_t Provider::loadData(void *output, size_t length, const char *path) { size_t Provider::loadData(void *output, size_t length, const char *path) {
auto _file = openFile(path, READ); auto file = openFile(path, READ);
if (!_file) if (!file)
return 0; return 0;
assert(_file->size >= length); assert(file->size >= length);
size_t actualLength = _file->read(output, length); size_t actualLength = file->read(output, length);
_file->close(); file->close();
delete _file; delete file;
return actualLength; return actualLength;
} }
size_t Provider::saveData(const void *input, size_t length, const char *path) { size_t Provider::saveData(const void *input, size_t length, const char *path) {
auto _file = openFile(path, WRITE | ALLOW_CREATE); auto file = openFile(path, WRITE | ALLOW_CREATE);
if (!_file) if (!file)
return 0; return 0;
size_t actualLength = _file->write(input, length); size_t actualLength = file->write(input, length);
_file->close(); file->close();
delete _file; delete file;
return actualLength; return actualLength;
} }
@ -118,22 +116,26 @@ size_t Provider::loadTIM(gpu::Image &output, const char *path) {
data.destroy(); data.destroy();
return 0; return 0;
} }
size_t uploadLength = 0;
if (header->flags & (1 << 3)) { if (header->flags & (1 << 3)) {
auto clut = reinterpret_cast<const gpu::TIMSectionHeader *>(section); auto clut = reinterpret_cast<const gpu::TIMSectionHeader *>(section);
uploadLength += gpu::upload(clut->vram, &clut[1], true);
gpu::upload(clut->vram, &clut[1], true);
section += clut->length; section += clut->length;
} }
auto image = reinterpret_cast<const gpu::TIMSectionHeader *>(section); auto image = reinterpret_cast<const gpu::TIMSectionHeader *>(section);
uploadLength += gpu::upload(image->vram, &image[1], true);
gpu::upload(image->vram, &image[1], true);
data.destroy(); data.destroy();
return data.length; return uploadLength;
} }
size_t Provider::loadVAG(spu::Sound &output, const char *path) { size_t Provider::loadVAG(
spu::Sound &output, uint32_t offset, const char *path
) {
// Sounds should be decompressed and uploaded to the SPU one chunk at a // Sounds should be decompressed and uploaded to the SPU one chunk at a
// time, but whatever. // time, but whatever.
util::Data data; util::Data data;
@ -144,17 +146,16 @@ size_t Provider::loadVAG(spu::Sound &output, const char *path) {
auto header = data.as<const spu::VAGHeader>(); auto header = data.as<const spu::VAGHeader>();
auto body = reinterpret_cast<const uint32_t *>(&header[1]); auto body = reinterpret_cast<const uint32_t *>(&header[1]);
if (!output.initFromVAGHeader(header, currentSPUOffset)) { if (!output.initFromVAGHeader(header, offset)) {
data.destroy(); data.destroy();
return 0; return 0;
} }
currentSPUOffset += spu::upload( auto uploadLength =
currentSPUOffset, body, data.length - sizeof(spu::VAGHeader), true spu::upload(offset, body, data.length - sizeof(spu::VAGHeader), true);
);
data.destroy(); data.destroy();
return data.length; return uploadLength;
} }
struct [[gnu::packed]] BMPHeader { struct [[gnu::packed]] BMPHeader {
@ -186,16 +187,16 @@ public:
}; };
size_t Provider::saveVRAMBMP(gpu::RectWH &rect, const char *path) { size_t Provider::saveVRAMBMP(gpu::RectWH &rect, const char *path) {
auto _file = openFile(path, WRITE | ALLOW_CREATE); auto file = openFile(path, WRITE | ALLOW_CREATE);
if (!_file) if (!file)
return 0; return 0;
BMPHeader header; BMPHeader header;
header.init(rect.w, rect.h, 16); header.init(rect.w, rect.h, 16);
size_t length = _file->write(&header, sizeof(header)); size_t length = file->write(&header, sizeof(header));
util::Data buffer; util::Data buffer;
if (buffer.allocate<uint16_t>(rect.w + 32)) { if (buffer.allocate<uint16_t>(rect.w + 32)) {
@ -224,14 +225,14 @@ size_t Provider::saveVRAMBMP(gpu::RectWH &rect, const char *path) {
*(ptr++) = newValue; *(ptr++) = newValue;
} }
length += _file->write(buffer.ptr, lineLength); length += file->write(buffer.ptr, lineLength);
} }
buffer.destroy(); buffer.destroy();
} }
_file->close(); file->close();
delete _file; delete file;
return length; return length;
} }

View File

@ -113,8 +113,6 @@ public:
/* Base file and asset provider classes */ /* Base file and asset provider classes */
extern uint32_t currentSPUOffset;
class Provider { class Provider {
public: public:
FileSystemType type; FileSystemType type;
@ -153,7 +151,7 @@ public:
virtual size_t saveData(const void *input, size_t length, const char *path); virtual size_t saveData(const void *input, size_t length, const char *path);
size_t loadTIM(gpu::Image &output, const char *path); size_t loadTIM(gpu::Image &output, const char *path);
size_t loadVAG(spu::Sound &output, const char *path); size_t loadVAG(spu::Sound &output, uint32_t offset, const char *path);
size_t saveVRAMBMP(gpu::RectWH &rect, const char *path); size_t saveVRAMBMP(gpu::RectWH &rect, const char *path);
}; };

View File

@ -124,12 +124,12 @@ bool ZIPProvider::init(File *file) {
_zip.m_pRead = []( _zip.m_pRead = [](
void *opaque, uint64_t offset, void *output, size_t length void *opaque, uint64_t offset, void *output, size_t length
) -> size_t { ) -> size_t {
auto _file = reinterpret_cast<File *>(opaque); auto file = reinterpret_cast<File *>(opaque);
if (_file->seek(offset) != offset) if (file->seek(offset) != offset)
return 0; return 0;
return _file->read(output, length); return file->read(output, length);
}; };
if (!mz_zip_reader_init(&_zip, file->size, _ZIP_FLAGS)) { if (!mz_zip_reader_init(&_zip, file->size, _ZIP_FLAGS)) {

244
src/common/mdec.cpp Normal file
View File

@ -0,0 +1,244 @@
/*
* 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 <stddef.h>
#include <stdint.h>
#include "common/util/templates.hpp"
#include "common/mdec.hpp"
#include "ps1/registers.h"
#include "ps1/system.h"
namespace mdec {
/* IDCT matrix and quantization table */
#define SF0 0x5a82 // cos(0/16 * pi) * sqrt(2)
#define SF1 0x7d8a // cos(1/16 * pi) * 2
#define SF2 0x7641 // cos(2/16 * pi) * 2
#define SF3 0x6a6d // cos(3/16 * pi) * 2
#define SF4 0x5a82 // cos(4/16 * pi) * 2
#define SF5 0x471c // cos(5/16 * pi) * 2
#define SF6 0x30fb // cos(6/16 * pi) * 2
#define SF7 0x18f8 // cos(7/16 * pi) * 2
static const int16_t _IDCT_TABLE[]{
SF0, SF0, SF0, SF0, SF0, SF0, SF0, SF0,
SF1, SF3, SF5, SF7, -SF7, -SF5, -SF3, -SF1,
SF2, SF6, -SF6, -SF2, -SF2, -SF6, SF6, SF2,
SF3, -SF7, -SF1, -SF5, SF5, SF1, SF7, -SF3,
SF4, -SF4, -SF4, SF4, SF4, -SF4, -SF4, SF4,
SF5, -SF1, SF7, SF3, -SF3, -SF7, SF1, -SF5,
SF6, -SF2, SF2, -SF6, -SF6, SF2, -SF2, SF6,
SF7, -SF5, SF3, -SF1, SF1, -SF3, SF5, -SF7
};
// The BS v2/v3 quantization table is based on the MPEG-1 table, with the only
// difference being the DC coefficient (2 instead of 8). Quantization tables are
// stored in zigzag order, rather than row- or column-major.
static const uint8_t _BS_QUANT_TABLE[]{
2, 16, 16, 19, 16, 19, 22, 22,
22, 22, 22, 22, 26, 24, 26, 27,
27, 27, 26, 26, 26, 26, 27, 27,
27, 29, 29, 29, 34, 34, 34, 29,
29, 29, 27, 27, 29, 29, 32, 32,
34, 34, 37, 38, 37, 35, 35, 34,
35, 38, 38, 40, 40, 40, 48, 48,
46, 46, 56, 56, 58, 69, 69, 83
};
/* Basic API */
static constexpr int _DMA_CHUNK_SIZE = 32;
static constexpr int _DMA_TIMEOUT = 100000;
void init(void) {
MDEC1 = MDEC_CTRL_RESET;
MDEC1 = MDEC_CTRL_DMA_OUT | MDEC_CTRL_DMA_IN;
MDEC0 = MDEC_CMD_SET_IDCT_TABLE;
feed(_IDCT_TABLE, sizeof(_IDCT_TABLE), true);
MDEC0 = MDEC_CMD_SET_QUANT_TABLE | MDEC_CMD_FLAG_USE_CHROMA;
feed(_BS_QUANT_TABLE, sizeof(_BS_QUANT_TABLE), true);
feed(_BS_QUANT_TABLE, sizeof(_BS_QUANT_TABLE), true);
}
size_t feed(const void *data, size_t length, bool wait) {
length /= 4;
util::assertAligned<uint32_t>(data);
#if 0
assert(!(length % _DMA_CHUNK_SIZE));
#else
length = (length + _DMA_CHUNK_SIZE - 1) / _DMA_CHUNK_SIZE;
#endif
if (!waitForDMATransfer(DMA_MDEC_IN, _DMA_TIMEOUT))
return 0;
DMA_MADR(DMA_MDEC_IN) = reinterpret_cast<uint32_t>(data);
DMA_BCR (DMA_MDEC_IN) = util::concat4(_DMA_CHUNK_SIZE, length);
DMA_CHCR(DMA_MDEC_IN) = 0
| DMA_CHCR_WRITE
| DMA_CHCR_MODE_SLICE
| DMA_CHCR_ENABLE;
if (wait)
waitForDMATransfer(DMA_MDEC_IN, _DMA_TIMEOUT);
return length * _DMA_CHUNK_SIZE * 4;
}
/* MDEC bitstream decompressor */
static constexpr inline uint8_t dc(int luma, int chroma) {
return (chroma & 15) | (luma << 4);
}
static constexpr inline uint16_t ac(int rl, int coeff) {
return (coeff & 0x3ff) | (rl << 10);
}
static constexpr inline uint32_t acl(int rl, int coeff, int length) {
return (coeff & 0x3ff) | (rl << 10) | (length << 16);
}
#define DC2(luma, chroma) dc (luma, chroma), dc (luma, chroma)
#define DC4(luma, chroma) DC2 (luma, chroma), DC2 (luma, chroma)
#define DC8(luma, chroma) DC4 (luma, chroma), DC4 (luma, chroma)
#define DC16(luma, chroma) DC8 (luma, chroma), DC8 (luma, chroma)
#define DC32(luma, chroma) DC16(luma, chroma), DC16(luma, chroma)
#define AC2(rl, coeff) ac (rl, coeff), ac (rl, coeff)
#define AC4(rl, coeff) AC2(rl, coeff), AC2(rl, coeff)
#define AC8(rl, coeff) AC4(rl, coeff), AC4(rl, coeff)
#define PAIR(rl, coeff) ac (rl, coeff), ac (rl, -(coeff))
#define PAIR2(rl, coeff) AC2(rl, coeff), AC2(rl, -(coeff))
#define PAIR4(rl, coeff) AC4(rl, coeff), AC4(rl, -(coeff))
#define PAIR8(rl, coeff) AC8(rl, coeff), AC8(rl, -(coeff))
#define ACL2(rl, coeff, length) acl (rl, coeff, length), acl (rl, coeff, length)
#define ACL4(rl, coeff, length) ACL2(rl, coeff, length), ACL2(rl, coeff, length)
#define ACL8(rl, coeff, length) ACL4(rl, coeff, length), ACL4(rl, coeff, length)
#define PAIRL(rl, coeff, length) acl (rl, coeff, length), acl (rl, -(coeff), length)
#define PAIRL2(rl, coeff, length) ACL2(rl, coeff, length), ACL2(rl, -(coeff), length)
#define PAIRL4(rl, coeff, length) ACL4(rl, coeff, length), ACL4(rl, -(coeff), length)
#define PAIRL8(rl, coeff, length) ACL8(rl, coeff, length), ACL8(rl, -(coeff), length)
struct BSHuffmanTable {
public:
uint16_t ac0[2];
uint32_t ac2[8], ac3 [64];
uint16_t ac4[8], ac5 [8], ac7 [16], ac8 [32];
uint16_t ac9[32], ac10[32], ac11[32], ac12[32];
uint8_t dcValues[128], dcLengths[9];
};
static const BSHuffmanTable _HUFFMAN_TABLE{
.ac0 = {
PAIR( 0, 1) // 11x
},
.ac2 = {
PAIRL ( 0, 2, 5), PAIRL ( 2, 1, 5), // 010xx
PAIRL2( 1, 1, 4) // 011x-
},
.ac3 = {
// 00100xxxx
PAIRL (13, 1, 9), PAIRL ( 0, 6, 9), PAIRL (12, 1, 9), PAIRL (11, 1, 9),
PAIRL ( 3, 2, 9), PAIRL ( 1, 3, 9), PAIRL ( 0, 5, 9), PAIRL (10, 1, 9),
// 001xxx---
PAIRL8( 0, 3, 6), PAIRL8( 4, 1, 6), PAIRL8( 3, 1, 6)
},
.ac4 = {
// 0001xxx
PAIR( 7, 1), PAIR( 6, 1), PAIR( 1, 2), PAIR( 5, 1)
},
.ac5 = {
// 00001xxx
PAIR( 2, 2), PAIR( 9, 1), PAIR( 0, 4), PAIR( 8, 1)
},
.ac7 = {
// 0000001xxxx
PAIR(16, 1), PAIR( 5, 2), PAIR( 0, 7), PAIR( 2, 3),
PAIR( 1, 4), PAIR(15, 1), PAIR(14, 1), PAIR( 4, 2)
},
.ac8 = {
// 00000001xxxxx
PAIR( 0, 11), PAIR( 8, 2), PAIR( 4, 3), PAIR( 0, 10),
PAIR( 2, 4), PAIR( 7, 2), PAIR(21, 1), PAIR(20, 1),
PAIR( 0, 9), PAIR(19, 1), PAIR(18, 1), PAIR( 1, 5),
PAIR( 3, 3), PAIR( 0, 8), PAIR( 6, 2), PAIR(17, 1)
},
.ac9 = {
// 000000001xxxxx
PAIR(10, 2), PAIR( 9, 2), PAIR( 5, 3), PAIR( 3, 4),
PAIR( 2, 5), PAIR( 1, 7), PAIR( 1, 6), PAIR( 0, 15),
PAIR( 0, 14), PAIR( 0, 13), PAIR( 0, 12), PAIR(26, 1),
PAIR(25, 1), PAIR(24, 1), PAIR(23, 1), PAIR(22, 1)
},
.ac10 = {
// 0000000001xxxxx
PAIR( 0, 31), PAIR( 0, 30), PAIR( 0, 29), PAIR( 0, 28),
PAIR( 0, 27), PAIR( 0, 26), PAIR( 0, 25), PAIR( 0, 24),
PAIR( 0, 23), PAIR( 0, 22), PAIR( 0, 21), PAIR( 0, 20),
PAIR( 0, 19), PAIR( 0, 18), PAIR( 0, 17), PAIR( 0, 16)
},
.ac11 = {
// 00000000001xxxxx
PAIR( 0, 40), PAIR( 0, 39), PAIR( 0, 38), PAIR( 0, 37),
PAIR( 0, 36), PAIR( 0, 35), PAIR( 0, 34), PAIR( 0, 33),
PAIR( 0, 32), PAIR( 1, 14), PAIR( 1, 13), PAIR( 1, 12),
PAIR( 1, 11), PAIR( 1, 10), PAIR( 1, 9), PAIR( 1, 8)
},
.ac12 = {
// 000000000001xxxxx
PAIR( 1, 18), PAIR( 1, 17), PAIR( 1, 16), PAIR( 1, 15),
PAIR( 6, 3), PAIR(16, 2), PAIR(15, 2), PAIR(14, 2),
PAIR(13, 2), PAIR(12, 2), PAIR(11, 2), PAIR(31, 1),
PAIR(30, 1), PAIR(29, 1), PAIR(28, 1), PAIR(27, 1)
},
.dcValues = {
DC32(1, 0), // 00-----
DC32(2, 1), // 01-----
DC16(0, 2), // 100----
DC16(3, 2), // 101----
DC16(4, 3), // 110----
DC8 (5, 4), // 1110---
DC4 (6, 5), // 11110--
DC2 (7, 6), // 111110-
dc (8, 7), // 1111110
dc (0, 8) // 1111111(0)
},
.dcLengths = {
dc(3, 2),
dc(2, 2),
dc(2, 2),
dc(3, 3),
dc(3, 4),
dc(4, 5),
dc(5, 6),
dc(6, 7),
dc(7, 8)
}
};
void initBSHuffmanTable(void) {
auto table = reinterpret_cast<BSHuffmanTable *>(CACHE_BASE);
__builtin_memcpy(table, &_HUFFMAN_TABLE, sizeof(BSHuffmanTable));
}
}

90
src/common/mdec.hpp Normal file
View File

@ -0,0 +1,90 @@
/*
* 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>
#include "ps1/registers.h"
namespace mdec {
/* Basic API */
void init(void);
size_t feed(const void *data, size_t length, bool wait);
static inline bool isIdle(void) {
return !(MDEC1 & MDEC_STAT_BUSY);
}
static inline size_t feedBS(const uint32_t *data, uint32_t flags, bool wait) {
size_t length = data[0] & MDEC_CMD_FLAG_LENGTH_BITMASK;
MDEC0 = MDEC_CMD_DECODE | length | flags;
return feed(&data[1], length, wait);
}
/* MDEC bitstream decompressor */
struct BSHeader {
public:
uint16_t outputLength;
uint16_t mdecCommand;
uint16_t quantScale;
uint16_t version;
};
enum BSDecompressorError {
NO_ERROR = 0,
PARTIAL_DATA = 1,
DECODE_ERROR = 2
};
extern "C" BSDecompressorError _bsDecompressorStart(
void *_this, uint32_t *output, size_t outputLength, const uint32_t *input
);
extern "C" BSDecompressorError _bsDecompressorResume(
void *_this, uint32_t *output, size_t outputLength
);
class BSDecompressor {
protected:
const uint32_t *_input;
uint32_t _bits, _nextBits;
size_t _remaining;
uint8_t _isV3;
int8_t _bitOffset, _blockIndex, _coeffIndex;
uint16_t _quantScale;
int16_t _lastY, _lastCr, _lastCb;
public:
inline BSDecompressorError decompress(
uint32_t *output, const uint32_t *input, size_t outputLength
) {
return _bsDecompressorStart(this, output, outputLength, input);
}
inline BSDecompressorError resume(uint32_t *output, size_t outputLength) {
return _bsDecompressorResume(this, output, outputLength);
}
};
void initBSHuffmanTable(void);
}

573
src/common/mdec.s Normal file
View File

@ -0,0 +1,573 @@
# 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/>.
.set noreorder
.set noat
.set GTE_LZCS, $30 # Leading zero count input
.set GTE_LZCR, $31 # Leading zero count output
.set CACHE_BASE, 0x9f800000
## Structure definitions
.set BSHeader_outputLength, 0
.set BSHeader_mdecCommand, BSHeader_outputLength + 2
.set BSHeader_quantScale, BSHeader_mdecCommand + 2
.set BSHeader_version, BSHeader_quantScale + 2
.set BSHeader_data0, BSHeader_version + 2
.set BSHeader_data1, BSHeader_data0 + 4
.set BSDecompressor_input, 0
.set BSDecompressor_bits, BSDecompressor_input + 4
.set BSDecompressor_nextBits, BSDecompressor_bits + 4
.set BSDecompressor_remaining, BSDecompressor_nextBits + 4
.set BSDecompressor_isBSv3, BSDecompressor_remaining + 4
.set BSDecompressor_bitOffset, BSDecompressor_isBSv3 + 1
.set BSDecompressor_blockIndex, BSDecompressor_bitOffset + 1
.set BSDecompressor_coeffIndex, BSDecompressor_blockIndex + 1
.set BSDecompressor_quantScale, BSDecompressor_coeffIndex + 1
.set BSDecompressor_lastY, BSDecompressor_quantScale + 2
.set BSDecompressor_lastCr, BSDecompressor_lastY + 2
.set BSDecompressor_lastCb, BSDecompressor_lastCr + 2
.set BSHuffmanTable_ac0, 0
.set BSHuffmanTable_ac2, BSHuffmanTable_ac0 + 2 * 2
.set BSHuffmanTable_ac3, BSHuffmanTable_ac2 + 8 * 4
.set BSHuffmanTable_ac4, BSHuffmanTable_ac3 + 64 * 4
.set BSHuffmanTable_ac5, BSHuffmanTable_ac4 + 8 * 2
.set BSHuffmanTable_ac7, BSHuffmanTable_ac5 + 8 * 2
.set BSHuffmanTable_ac8, BSHuffmanTable_ac7 + 16 * 2
.set BSHuffmanTable_ac9, BSHuffmanTable_ac8 + 32 * 2
.set BSHuffmanTable_ac10, BSHuffmanTable_ac9 + 32 * 2
.set BSHuffmanTable_ac11, BSHuffmanTable_ac10 + 32 * 2
.set BSHuffmanTable_ac12, BSHuffmanTable_ac11 + 32 * 2
.set BSHuffmanTable_dcValues, BSHuffmanTable_ac12 + 32 * 2
.set BSHuffmanTable_dcLengths, BSHuffmanTable_dcValues + 128 * 1
## Constants
.set NO_ERROR, 0
.set PARTIAL_DATA, 1
.set DECODE_ERROR, 2
.set BLOCK_INDEX_Y3, 0
.set BLOCK_INDEX_Y2, 1
.set BLOCK_INDEX_Y1, 2
.set BLOCK_INDEX_Y0, 3
.set BLOCK_INDEX_CB, 4
.set BLOCK_INDEX_CR, 5
.set MDEC_COMMAND, 0x3800
.set MDEC_END_CODE, 0xfe00
.set BS_DC_END_CODE, 0x1ff
.set BS_DC_BITMASK, 0x3ff
.set BS_DC_V2_LENGTH, 10
.set BS_DC_V3_LENGTH, 7
.set BS_DC_V3_END_LENGTH, 9
.set MAX_PREFIX_LENGTH, 11
.set JUMP_CASE_LENGTH, 5 # (1 << 5) = 32 bytes = 8 instructions
## Local variables and macros
.set value, $v0
.set length, $v1
.set this, $a0
.set output, $a1
.set outputLength, $a2
.set input, $a3
.set temp, $t0
.set bits, $t1
.set nextBits, $t2
.set remaining, $t3
.set isBSv3, $t4
.set bitOffset, $t5
.set blockIndex, $t6
.set coeffIndex, $t7
.set quantScale, $s0
.set lastY, $s1
.set lastCr, $s2
.set lastCb, $s3
.set huffmanTable, $t8
.set acJumpPtr, $t9
.macro swapHalfwords reg
# reg = uint32_t(reg << 16) | uint32_t(reg >> 16);
srl temp, \reg, 16
sll \reg, 16
or \reg, temp
.endm
.macro decodeBSv3DC lastValueReg, jumpTo
# bits <<= temp;
# bitOffset -= temp;
sllv bits, bits, temp
beqz length, 3f
subu bitOffset, temp
0: # if (length) {
# value = bits >> (32 - length);
subu $at, length
srlv value, bits, $at
# ((1 << length) - 1) below is computed as (0xffffffff >> (32 - length)) as
# it takes fewer instructions.
bltz bits, 2f
li temp, -1
1:
# if (!(bits >> 31)) value -= (1 << length) - 1;
srlv temp, temp, $at
subu value, temp
2:
# lastValueReg += value * 4;
# lastValueReg &= BS_DC_BITMASK;
sll value, 2
addu \lastValueReg, value
andi \lastValueReg, BS_DC_BITMASK
3: # } else {
# *output = lastY | quantScale;
or temp, \lastValueReg, quantScale
b \jumpTo
sh temp, 0(output)
.endm # }
.macro decodeFixedAC prefixLength, codeLength, discarded, tableImm, jumpTo
# bitmask = (1 << codeLength) - 1;
# value = (bits >> (32 - totalLength)) & bitmask;
srl value, bits, 32 - (\prefixLength + \codeLength + 1)
andi value, ((1 << \codeLength) - 1) << 1
# An extra shift (to multiply the code by the size of each table entry, 2
# bytes) is avoided here by keeping one more bit from the sliding window
# above, then masking it off.
addu value, huffmanTable
lhu value, \tableImm(value)
# bits <<= totalLength;
# bitOffset -= totalLength + discarded;
sll bits, \prefixLength + \codeLength
addiu bitOffset, -(\prefixLength + \codeLength + \discarded)
# *output = tableImm[value];
b \jumpTo
sh value, 0(output)
.endm
.macro decodeVariableAC prefixLength, codeLength, tableImm, jumpTo
# Lookup tables with 32-bit entries are used to decode variable length
# codes, with the upper 16 bits holding the length of the code.
# bitmask = (1 << codeLength) - 1;
# value = (bits >> (32 - totalLength)) & bitmask;
srl value, bits, 32 - (\prefixLength + \codeLength + 2)
andi value, ((1 << \codeLength) - 1) << 2
# An extra shift (to multiply the code by the size of each table entry, 4
# bytes) is avoided here by keeping two more bits from the sliding window
# above, then masking it off.
addu value, huffmanTable
lw value, \tableImm(value)
# *output = tableImm[index] & 0xffff;
# length = tableImm[index] >> 16;
b \jumpTo
sh value, 0(output)
nop
nop
.endm
.macro decodeACEscape prefixLength, codeLength, discarded, jumpTo
# shift = 32 - (prefixLength + codeLength);
# value = bits >> shift;
srl value, bits, 32 - (\prefixLength + \codeLength)
# bits <<= totalLength;
# bitOffset -= totalLength + discarded;
sll bits, \prefixLength + \codeLength
addiu bitOffset, -(\prefixLength + \codeLength + \discarded)
# *output = value & 0xffff;
b \jumpTo
sh value, 0(output)
nop
nop
nop
.endm
## MDEC bitstream decompressor
.section .text._bsDecompressorStart, "ax", @progbits
.global _bsDecompressorStart
.type _bsDecompressorStart, @function
_bsDecompressorStart:
addiu $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
sw $s2, 8($sp)
sw $s3, 12($sp)
# header = (const BSHeader *) input;
# bits = swapHalfwords(header->data[0]);
# lastY = 0;
lw bits, BSHeader_data0(input)
li lastY, 0
swapHalfwords bits
# nextBits = swapHalfwords(header->data[1]);
# lastCr = 0;
lw nextBits, BSHeader_data1(input)
li lastCr, 0
swapHalfwords nextBits
# remaining = header->outputLength * 2;
# lastCb = 0;
lhu remaining, BSHeader_outputLength(input)
li lastCb, 0
sll remaining, 1
# quantScale = (header->quantScale & 63) << 10;
# bitOffset = 32;
lw temp, BSHeader_quantScale(input)
li bitOffset, 32
andi quantScale, temp, 63
sll quantScale, 10
# isBSv3 = !(header->version < 3);
# blockIndex = BLOCK_INDEX_CR;
# coeffIndex = 0;
srl temp, 16
sltiu isBSv3, temp, 3
xori isBSv3, 1
li blockIndex, BLOCK_INDEX_CR
li coeffIndex, 0
# input = &(header->data[2]);
j _bsDecompressorSkipContextLoad
addiu input, 16
.section .text._bsDecompressorResume, "ax", @progbits
.global _bsDecompressorResume
.type _bsDecompressorResume, @function
_bsDecompressorResume:
addiu $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
sw $s2, 8($sp)
sw $s3, 12($sp)
lw input, BSDecompressor_input (this)
lw bits, BSDecompressor_bits (this)
lw nextBits, BSDecompressor_nextBits (this)
lw remaining, BSDecompressor_remaining (this)
lb isBSv3, BSDecompressor_isBSv3 (this)
lb bitOffset, BSDecompressor_bitOffset (this)
lb blockIndex, BSDecompressor_blockIndex(this)
lb coeffIndex, BSDecompressor_coeffIndex(this)
lhu quantScale, BSDecompressor_quantScale(this)
lh lastY, BSDecompressor_lastY (this)
lh lastCr, BSDecompressor_lastCr (this)
lh lastCb, BSDecompressor_lastCb (this)
_bsDecompressorSkipContextLoad:
# if (outputLength <= 0) outputLength = 0x3fff0000;
bgtz outputLength, .LoutputLengthValid
addiu outputLength, -1
.LdefaultOutputLength:
lui outputLength, 0x3fff
.LoutputLengthValid:
# outputLength = min((outputLength - 1) * 2, remaining);
# remaining -= outputLength;
sll outputLength, 1
subu remaining, outputLength
bgez remaining, .LremainingValid
lui temp, MDEC_COMMAND
.LadjustRemaining:
addu outputLength, remaining
li remaining, 0
.LremainingValid:
# *(output++) = outputLength / 2;
# *(output++) = MDEC_COMMAND;
srl value, outputLength, 1
or value, temp
sw value, 0(output)
# huffmanTable = (const BSHuffmanTable *) CACHE_BASE;
# acJumpPtr = &LacJumpArea;
la huffmanTable, CACHE_BASE
la acJumpPtr, .LacJumpArea
beqz outputLength, .Lbreak
addiu output, 4
.LdecompressLoop: # while (outputLength) {
# The first step to decompress each code is to determine whether it is a DC
# or AC coefficient. At the same time the GTE is given the task of counting
# the number of leading zeroes/ones in the code.
mtc2 bits, GTE_LZCS
bnez coeffIndex, .LisACCoeff
addiu coeffIndex, 1
bnez isBSv3, .LisBSv3DCCoeff
li temp, BS_DC_END_CODE
.LisBSv2DCCoeff: # if (!coeffIndex && !isBSv3) {
# The DC coefficient in v2 frames is a raw 10-bit value. Value 0x1ff is used
# to signal the end of the bitstream.
# value = bits >> (32 - BS_DC_V2_LENGTH);
# if (value == BS_DC_END_CODE) break;
srl value, bits, 32 - BS_DC_V2_LENGTH
beq value, temp, .Lbreak
or value, quantScale
# bits <<= BS_DC_V2_LENGTH;
# bitOffset -= BS_DC_V2_LENGTH;
sll bits, BS_DC_V2_LENGTH
addiu bitOffset, -BS_DC_V2_LENGTH
# *output = value | quantScale;
b .Ldone
sh value, 0(output)
.LisBSv3DCCoeff: # } else if (!coeffIndex && isBSv3) {
# v3 DC coefficients are variable-length deltas prefixed with a Huffman code
# indicating their length. Since the prefix code is up to 7 bits long, it
# makes sense to decode it with a simple 128-byte lookup table rather than
# using the GTE. The codes are different for luma and chroma blocks, so each
# table entry contains the decoded length for both block types (packed as
# two nibbles). Prefix 111111111 is used to signal the end of the bitstream.
# length = bits >> (32 - BS_DC_V3_END_LENGTH);
# if (length == BS_DC_END_CODE) break;
srl length, bits, 32 - BS_DC_V3_END_LENGTH
beq length, temp, .Lbreak
srl length, BS_DC_V3_END_LENGTH - BS_DC_V3_LENGTH
# length >>= BS_DC_V3_END_LENGTH - BS_DC_V3_LENGTH;
# length = huffmanTable->dcValues[length];
addu length, huffmanTable
addiu $at, blockIndex, -BLOCK_INDEX_CB
bltz $at, .LisY
lbu length, BSHuffmanTable_dcValues(length)
# if (blockIndex >= BLOCK_INDEX_CB)
beqz $at, .LisCb
andi length, 15
.LisCr: # if (blockIndex > BLOCK_INDEX_CB) {
# length &= 15;
# temp = huffmanTable->dcLengths[length] & 15;
addu temp, length, huffmanTable
lbu temp, BSHuffmanTable_dcLengths(temp)
li $at, 32
# decodeBSv3DC(lastCb);
# bits <<= length;
# bitOffset -= length;
andi temp, 15
decodeBSv3DC lastCr, .LconsumeBits
.LisCb: # } else if (block_index == BLOCK_INDEX_CB) {
# length &= 15;
# temp = huffmanTable->dcLengths[length] & 15;
addu temp, length, huffmanTable
lbu temp, BSHuffmanTable_dcLengths(temp)
li $at, 32
# decodeBSv3DC(lastCb);
# bits <<= length;
# bitOffset -= length;
andi temp, 15
decodeBSv3DC lastCb, .LconsumeBits
.LisY: # } else {
# length >>= 4;
# temp = huffmanTable->dcLengths[length] >> 4;
nop
srl length, 4
addu temp, length, huffmanTable
lbu temp, BSHuffmanTable_dcLengths(temp)
li $at, 32
# decodeBSv3DC(lastCb);
# bits <<= length;
# bitOffset -= length;
srl temp, 4
decodeBSv3DC lastY, .LconsumeBits
.LisACCoeff: # } } else {
# Check whether the code starts with 10 or 11; if not, retrieve the leading
# zero count from the GTE, validate it and use it as an index into the jump
# area. Each case is 8 instructions long and handles decoding a specific
# Huffman prefix.
# temp = countLeadingZeroes(temp);
mfc2 temp, GTE_LZCR
bltz bits, .Lac1
addiu $at, temp, -MAX_PREFIX_LENGTH
bgtz $at, .LacInvalid
sll temp, JUMP_CASE_LENGTH
.Lac0: # if ((prefix <= MAX_PREFIX_LENGTH) && !(bits >> 31)) {
# goto &acJumpArea[prefix << JUMP_CASE_LENGTH];
addu temp, acJumpPtr
jr temp
nop
.LacInvalid: # } else if (prefix > MAX_PREFIX_LENGTH) {
# return DECODE_ERROR;
b .Lreturn
li $v0, DECODE_ERROR
.Lac1: # } else {
# bits <<= 1;
# if (bits >> 31) goto &acJumpArea[0];
sll bits, 1
bltz bits, .LacJumpArea
li temp, MDEC_END_CODE
.Lac10: # else {
# Prefix 10 marks the end of a block. Note that the 10/11 prefix check above
# shifts the window by one bit *without* updating the bit offset.
# bits <<= 1;
# bitOffset -= 2;
sll bits, 1
addiu bitOffset, -2
# *output = MDEC_END_CODE;
sh temp, 0(output)
# coeffIndex = 0;
# if (--blockIndex < BLOCK_INDEX_Y3) blockIndex = BLOCK_INDEX_CR;
addiu blockIndex, -1
bgez blockIndex, .Ldone
li coeffIndex, 0
.LresetBlockIndex:
b .Ldone
li blockIndex, BLOCK_INDEX_CR
.LacJumpArea: # } }
decodeFixedAC 1, 1, 1, BSHuffmanTable_ac0, .Ldone # (1)1x
decodeVariableAC 2, 3, BSHuffmanTable_ac2, .LconsumeAC # 01xxx
decodeVariableAC 3, 6, BSHuffmanTable_ac3, .LconsumeAC # 001xxxxxx
decodeFixedAC 4, 3, 0, BSHuffmanTable_ac4, .Ldone # 0001xxx
decodeFixedAC 5, 3, 0, BSHuffmanTable_ac5, .Ldone # 00001xxx
decodeACEscape 6, 16, 0, .Ldone # 000001xxxxxxxxxxxxxxxx
decodeFixedAC 7, 4, 0, BSHuffmanTable_ac7, .Ldone # 0000001xxxx
decodeFixedAC 8, 5, 0, BSHuffmanTable_ac8, .Ldone # 00000001xxxxx
decodeFixedAC 9, 5, 0, BSHuffmanTable_ac9, .Ldone # 000000001xxxxx
decodeFixedAC 10, 5, 0, BSHuffmanTable_ac10, .Ldone # 0000000001xxxxx
decodeFixedAC 11, 5, 0, BSHuffmanTable_ac11, .Ldone # 00000000001xxxxx
decodeFixedAC 12, 5, 0, BSHuffmanTable_ac12, .Ldone # 000000000001xxxxx
.LconsumeAC:
srl length, value, 16
.LconsumeBits:
sllv bits, bits, length
subu bitOffset, length
.Ldone: # }
# Update the bits. This makes sure the next iteration of the loop will be
# able to read up to 32 bits from the bitstream.
# coeffIndex++;
# outputLength--;
bgez bitOffset, .LskipFeeding
addiu outputLength, -1
.LfeedBitstream: # if (bitOffset < 0) {
# bits = nextBits << (-bitOffset);
subu temp, $0, bitOffset
sllv bits, nextBits, temp
# nextBits = swapHalfwords(*(input++));
# bitOffset += 32;
lw nextBits, 0(input)
addiu bitOffset, 32
swapHalfwords nextBits
addiu input, 4
.LskipFeeding: # }
# bits |= nextBits >> bitOffset;
# output++;
srlv temp, nextBits, bitOffset
or bits, temp
bnez outputLength, .LdecompressLoop
addiu output, 2
.Lbreak: # }
beqz remaining, .LpadOutput
li temp, MDEC_END_CODE
.LsaveContext: # if (remaining) {
sw input, BSDecompressor_input (this)
sw bits, BSDecompressor_bits (this)
sw nextBits, BSDecompressor_nextBits (this)
sw remaining, BSDecompressor_remaining (this)
sb bitOffset, BSDecompressor_bitOffset (this)
sb blockIndex, BSDecompressor_blockIndex(this)
sb coeffIndex, BSDecompressor_coeffIndex(this)
sh lastY, BSDecompressor_lastY (this)
sh lastCr, BSDecompressor_lastCr (this)
sh lastCb, BSDecompressor_lastCb (this)
# return PARTIAL_DATA;
b .Lreturn
li $v0, PARTIAL_DATA
.LpadOutput: # } else {
# for (; outputLength; outputLength--) *(output++) = MDEC_END_CODE;
# return NO_ERROR;
beqz outputLength, .Lreturn
li $v0, NO_ERROR
.LpadOutputLoop:
sh temp, 0(output)
addiu outputLength, -1
bnez outputLength, .LpadOutputLoop
addiu output, 2
.Lreturn: # }
lw $s0, 0($sp)
lw $s1, 4($sp)
lw $s2, 8($sp)
lw $s3, 12($sp)
jr $ra
addiu $sp, 16

View File

@ -89,7 +89,6 @@ public:
// Note that all offsets must be multiples of 2, as writes are done in // Note that all offsets must be multiples of 2, as writes are done in
// halfwords. // halfwords.
virtual ~Driver(void) {}
virtual void write(uint32_t offset, uint16_t value) {} virtual void write(uint32_t offset, uint16_t value) {}
virtual void eraseSector(uint32_t offset) {} virtual void eraseSector(uint32_t offset) {}
virtual void eraseChip(uint32_t offset) {} virtual void eraseChip(uint32_t offset) {}

View File

@ -127,6 +127,9 @@ void IDEDevice::_writePIO(const void *data, size_t length) const {
bool IDEDevice::_readDMA(void *data, size_t length) const { bool IDEDevice::_readDMA(void *data, size_t length) const {
util::assertAligned<uint32_t>(data); util::assertAligned<uint32_t>(data);
if (!waitForDMATransfer(DMA_PIO, _DMA_TIMEOUT))
return false;
DMA_MADR(DMA_PIO) = reinterpret_cast<uint32_t>(data); DMA_MADR(DMA_PIO) = reinterpret_cast<uint32_t>(data);
DMA_BCR (DMA_PIO) = (length + 3) / 4; DMA_BCR (DMA_PIO) = (length + 3) / 4;
DMA_CHCR(DMA_PIO) = 0 DMA_CHCR(DMA_PIO) = 0
@ -141,6 +144,9 @@ bool IDEDevice::_readDMA(void *data, size_t length) const {
bool IDEDevice::_writeDMA(const void *data, size_t length) const { bool IDEDevice::_writeDMA(const void *data, size_t length) const {
util::assertAligned<uint32_t>(data); util::assertAligned<uint32_t>(data);
if (!waitForDMATransfer(DMA_PIO, _DMA_TIMEOUT))
return false;
DMA_MADR(DMA_PIO) = reinterpret_cast<uint32_t>(data); DMA_MADR(DMA_PIO) = reinterpret_cast<uint32_t>(data);
DMA_BCR (DMA_PIO) = (length + 3) / 4; DMA_BCR (DMA_PIO) = (length + 3) / 4;
DMA_CHCR(DMA_PIO) = 0 DMA_CHCR(DMA_PIO) = 0

View File

@ -206,7 +206,6 @@ public:
inline Device(uint8_t flags = 0) inline Device(uint8_t flags = 0)
: type(NONE), flags(flags), sectorLength(0), capacity(0) {} : type(NONE), flags(flags), sectorLength(0), capacity(0) {}
virtual ~Device(void) {}
virtual DeviceError enumerate(void) { return UNSUPPORTED_OP; } virtual DeviceError enumerate(void) { return UNSUPPORTED_OP; }
virtual DeviceError poll(void) { return UNSUPPORTED_OP; } virtual DeviceError poll(void) { return UNSUPPORTED_OP; }
virtual void handleInterrupt(void) {} virtual void handleInterrupt(void) {}

View File

@ -111,6 +111,46 @@ size_t encodeBase41(char *output, const uint8_t *input, size_t length) {
/* UTF-8 parser */ /* UTF-8 parser */
#if 0
#define L1(length) (length)
#define L2(length) L1(length), L1(length)
#define L4(length) L2(length), L2(length)
#define L8(length) L4(length), L4(length)
#define L16(length) L8(length), L8(length)
static const uint8_t _START_BYTE_LENGTHS[]{
L16(1), // 0xxxx--- (1 byte)
L8 (0), // 10xxx--- (invalid)
L4 (2), // 110xx--- (2 bytes)
L2 (3), // 1110x--- (3 bytes)
L1 (4), // 11110--- (4 bytes)
L1 (0) // 11111--- (invalid)
};
static const uint8_t _START_BYTE_MASKS[]{
0x00,
0x7f, // 0xxxxxxx (1 byte)
0x1f, // 110xxxxx (2 bytes)
0x0f, // 1110xxxx (3 bytes)
0x07 // 11110xxx (4 bytes)
};
UTF8Character parseUTF8Character(const char *ch) {
auto start = uint8_t(*(ch++));
auto length = _START_BYTE_LENGTHS[start >> 3];
auto mask = _START_BYTE_MASKS[length];
auto codePoint = UTF8CodePoint(start & mask);
for (size_t i = length - 1; i; i--) {
codePoint <<= 6;
codePoint |= *(ch++) & 0x3f;
}
return { codePoint, length };
}
#endif
size_t getUTF8StringLength(const char *str) { size_t getUTF8StringLength(const char *str) {
for (size_t length = 0;; length++) { for (size_t length = 0;; length++) {
auto value = parseUTF8Character(str); auto value = parseUTF8Character(str);

View File

@ -43,17 +43,19 @@ public:
size_t length; size_t length;
}; };
#if 0
UTF8Character parseUTF8Character(const char *ch);
#else
extern "C" uint64_t _parseUTF8Character(const char *ch); extern "C" uint64_t _parseUTF8Character(const char *ch);
size_t getUTF8StringLength(const char *str);
static inline UTF8Character parseUTF8Character(const char *ch) { static inline UTF8Character parseUTF8Character(const char *ch) {
auto values = _parseUTF8Character(ch); auto values = _parseUTF8Character(ch);
return { return { UTF8CodePoint(values), size_t(values >> 32) };
.codePoint = UTF8CodePoint(values),
.length = size_t(values >> 32)
};
} }
#endif
size_t getUTF8StringLength(const char *str);
/* LZ4 decompressor */ /* LZ4 decompressor */

View File

@ -50,14 +50,16 @@ template<typename T, typename E> T Tween<T, E>::getValue(int time) const {
) / TWEEN_UNIT; ) / TWEEN_UNIT;
} }
// NOTE: T should always be a signed type, as the delta will be negative when
// interpolating from a higher value to a lower one.
template class Tween<int, LinearEasing>; template class Tween<int, LinearEasing>;
template class Tween<int, QuadInEasing>; template class Tween<int, QuadInEasing>;
template class Tween<int, QuadOutEasing>; template class Tween<int, QuadOutEasing>;
template class Tween<uint16_t, LinearEasing>; template class Tween<int8_t, LinearEasing>;
template class Tween<uint16_t, QuadInEasing>; template class Tween<int8_t, QuadInEasing>;
template class Tween<uint16_t, QuadOutEasing>; template class Tween<int8_t, QuadOutEasing>;
template class Tween<uint32_t, LinearEasing>; template class Tween<int16_t, LinearEasing>;
template class Tween<uint32_t, QuadInEasing>; template class Tween<int16_t, QuadInEasing>;
template class Tween<uint32_t, QuadOutEasing>; template class Tween<int16_t, QuadOutEasing>;
} }

View File

@ -272,10 +272,10 @@ void App::_loadResources(void) {
res.loadTIM(_splashOverlay.image, "assets/textures/splash.tim"); res.loadTIM(_splashOverlay.image, "assets/textures/splash.tim");
res.loadData(_stringTable, "assets/lang/en.lang"); res.loadData(_stringTable, "assets/lang/en.lang");
fs::currentSPUOffset = spu::DUMMY_BLOCK_END; uint32_t spuOffset = spu::DUMMY_BLOCK_END;
for (int i = 0; i < ui::NUM_UI_SOUNDS; i++) for (int i = 0; i < ui::NUM_UI_SOUNDS; i++)
res.loadVAG(_ctx.sounds[i], _UI_SOUND_PATHS[i]); res.loadVAG(_ctx.sounds[i], spuOffset, _UI_SOUND_PATHS[i]);
} }
bool App::_createDataDirectory(void) { bool App::_createDataDirectory(void) {

View File

@ -267,15 +267,15 @@ bool App::_cartRestoreWorker(void) {
_workerStatus.update(0, 3, WSTR("App.cartRestoreWorker.init")); _workerStatus.update(0, 3, WSTR("App.cartRestoreWorker.init"));
const char *path = _fileBrowserScreen.selectedPath; const char *path = _fileBrowserScreen.selectedPath;
auto _file = _fileIO.vfs.openFile(path, fs::READ); auto file = _fileIO.vfs.openFile(path, fs::READ);
cart::CartDump newDump; cart::CartDump newDump;
if (_file) { if (file) {
auto length = _file->read(&newDump, sizeof(newDump)); auto length = file->read(&newDump, sizeof(newDump));
_file->close(); file->close();
delete _file; delete file;
if (length < (sizeof(newDump) - sizeof(newDump.data))) if (length < (sizeof(newDump) - sizeof(newDump.data)))
goto _fileError; goto _fileError;

View File

@ -310,7 +310,7 @@ void ResolutionScreen::update(ui::Context &ctx) {
} }
} }
static constexpr uint16_t _LOOP_FADE_IN_VOLUME = spu::MAX_VOLUME / 2; static constexpr int _LOOP_FADE_IN_VOLUME = spu::MAX_VOLUME / 2;
static constexpr int _LOOP_FADE_IN_TIME = 30; static constexpr int _LOOP_FADE_IN_TIME = 30;
void AboutScreen::show(ui::Context &ctx, bool goBack) { void AboutScreen::show(ui::Context &ctx, bool goBack) {

View File

@ -65,7 +65,7 @@ private:
util::Data _text; util::Data _text;
spu::Channel _loopChannel; spu::Channel _loopChannel;
util::Tween<uint16_t, util::QuadInEasing> _loopVolume; util::Tween<int, util::QuadInEasing> _loopVolume;
public: public:
void show(ui::Context &ctx, bool goBack = false); void show(ui::Context &ctx, bool goBack = false);

View File

@ -151,12 +151,12 @@ bool App::_executableWorker(void) {
} else { } else {
__builtin_memset(header.magic, 0, sizeof(header.magic)); __builtin_memset(header.magic, 0, sizeof(header.magic));
auto _file = _fileIO.vfs.openFile(path, fs::READ); auto file = _fileIO.vfs.openFile(path, fs::READ);
if (_file) { if (file) {
_file->read(&header, sizeof(header)); file->read(&header, sizeof(header));
_file->close(); file->close();
delete _file; delete file;
} }
if (!header.validateMagic()) { if (!header.validateMagic()) {

View File

@ -221,7 +221,7 @@ void FilePickerScreen::show(ui::Context &ctx, bool goBack) {
_listLength = 0; _listLength = 0;
#ifdef ENABLE_PCDRV #ifdef ENABLE_PCDRV
_addDevice(nullptr, APP->_fileIO.host, "host:"); _addDevice(nullptr, &(APP->_fileIO.host), "host:");
#endif #endif
for (size_t i = 0; i < util::countOf(APP->_fileIO.ideDevices); i++) for (size_t i = 0; i < util::countOf(APP->_fileIO.ideDevices); i++)

View File

@ -145,11 +145,11 @@ bool App::_romDumpWorker(void) {
snprintf(filePath, sizeof(filePath), entry.path, dirPath); snprintf(filePath, sizeof(filePath), entry.path, dirPath);
auto _file = _fileIO.vfs.openFile( auto file = _fileIO.vfs.openFile(
filePath, fs::WRITE | fs::ALLOW_CREATE filePath, fs::WRITE | fs::ALLOW_CREATE
); );
if (!_file) if (!file)
goto _fileError; goto _fileError;
util::Data buffer; util::Data buffer;
@ -161,10 +161,10 @@ bool App::_romDumpWorker(void) {
_workerStatus.update(i, numChunks, WSTRH(entry.dumpPrompt)); _workerStatus.update(i, numChunks, WSTRH(entry.dumpPrompt));
entry.region.read(buffer.ptr, offset, chunkLength); entry.region.read(buffer.ptr, offset, chunkLength);
if (_file->write(buffer.ptr, chunkLength) < chunkLength) { if (file->write(buffer.ptr, chunkLength) < chunkLength) {
buffer.destroy(); buffer.destroy();
_file->close(); file->close();
delete _file; delete file;
goto _fileError; goto _fileError;
} }
@ -173,8 +173,8 @@ bool App::_romDumpWorker(void) {
} }
buffer.destroy(); buffer.destroy();
_file->close(); file->close();
delete _file; delete file;
LOG_APP("%s saved", filePath); LOG_APP("%s saved", filePath);
} }
@ -201,9 +201,9 @@ bool App::_romRestoreWorker(void) {
_workerStatus.update(0, 1, WSTR("App.romRestoreWorker.init")); _workerStatus.update(0, 1, WSTR("App.romRestoreWorker.init"));
const char *path = _fileBrowserScreen.selectedPath; const char *path = _fileBrowserScreen.selectedPath;
auto _file = _fileIO.vfs.openFile(path, fs::READ); auto file = _fileIO.vfs.openFile(path, fs::READ);
if (!_file) { if (!file) {
_messageScreen.setMessage( _messageScreen.setMessage(
MESSAGE_ERROR, WSTR("App.romRestoreWorker.fileError"), path MESSAGE_ERROR, WSTR("App.romRestoreWorker.fileError"), path
); );
@ -243,8 +243,8 @@ bool App::_romRestoreWorker(void) {
size_t j = numChips; j > 0; j--, bufferPtr += maxChunkLength, size_t j = numChips; j > 0; j--, bufferPtr += maxChunkLength,
offset += chipLength offset += chipLength
) { ) {
_file->seek(offset); file->seek(offset);
auto length = _file->read(bufferPtr, maxChunkLength); auto length = file->read(bufferPtr, maxChunkLength);
// Data is written 16 bits at a time, so the chunk must be padded to // Data is written 16 bits at a time, so the chunk must be padded to
// an even number of bytes. // an even number of bytes.
@ -301,8 +301,8 @@ bool App::_romRestoreWorker(void) {
buffers.destroy(); buffers.destroy();
chunkLengths.destroy(); chunkLengths.destroy();
_file->close(); file->close();
delete _file; delete file;
delete driver; delete driver;
_messageScreen.setMessage( _messageScreen.setMessage(
@ -316,14 +316,14 @@ bool App::_romRestoreWorker(void) {
util::Hash message; util::Hash message;
message = (_file->size > regionLength) message = (file->size > regionLength)
? "App.romRestoreWorker.overflow"_h ? "App.romRestoreWorker.overflow"_h
: "App.romRestoreWorker.success"_h; : "App.romRestoreWorker.success"_h;
buffers.destroy(); buffers.destroy();
chunkLengths.destroy(); chunkLengths.destroy();
_file->close(); file->close();
delete _file; delete file;
delete driver; delete driver;
_messageScreen.setMessage(MESSAGE_SUCCESS, WSTRH(message), bytesWritten); _messageScreen.setMessage(MESSAGE_SUCCESS, WSTRH(message), bytesWritten);

View File

@ -133,7 +133,6 @@ public:
inline CartParser(CartDump &dump, uint8_t flags = 0) inline CartParser(CartDump &dump, uint8_t flags = 0)
: _dump(dump), flags(flags) {} : _dump(dump), flags(flags) {}
virtual ~CartParser(void) {}
virtual size_t getCode(char *output) const { return 0; } virtual size_t getCode(char *output) const { return 0; }
virtual void setCode(const char *input) {} virtual void setCode(const char *input) {}
virtual size_t getRegion(char *output) const { return 0; } virtual size_t getRegion(char *output) const { return 0; }
@ -219,7 +218,6 @@ public:
inline ROMHeaderParser(ROMHeaderDump &dump, uint8_t flags = 0) inline ROMHeaderParser(ROMHeaderDump &dump, uint8_t flags = 0)
: _dump(dump), flags(flags) {} : _dump(dump), flags(flags) {}
virtual ~ROMHeaderParser(void) {}
virtual size_t getCode(char *output) const { return 0; } virtual size_t getCode(char *output) const { return 0; }
virtual void setCode(const char *input) {} virtual void setCode(const char *input) {}
virtual size_t getRegion(char *output) const { return 0; } virtual size_t getRegion(char *output) const { return 0; }

View File

@ -47,7 +47,6 @@ public:
inline Driver(CartDump &dump) inline Driver(CartDump &dump)
: _dump(dump) {} : _dump(dump) {}
virtual ~Driver(void) {}
virtual DriverError readSystemID(void) { return UNSUPPORTED_OP; } virtual DriverError readSystemID(void) { return UNSUPPORTED_OP; }
virtual DriverError readCartID(void) { return UNSUPPORTED_OP; } virtual DriverError readCartID(void) { return UNSUPPORTED_OP; }
virtual DriverError readPublicData(void) { return UNSUPPORTED_OP; } virtual DriverError readPublicData(void) { return UNSUPPORTED_OP; }

View File

@ -20,6 +20,7 @@
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/ioboard.hpp" #include "common/ioboard.hpp"
#include "common/mdec.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
@ -35,6 +36,7 @@ int main(int argc, const char **argv) {
installExceptionHandler(); installExceptionHandler();
gpu::init(); gpu::init();
spu::init(); spu::init();
mdec::init();
io::init(); io::init();
util::initZipCRC32(); util::initZipCRC32();

View File

@ -369,6 +369,26 @@ typedef enum {
/* MDEC */ /* MDEC */
typedef enum { typedef enum {
MDEC_CMD_NOP = 0 << 29,
MDEC_CMD_DECODE = 1 << 29,
MDEC_CMD_SET_QUANT_TABLE = 2 << 29,
MDEC_CMD_SET_IDCT_TABLE = 3 << 29
} MDECCommand;
typedef enum {
MDEC_CMD_FLAG_LENGTH_BITMASK = 0xffff << 0, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_USE_CHROMA = 1 << 0, // MDEC_CMD_SET_QUANT_TABLE
MDEC_CMD_FLAG_SIGNED = 1 << 25, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_16BPP_MASK = 1 << 26, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_FORMAT_BITMASK = 3 << 27, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_FORMAT_4BPP = 0 << 27, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_FORMAT_8BPP = 1 << 27, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_FORMAT_24BPP = 2 << 27, // MDEC_CMD_DECODE
MDEC_CMD_FLAG_FORMAT_16BPP = 3 << 27 // MDEC_CMD_DECODE
} MDECCommandFlag;
typedef enum {
MDEC_STAT_LENGTH_BITMASK = 0xffff << 0,
MDEC_STAT_BLOCK_BITMASK = 7 << 16, MDEC_STAT_BLOCK_BITMASK = 7 << 16,
MDEC_STAT_BLOCK_Y0 = 0 << 16, MDEC_STAT_BLOCK_Y0 = 0 << 16,
MDEC_STAT_BLOCK_Y1 = 1 << 16, MDEC_STAT_BLOCK_Y1 = 1 << 16,
@ -376,6 +396,13 @@ typedef enum {
MDEC_STAT_BLOCK_Y3 = 3 << 16, MDEC_STAT_BLOCK_Y3 = 3 << 16,
MDEC_STAT_BLOCK_CR = 4 << 16, MDEC_STAT_BLOCK_CR = 4 << 16,
MDEC_STAT_BLOCK_CB = 5 << 16, MDEC_STAT_BLOCK_CB = 5 << 16,
MDEC_STAT_16BPP_MASK = 1 << 23,
MDEC_STAT_SIGNED = 1 << 24,
MDEC_STAT_FORMAT_BITMASK = 3 << 25,
MDEC_STAT_FORMAT_4BPP = 0 << 25,
MDEC_STAT_FORMAT_8BPP = 1 << 25,
MDEC_STAT_FORMAT_24BPP = 2 << 25,
MDEC_STAT_FORMAT_16BPP = 3 << 25,
MDEC_STAT_DREQ_OUT = 1 << 27, MDEC_STAT_DREQ_OUT = 1 << 27,
MDEC_STAT_DREQ_IN = 1 << 28, MDEC_STAT_DREQ_IN = 1 << 28,
MDEC_STAT_BUSY = 1 << 29, MDEC_STAT_BUSY = 1 << 29,