From a747dabd7609b446098f39dcd6bafbfe4fa80e38 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sun, 15 Sep 2024 22:42:20 +0200 Subject: [PATCH] More cleaning up, add preliminary MDEC API --- CMakeLists.txt | 283 ++++++++--------- cmake/options.cmake | 145 +++++++++ src/boot/main.cpp | 2 +- src/common/fs/fat.cpp | 10 +- src/common/fs/file.cpp | 83 ++--- src/common/fs/file.hpp | 4 +- src/common/fs/zip.cpp | 6 +- src/common/mdec.cpp | 244 +++++++++++++++ src/common/mdec.hpp | 90 ++++++ src/common/mdec.s | 573 ++++++++++++++++++++++++++++++++++ src/common/romdrivers.hpp | 1 - src/common/storage/device.cpp | 6 + src/common/storage/device.hpp | 1 - src/common/util/string.cpp | 40 +++ src/common/util/string.hpp | 12 +- src/common/util/tween.cpp | 20 +- src/main/app/app.cpp | 4 +- src/main/app/cartworkers.cpp | 10 +- src/main/app/misc.cpp | 4 +- src/main/app/misc.hpp | 2 +- src/main/app/miscworkers.cpp | 10 +- src/main/app/modals.cpp | 2 +- src/main/app/romworkers.cpp | 32 +- src/main/cart/cartdata.hpp | 2 - src/main/cart/cartio.hpp | 1 - src/main/main.cpp | 2 + src/ps1/registers.h | 51 ++- 27 files changed, 1374 insertions(+), 266 deletions(-) create mode 100644 cmake/options.cmake create mode 100644 src/common/mdec.cpp create mode 100644 src/common/mdec.hpp create mode 100644 src/common/mdec.s diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fdb9cb..d498940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,36 +24,12 @@ project( HOMEPAGE_URL "https://github.com/spicyjpeg/573in1" ) +include(cmake/options.cmake) + +## Source files + set( - RELEASE_INFO "${PROJECT_NAME} ${PROJECT_VERSION} - (C) 2022-2024 spicyjpeg" - 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 + ps1Sources #src/libc/crt0.c src/libc/cxxsupport.cpp src/libc/malloc.c @@ -66,75 +42,61 @@ add_library( src/ps1/system.s src/ps1/unhandledexc.c ) -target_include_directories( - common PUBLIC - src - src/libc +set( + vendorSources + src/vendor/ff.c + src/vendor/ffunicode.c + src/vendor/miniz.c + src/vendor/printf.c + src/vendor/qrcodegen.c ) -target_compile_options( - common PUBLIC - -Wall - -Wextra - -Wno-unused-parameter - $<$: - -Wno-pmf-conversions - > + +set( + commonSources + src/common/args.cpp + src/common/gpu.cpp + src/common/gpufont.cpp + 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( - common PUBLIC - 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} - "$" - "${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 +set( + fsSources src/common/fs/fat.cpp src/common/fs/file.cpp src/common/fs/iso9660.cpp src/common/fs/misc.cpp src/common/fs/zip.cpp +) +set( + storageSources src/common/storage/ata.cpp src/common/storage/atapi.cpp src/common/storage/device.cpp +) +set( + utilSources src/common/util/hash.cpp src/common/util/log.cpp src/common/util/misc.cpp src/common/util/string.cpp src/common/util/string.s src/common/util/tween.cpp - src/common/args.cpp - src/common/gpu.cpp - src/common/gpufont.cpp - src/common/io.cpp - src/common/ioboard.cpp - src/common/pad.cpp - src/common/rom.cpp - src/common/romdrivers.cpp - src/common/spu.cpp +) + +set( + mainSources + ${ps1Sources} + ${vendorSources} + ${commonSources} + ${fsSources} + ${storageSources} + ${utilSources} src/libc/crt0.c src/main/app/app.cpp src/main/app/cartactions.cpp @@ -155,82 +117,109 @@ addPS1Executable( src/main/uibase.cpp src/main/uicommon.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( - main PRIVATE - # Logging options - ENABLE_APP_LOGGING=1 - ENABLE_CART_IO_LOGGING=1 - 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 +set( + launcherSources + ${ps1Sources} + ${storageSources} + ${utilSources} + src/common/args.cpp + src/common/io.cpp + src/launcher/exchandler.s + src/launcher/main.cpp + src/libc/crt0.c +) +set( + bootStubSources + ${ps1Sources} + ${utilSources} + src/boot/crt0.s + src/boot/main.cpp + src/common/io.cpp ) -## Boot stub and executable launchers +## Flags and compile-time options + +set( + commonOptions + -Wall + -Wextra + -Wno-unused-parameter + $<$: + -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. -add_library(bootFlags INTERFACE) -target_compile_options(bootFlags INTERFACE -Os) +target_compile_options(mainFlags INTERFACE ${commonOptions}) +target_compile_options(subExecutableFlags INTERFACE ${commonOptions} -Os) + target_compile_definitions( - bootFlags INTERFACE - $<$: - #ENABLE_ARGV=1 - #ENABLE_LOGGING=1 - NDEBUG=1 - > + mainFlags INTERFACE + ${mainOptions} + VERSION="${PROJECT_VERSION}" + EXTERNAL_DATA_DIR="hdd:/${PROJECT_NAME}" +) +target_compile_definitions( + subExecutableFlags INTERFACE + ${subExecutableOptions} + 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/io.cpp - src/launcher/exchandler.s - src/launcher/main.cpp - src/libc/crt0.c - src/vendor/printf.c +## 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} + "$" + "${name}.psexe" + VERBATIM ) - target_link_libraries(launcher${address} PRIVATE bootFlags) endfunction() -# IMPORTANT: these addresses assume the launcher's total size (including code, -# heap and stack allocations, but excluding the executable header) is <12 KB -# (0x3000 bytes). -addLauncher(801fd000 801ffff0) -addLauncher(803fd000 803ffff0) +# IMPORTANT: these addresses assume the boot executable's size (including code, +# heap and stack allocations as well as the resource archive, but excluding the +# executable header) is 576 KB (0x90000 bytes) or less, and that each launcher's +# size is 12 KB (0x3000 bytes) or less. +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/*) 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) add_custom_command( @@ -250,23 +239,17 @@ function(addBootStub name resourceName) VERBATIM ) - addPS1Executable( - ${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 - ) + addPS1Executable(${name} 80010000 0) addBinaryFile( ${name} _resourceArchive _resourceArchiveLength "${PROJECT_BINARY_DIR}/${resourceName}.zip" ) - target_link_libraries(${name} PRIVATE bootFlags) + + target_link_libraries(${name} PUBLIC bootStub) endfunction() -addBootStub("${RELEASE_NAME}" resources) -addBootStub("${RELEASE_NAME}-tiny" resourcestiny) +addBuildVariant("${RELEASE_NAME}" resources) +addBuildVariant("${RELEASE_NAME}-tiny" resourcestiny) ## CD-ROM image diff --git a/cmake/options.cmake b/cmake/options.cmake new file mode 100644 index 0000000..5b38a6e --- /dev/null +++ b/cmake/options.cmake @@ -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 . + +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 + $<$:ENABLE_LOG_BUFFER=1> + $<$:ENABLE_APP_LOGGING=1> + $<$:ENABLE_CART_IO_LOGGING=1> + $<$:ENABLE_CART_DATA_LOGGING=1> + $<$:ENABLE_IO_LOGGING=1> + $<$:ENABLE_ROM_LOGGING=1> + $<$:ENABLE_STORAGE_LOGGING=1> + $<$:ENABLE_FS_LOGGING=1> + $<$:ENABLE_DUMMY_CART_DRIVER=1> + $<$:ENABLE_X76F041_CART_DRIVER=1> + $<$:ENABLE_X76F100_CART_DRIVER=1> + $<$:ENABLE_ZS01_CART_DRIVER=1> + $<$:ENABLE_AUTOBOOT=1> + $<$:ENABLE_PCDRV=1> + $<$:ENABLE_PS1_CONTROLLER=1> +) +set( + subExecutableOptions + $<$:ENABLE_ARGV_PARSER=1> +) diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 11276a7..249a00a 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -90,7 +90,7 @@ int main(int argc, const char **argv) { util::hexValueToString(&_lengthArg[16], _resourceArchiveLength, 8); loader.addArgument(_lengthArg); -#ifdef ENABLE_ARGV +#ifdef ENABLE_ARGV_PARSER for (; argc > 0; argc--) { if (!loader.copyArgument(*(argv++))) break; diff --git a/src/common/fs/fat.cpp b/src/common/fs/fat.cpp index 6205bd7..476d247 100644 --- a/src/common/fs/fat.cpp +++ b/src/common/fs/fat.cpp @@ -246,17 +246,17 @@ bool FATProvider::createDirectory(const char *path) { } File *FATProvider::openFile(const char *path, uint32_t flags) { - auto _file = new FATFile(); - auto error = f_open(&_fs, &(_file->_fd), path, uint8_t(flags)); + auto file = new FATFile(); + auto error = f_open(&_fs, &(file->_fd), path, uint8_t(flags)); if (error) { LOG_FS("%s: %s", _FATFS_ERROR_NAMES[error], path); - delete _file; + delete file; return nullptr; } - _file->size = f_size(&(_file->_fd)); - return _file; + file->size = f_size(&(file->_fd)); + return file; } /* FatFs library API glue */ diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp index c186aa4..dc0443e 100644 --- a/src/common/fs/file.cpp +++ b/src/common/fs/file.cpp @@ -52,56 +52,54 @@ Directory::~Directory(void) { /* Base file and asset provider classes */ -uint32_t currentSPUOffset = spu::DUMMY_BLOCK_END; - Provider::~Provider(void) { close(); } 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; - assert(_file->size <= SIZE_MAX); - if (!output.allocate(size_t(_file->size))) { - _file->close(); - delete _file; + assert(file->size <= SIZE_MAX); + if (!output.allocate(size_t(file->size))) { + file->close(); + delete file; return 0; } - size_t actualLength = _file->read(output.ptr, output.length); + size_t actualLength = file->read(output.ptr, output.length); - _file->close(); - delete _file; + file->close(); + delete file; return actualLength; } 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; - assert(_file->size >= length); - size_t actualLength = _file->read(output, length); + assert(file->size >= length); + size_t actualLength = file->read(output, length); - _file->close(); - delete _file; + file->close(); + delete file; return actualLength; } 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; - size_t actualLength = _file->write(input, length); + size_t actualLength = file->write(input, length); - _file->close(); - delete _file; + file->close(); + delete file; return actualLength; } @@ -118,22 +116,26 @@ size_t Provider::loadTIM(gpu::Image &output, const char *path) { data.destroy(); return 0; } - if (header->flags & (1 << 3)) { - auto clut = reinterpret_cast(section); - gpu::upload(clut->vram, &clut[1], true); + size_t uploadLength = 0; + + if (header->flags & (1 << 3)) { + auto clut = reinterpret_cast(section); + uploadLength += gpu::upload(clut->vram, &clut[1], true); + section += clut->length; } - auto image = reinterpret_cast(section); - - gpu::upload(image->vram, &image[1], true); + auto image = reinterpret_cast(section); + uploadLength += gpu::upload(image->vram, &image[1], true); 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 // time, but whatever. util::Data data; @@ -144,17 +146,16 @@ size_t Provider::loadVAG(spu::Sound &output, const char *path) { auto header = data.as(); auto body = reinterpret_cast(&header[1]); - if (!output.initFromVAGHeader(header, currentSPUOffset)) { + if (!output.initFromVAGHeader(header, offset)) { data.destroy(); return 0; } - currentSPUOffset += spu::upload( - currentSPUOffset, body, data.length - sizeof(spu::VAGHeader), true - ); + auto uploadLength = + spu::upload(offset, body, data.length - sizeof(spu::VAGHeader), true); data.destroy(); - return data.length; + return uploadLength; } struct [[gnu::packed]] BMPHeader { @@ -186,16 +187,16 @@ public: }; 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; BMPHeader header; 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; if (buffer.allocate(rect.w + 32)) { @@ -224,14 +225,14 @@ size_t Provider::saveVRAMBMP(gpu::RectWH &rect, const char *path) { *(ptr++) = newValue; } - length += _file->write(buffer.ptr, lineLength); + length += file->write(buffer.ptr, lineLength); } buffer.destroy(); } - _file->close(); - delete _file; + file->close(); + delete file; return length; } diff --git a/src/common/fs/file.hpp b/src/common/fs/file.hpp index 8cfa558..a17c685 100644 --- a/src/common/fs/file.hpp +++ b/src/common/fs/file.hpp @@ -113,8 +113,6 @@ public: /* Base file and asset provider classes */ -extern uint32_t currentSPUOffset; - class Provider { public: FileSystemType type; @@ -153,7 +151,7 @@ public: virtual size_t saveData(const void *input, size_t length, 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); }; diff --git a/src/common/fs/zip.cpp b/src/common/fs/zip.cpp index 5097272..5528e14 100644 --- a/src/common/fs/zip.cpp +++ b/src/common/fs/zip.cpp @@ -124,12 +124,12 @@ bool ZIPProvider::init(File *file) { _zip.m_pRead = []( void *opaque, uint64_t offset, void *output, size_t length ) -> size_t { - auto _file = reinterpret_cast(opaque); + auto file = reinterpret_cast(opaque); - if (_file->seek(offset) != offset) + if (file->seek(offset) != offset) return 0; - return _file->read(output, length); + return file->read(output, length); }; if (!mz_zip_reader_init(&_zip, file->size, _ZIP_FLAGS)) { diff --git a/src/common/mdec.cpp b/src/common/mdec.cpp new file mode 100644 index 0000000..0ec63b1 --- /dev/null +++ b/src/common/mdec.cpp @@ -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 . + */ + +#include +#include +#include +#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(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(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(CACHE_BASE); + + __builtin_memcpy(table, &_HUFFMAN_TABLE, sizeof(BSHuffmanTable)); +} + +} diff --git a/src/common/mdec.hpp b/src/common/mdec.hpp new file mode 100644 index 0000000..34be93a --- /dev/null +++ b/src/common/mdec.hpp @@ -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 . + */ + +#pragma once + +#include +#include +#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); + +} diff --git a/src/common/mdec.s b/src/common/mdec.s new file mode 100644 index 0000000..780912f --- /dev/null +++ b/src/common/mdec.s @@ -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 . + +.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 diff --git a/src/common/romdrivers.hpp b/src/common/romdrivers.hpp index dbc854e..3eb5747 100644 --- a/src/common/romdrivers.hpp +++ b/src/common/romdrivers.hpp @@ -89,7 +89,6 @@ public: // Note that all offsets must be multiples of 2, as writes are done in // halfwords. - virtual ~Driver(void) {} virtual void write(uint32_t offset, uint16_t value) {} virtual void eraseSector(uint32_t offset) {} virtual void eraseChip(uint32_t offset) {} diff --git a/src/common/storage/device.cpp b/src/common/storage/device.cpp index acf2f0e..8fb6c36 100644 --- a/src/common/storage/device.cpp +++ b/src/common/storage/device.cpp @@ -127,6 +127,9 @@ void IDEDevice::_writePIO(const void *data, size_t length) const { bool IDEDevice::_readDMA(void *data, size_t length) const { util::assertAligned(data); + if (!waitForDMATransfer(DMA_PIO, _DMA_TIMEOUT)) + return false; + DMA_MADR(DMA_PIO) = reinterpret_cast(data); DMA_BCR (DMA_PIO) = (length + 3) / 4; 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 { util::assertAligned(data); + if (!waitForDMATransfer(DMA_PIO, _DMA_TIMEOUT)) + return false; + DMA_MADR(DMA_PIO) = reinterpret_cast(data); DMA_BCR (DMA_PIO) = (length + 3) / 4; DMA_CHCR(DMA_PIO) = 0 diff --git a/src/common/storage/device.hpp b/src/common/storage/device.hpp index 5dd8545..fc1fd59 100644 --- a/src/common/storage/device.hpp +++ b/src/common/storage/device.hpp @@ -206,7 +206,6 @@ public: inline Device(uint8_t flags = 0) : type(NONE), flags(flags), sectorLength(0), capacity(0) {} - virtual ~Device(void) {} virtual DeviceError enumerate(void) { return UNSUPPORTED_OP; } virtual DeviceError poll(void) { return UNSUPPORTED_OP; } virtual void handleInterrupt(void) {} diff --git a/src/common/util/string.cpp b/src/common/util/string.cpp index afe7da4..92fffc8 100644 --- a/src/common/util/string.cpp +++ b/src/common/util/string.cpp @@ -111,6 +111,46 @@ size_t encodeBase41(char *output, const uint8_t *input, size_t length) { /* 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) { for (size_t length = 0;; length++) { auto value = parseUTF8Character(str); diff --git a/src/common/util/string.hpp b/src/common/util/string.hpp index 6e13706..98efff0 100644 --- a/src/common/util/string.hpp +++ b/src/common/util/string.hpp @@ -43,17 +43,19 @@ public: size_t length; }; +#if 0 +UTF8Character parseUTF8Character(const char *ch); +#else extern "C" uint64_t _parseUTF8Character(const char *ch); -size_t getUTF8StringLength(const char *str); static inline UTF8Character parseUTF8Character(const char *ch) { auto values = _parseUTF8Character(ch); - return { - .codePoint = UTF8CodePoint(values), - .length = size_t(values >> 32) - }; + return { UTF8CodePoint(values), size_t(values >> 32) }; } +#endif + +size_t getUTF8StringLength(const char *str); /* LZ4 decompressor */ diff --git a/src/common/util/tween.cpp b/src/common/util/tween.cpp index 0e10e86..5462811 100644 --- a/src/common/util/tween.cpp +++ b/src/common/util/tween.cpp @@ -50,14 +50,16 @@ template T Tween::getValue(int time) const { ) / TWEEN_UNIT; } -template class Tween; -template class Tween; -template class Tween; -template class Tween; -template class Tween; -template class Tween; -template class Tween; -template class Tween; -template class Tween; +// 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; +template class Tween; +template class Tween; +template class Tween; +template class Tween; +template class Tween; +template class Tween; +template class Tween; +template class Tween; } diff --git a/src/main/app/app.cpp b/src/main/app/app.cpp index 508a761..c550ee9 100644 --- a/src/main/app/app.cpp +++ b/src/main/app/app.cpp @@ -272,10 +272,10 @@ void App::_loadResources(void) { res.loadTIM(_splashOverlay.image, "assets/textures/splash.tim"); 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++) - res.loadVAG(_ctx.sounds[i], _UI_SOUND_PATHS[i]); + res.loadVAG(_ctx.sounds[i], spuOffset, _UI_SOUND_PATHS[i]); } bool App::_createDataDirectory(void) { diff --git a/src/main/app/cartworkers.cpp b/src/main/app/cartworkers.cpp index 1c1c15e..2212f1e 100644 --- a/src/main/app/cartworkers.cpp +++ b/src/main/app/cartworkers.cpp @@ -267,15 +267,15 @@ bool App::_cartRestoreWorker(void) { _workerStatus.update(0, 3, WSTR("App.cartRestoreWorker.init")); const char *path = _fileBrowserScreen.selectedPath; - auto _file = _fileIO.vfs.openFile(path, fs::READ); + auto file = _fileIO.vfs.openFile(path, fs::READ); cart::CartDump newDump; - if (_file) { - auto length = _file->read(&newDump, sizeof(newDump)); + if (file) { + auto length = file->read(&newDump, sizeof(newDump)); - _file->close(); - delete _file; + file->close(); + delete file; if (length < (sizeof(newDump) - sizeof(newDump.data))) goto _fileError; diff --git a/src/main/app/misc.cpp b/src/main/app/misc.cpp index c70ebb8..9cb06dc 100644 --- a/src/main/app/misc.cpp +++ b/src/main/app/misc.cpp @@ -310,8 +310,8 @@ void ResolutionScreen::update(ui::Context &ctx) { } } -static constexpr uint16_t _LOOP_FADE_IN_VOLUME = spu::MAX_VOLUME / 2; -static constexpr int _LOOP_FADE_IN_TIME = 30; +static constexpr int _LOOP_FADE_IN_VOLUME = spu::MAX_VOLUME / 2; +static constexpr int _LOOP_FADE_IN_TIME = 30; void AboutScreen::show(ui::Context &ctx, bool goBack) { _title = STR("AboutScreen.title"); diff --git a/src/main/app/misc.hpp b/src/main/app/misc.hpp index f4a1b3d..89b0623 100644 --- a/src/main/app/misc.hpp +++ b/src/main/app/misc.hpp @@ -65,7 +65,7 @@ private: util::Data _text; spu::Channel _loopChannel; - util::Tween _loopVolume; + util::Tween _loopVolume; public: void show(ui::Context &ctx, bool goBack = false); diff --git a/src/main/app/miscworkers.cpp b/src/main/app/miscworkers.cpp index fa125ee..1837af4 100644 --- a/src/main/app/miscworkers.cpp +++ b/src/main/app/miscworkers.cpp @@ -151,12 +151,12 @@ bool App::_executableWorker(void) { } else { __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) { - _file->read(&header, sizeof(header)); - _file->close(); - delete _file; + if (file) { + file->read(&header, sizeof(header)); + file->close(); + delete file; } if (!header.validateMagic()) { diff --git a/src/main/app/modals.cpp b/src/main/app/modals.cpp index be06192..5c216ed 100644 --- a/src/main/app/modals.cpp +++ b/src/main/app/modals.cpp @@ -221,7 +221,7 @@ void FilePickerScreen::show(ui::Context &ctx, bool goBack) { _listLength = 0; #ifdef ENABLE_PCDRV - _addDevice(nullptr, APP->_fileIO.host, "host:"); + _addDevice(nullptr, &(APP->_fileIO.host), "host:"); #endif for (size_t i = 0; i < util::countOf(APP->_fileIO.ideDevices); i++) diff --git a/src/main/app/romworkers.cpp b/src/main/app/romworkers.cpp index a7ee04f..d2e0618 100644 --- a/src/main/app/romworkers.cpp +++ b/src/main/app/romworkers.cpp @@ -145,11 +145,11 @@ bool App::_romDumpWorker(void) { snprintf(filePath, sizeof(filePath), entry.path, dirPath); - auto _file = _fileIO.vfs.openFile( + auto file = _fileIO.vfs.openFile( filePath, fs::WRITE | fs::ALLOW_CREATE ); - if (!_file) + if (!file) goto _fileError; util::Data buffer; @@ -161,10 +161,10 @@ bool App::_romDumpWorker(void) { _workerStatus.update(i, numChunks, WSTRH(entry.dumpPrompt)); entry.region.read(buffer.ptr, offset, chunkLength); - if (_file->write(buffer.ptr, chunkLength) < chunkLength) { + if (file->write(buffer.ptr, chunkLength) < chunkLength) { buffer.destroy(); - _file->close(); - delete _file; + file->close(); + delete file; goto _fileError; } @@ -173,8 +173,8 @@ bool App::_romDumpWorker(void) { } buffer.destroy(); - _file->close(); - delete _file; + file->close(); + delete file; LOG_APP("%s saved", filePath); } @@ -201,9 +201,9 @@ bool App::_romRestoreWorker(void) { _workerStatus.update(0, 1, WSTR("App.romRestoreWorker.init")); 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( MESSAGE_ERROR, WSTR("App.romRestoreWorker.fileError"), path ); @@ -243,8 +243,8 @@ bool App::_romRestoreWorker(void) { size_t j = numChips; j > 0; j--, bufferPtr += maxChunkLength, offset += chipLength ) { - _file->seek(offset); - auto length = _file->read(bufferPtr, maxChunkLength); + file->seek(offset); + auto length = file->read(bufferPtr, maxChunkLength); // Data is written 16 bits at a time, so the chunk must be padded to // an even number of bytes. @@ -301,8 +301,8 @@ bool App::_romRestoreWorker(void) { buffers.destroy(); chunkLengths.destroy(); - _file->close(); - delete _file; + file->close(); + delete file; delete driver; _messageScreen.setMessage( @@ -316,14 +316,14 @@ bool App::_romRestoreWorker(void) { util::Hash message; - message = (_file->size > regionLength) + message = (file->size > regionLength) ? "App.romRestoreWorker.overflow"_h : "App.romRestoreWorker.success"_h; buffers.destroy(); chunkLengths.destroy(); - _file->close(); - delete _file; + file->close(); + delete file; delete driver; _messageScreen.setMessage(MESSAGE_SUCCESS, WSTRH(message), bytesWritten); diff --git a/src/main/cart/cartdata.hpp b/src/main/cart/cartdata.hpp index 7863d84..674d9a6 100644 --- a/src/main/cart/cartdata.hpp +++ b/src/main/cart/cartdata.hpp @@ -133,7 +133,6 @@ public: inline CartParser(CartDump &dump, uint8_t flags = 0) : _dump(dump), flags(flags) {} - virtual ~CartParser(void) {} virtual size_t getCode(char *output) const { return 0; } virtual void setCode(const char *input) {} virtual size_t getRegion(char *output) const { return 0; } @@ -219,7 +218,6 @@ public: inline ROMHeaderParser(ROMHeaderDump &dump, uint8_t flags = 0) : _dump(dump), flags(flags) {} - virtual ~ROMHeaderParser(void) {} virtual size_t getCode(char *output) const { return 0; } virtual void setCode(const char *input) {} virtual size_t getRegion(char *output) const { return 0; } diff --git a/src/main/cart/cartio.hpp b/src/main/cart/cartio.hpp index 243fb63..7ca00bd 100644 --- a/src/main/cart/cartio.hpp +++ b/src/main/cart/cartio.hpp @@ -47,7 +47,6 @@ public: inline Driver(CartDump &dump) : _dump(dump) {} - virtual ~Driver(void) {} virtual DriverError readSystemID(void) { return UNSUPPORTED_OP; } virtual DriverError readCartID(void) { return UNSUPPORTED_OP; } virtual DriverError readPublicData(void) { return UNSUPPORTED_OP; } diff --git a/src/main/main.cpp b/src/main/main.cpp index 853ec0f..a8ee35e 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -20,6 +20,7 @@ #include "common/gpu.hpp" #include "common/io.hpp" #include "common/ioboard.hpp" +#include "common/mdec.hpp" #include "common/spu.hpp" #include "main/app/app.hpp" #include "main/uibase.hpp" @@ -35,6 +36,7 @@ int main(int argc, const char **argv) { installExceptionHandler(); gpu::init(); spu::init(); + mdec::init(); io::init(); util::initZipCRC32(); diff --git a/src/ps1/registers.h b/src/ps1/registers.h index 576efb8..c1b5947 100644 --- a/src/ps1/registers.h +++ b/src/ps1/registers.h @@ -369,18 +369,45 @@ typedef enum { /* MDEC */ typedef enum { - MDEC_STAT_BLOCK_BITMASK = 7 << 16, - MDEC_STAT_BLOCK_Y0 = 0 << 16, - MDEC_STAT_BLOCK_Y1 = 1 << 16, - MDEC_STAT_BLOCK_Y2 = 2 << 16, - MDEC_STAT_BLOCK_Y3 = 3 << 16, - MDEC_STAT_BLOCK_CR = 4 << 16, - MDEC_STAT_BLOCK_CB = 5 << 16, - MDEC_STAT_DREQ_OUT = 1 << 27, - MDEC_STAT_DREQ_IN = 1 << 28, - MDEC_STAT_BUSY = 1 << 29, - MDEC_STAT_DATA_FULL = 1 << 30, - MDEC_STAT_DATA_EMPTY = 1 << 31 + 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_Y0 = 0 << 16, + MDEC_STAT_BLOCK_Y1 = 1 << 16, + MDEC_STAT_BLOCK_Y2 = 2 << 16, + MDEC_STAT_BLOCK_Y3 = 3 << 16, + MDEC_STAT_BLOCK_CR = 4 << 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_IN = 1 << 28, + MDEC_STAT_BUSY = 1 << 29, + MDEC_STAT_DATA_FULL = 1 << 30, + MDEC_STAT_DATA_EMPTY = 1 << 31 } MDECStatusFlag; typedef enum {