Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
92571ae
Answer sceKernelIsCpuIntrEnable
MHunterG Sep 26, 2026
40a9384
List disc directories with the names as the disc spells them
MHunterG Sep 26, 2026
9a2521b
Implement sceIoChdir and open disc files with write access read-only
MHunterG Sep 26, 2026
8520ac1
Ask for a looping streamed ATRAC track's loop again once the file is in
MHunterG Sep 26, 2026
782d945
Number the GE's own SIGNAL list flow as Patapon uses it
MHunterG Sep 26, 2026
13ba7fa
Add <prefix>_TRACE_SAS: voices set, keyed on and off, end flags
MHunterG Sep 26, 2026
dd7276d
Implement message pipes (sceKernel*MsgPipe)
MHunterG Sep 26, 2026
e19c7bc
Implement scePsmf, the PSMF header library
MHunterG Sep 26, 2026
14d14eb
Implement sceMpegAvcCsc
MHunterG Sep 26, 2026
9df93c8
Let the clock move for a thread that reads it and never waits
MHunterG Sep 26, 2026
00857f9
Implement sceKernelReferThreadStatus, and charge busy clock reads
MHunterG Sep 26, 2026
a8751ef
Answer sceAtracGetSecondBufferInfo: no second buffer is needed
MHunterG Sep 26, 2026
c7c73c9
Pass the corpus link, and any long compile, through a response file
MHunterG Sep 26, 2026
3f6cb17
Implement sceKernelReferEventFlagStatus, sceDisplayGetFramePerSec, sc…
MHunterG Sep 26, 2026
36e8073
Charge a busy thread's time as any import finishes, past 100 ms
MHunterG Sep 26, 2026
cced2bc
Merge origin/main into hle-coverage
MHunterG Sep 26, 2026
791d2fb
Implement sceRtc's tick and calendar calls
MHunterG Sep 26, 2026
63bf4f1
Merge origin/main into hle-coverage
MHunterG Sep 26, 2026
b0b0443
Implement sceNetAdhocctlCreate, Connect, Join, GetNameByAddr and sceN…
MHunterG Sep 26, 2026
5712e24
Answer the clock, cache and thread calls PSP2i, GoW and Patapon make
MHunterG Sep 26, 2026
ce81987
Answer infrastructure networking as a PSP with no access point
MHunterG Sep 26, 2026
05c6e41
Implement the small calls left in the maintainer's games' import lists
MHunterG Sep 26, 2026
f2b2015
Add docs/HLE_COVERAGE.md: what the HLE answers and how far it is checked
MHunterG Sep 26, 2026
3f0b223
Document TRACE_GE_LIST, TRACE_SAS and NO_BUSY_CLOCK
MHunterG Sep 26, 2026
8c14a91
Trace where sceMpegAvcDecode writes its picture, and in which format
MHunterG Sep 26, 2026
6b78a9c
Show movie pictures the game decodes straight into VRAM
MHunterG Sep 26, 2026
2b5caa5
Merge origin/main into hle-coverage
MHunterG Sep 26, 2026
167108d
Answer the profiler queries as a PSP with the profiler off
MHunterG Sep 26, 2026
a19f4dd
Close the response file before the test removes it
MHunterG Sep 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,46 @@ if(PSPRECOMP_BUILD_TESTS)
add_test(NAME portablekit_pool_tests COMMAND portablekit_pool_tests)
endif()

# Message pipes (sceKernel*MsgPipe): their bookkeeping, with no kernel.
if(PSPRECOMP_BUILD_TESTS)
add_executable(portablekit_pipe_tests
"${PORTABLEKIT_ROOT}/tests/pipe_tests.cpp"
"${PORTABLEKIT_ROOT}/host/kernel/message_pipe.cpp")
target_include_directories(portablekit_pipe_tests PRIVATE "${PORTABLEKIT_ROOT}/host")
set_target_properties(portablekit_pipe_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_test(NAME portablekit_pipe_tests COMMAND portablekit_pipe_tests)
endif()

# The PSMF header as scePsmf reads it.
if(PSPRECOMP_BUILD_TESTS)
add_executable(portablekit_psmf_tests
"${PORTABLEKIT_ROOT}/tests/psmf_tests.cpp"
"${PORTABLEKIT_ROOT}/host/movie/psmf_header.cpp")
target_include_directories(portablekit_psmf_tests PRIVATE "${PORTABLEKIT_ROOT}/host")
set_target_properties(portablekit_psmf_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_test(NAME portablekit_psmf_tests COMMAND portablekit_psmf_tests)
endif()

# The desktop app's response files for long compile and link command lines.
if(PSPRECOMP_BUILD_TESTS)
add_executable(portablekit_response_file_tests
"${PORTABLEKIT_ROOT}/tests/response_file_tests.cpp"
"${PORTABLEKIT_ROOT}/apps/portablekit/src/response_file.cpp")
target_include_directories(portablekit_response_file_tests PRIVATE "${PORTABLEKIT_ROOT}/apps/portablekit/src")
set_target_properties(portablekit_response_file_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_test(NAME portablekit_response_file_tests COMMAND portablekit_response_file_tests)
endif()

# sceRtc's calendar arithmetic.
if(PSPRECOMP_BUILD_TESTS)
add_executable(portablekit_rtc_tests
"${PORTABLEKIT_ROOT}/tests/rtc_tests.cpp"
"${PORTABLEKIT_ROOT}/host/kernel/rtc_time.cpp")
target_include_directories(portablekit_rtc_tests PRIVATE "${PORTABLEKIT_ROOT}/host")
set_target_properties(portablekit_rtc_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_test(NAME portablekit_rtc_tests COMMAND portablekit_rtc_tests)
endif()

# Each platform's settings defaults.
if(PSPRECOMP_BUILD_TESTS)
add_executable(portablekit_settings_tests
Expand Down
1 change: 1 addition & 0 deletions apps/portablekit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(app_sources
src/keys_file.cpp
src/launcher_ui.cpp
src/process.cpp
src/response_file.cpp
src/text_format.cpp)

set(profile_index 0)
Expand Down
24 changes: 20 additions & 4 deletions apps/portablekit/src/corpus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "app_home.hpp"
#include "process.hpp"
#include "response_file.hpp"
#include "text_format.hpp"

#include "corpus_abi.hpp"
Expand All @@ -25,6 +26,10 @@ namespace portablekit::app {
namespace {

namespace fs = std::filesystem;

// Past this many characters a command goes through a response file. Windows
// starts nothing longer than 32767; this leaves room for the program path.
constexpr std::size_t kLongCommandLine = 8000u;
using Clock = std::chrono::steady_clock;

// Exit codes (app_main.cpp lists them all).
Expand Down Expand Up @@ -475,11 +480,18 @@ int compile_corpus(const GameRecord &game, const CompileOptions &options) {
if (!current) {
// Written under another name and renamed when complete, so a
// compile stopped halfway never leaves an object that looks
// finished.
// finished. Compile lines are short; one that is not goes
// through a response file, as the link does.
fs::path partial_object = object;
partial_object += ".part";
const ProcessResult result = run_process(
compile_arguments(command, options.opt_level, source, partial_object, paths.generated), paths.log);
std::vector<std::string> arguments =
compile_arguments(command, options.opt_level, source, partial_object, paths.generated);
if (command_line_length(arguments) > kLongCommandLine) {
fs::path rsp = object;
rsp += ".rsp";
arguments = with_response_file(arguments, command.prefix.size(), rsp);
}
const ProcessResult result = run_process(arguments, paths.log);
if (!result.started || result.exit_code != 0) {
const std::lock_guard<std::mutex> guard(status_lock);
if (!failed) failure = result.started ? "Compiling " + source.filename().string() + " failed; see " + path_text(paths.log) + "." : result.error;
Expand Down Expand Up @@ -509,7 +521,11 @@ int compile_corpus(const GameRecord &game, const CompileOptions &options) {
const auto link_start = Clock::now();
fs::path partial = paths.library;
partial += ".part";
const ProcessResult linked = run_process(link_arguments(command, partial, objects), paths.log);
// Every object by full path is too long a command line for Windows once
// a game has a few hundred units (32767 characters): through a file.
const ProcessResult linked = run_process(
with_response_file(link_arguments(command, partial, objects), command.prefix.size(), paths.root / "link.rsp"),
paths.log);
status.link_seconds = seconds_since(link_start);
if (!linked.started || linked.exit_code != 0)
return fail(kLinkFailed, linked.started ? "Linking failed; see " + path_text(paths.log) + "." : linked.error);
Expand Down
42 changes: 42 additions & 0 deletions apps/portablekit/src/response_file.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "response_file.hpp"

#include <fstream>

namespace portablekit::app {

std::string response_file_text(const std::vector<std::string> &arguments) {
std::string text;
for (const std::string &argument : arguments) {
text += '"';
for (const char c : argument) {
if (c == '\\') text += '/';
else if (c == '"') text += "\\\"";
else text += c;
}
text += "\"\n";
}
return text;
}

std::vector<std::string> with_response_file(const std::vector<std::string> &command, std::size_t keep,
const std::filesystem::path &path) {
if (command.size() <= keep) return command;
const std::vector<std::string> rest(command.begin() + static_cast<std::ptrdiff_t>(keep), command.end());
{
std::ofstream file(path, std::ios::binary | std::ios::trunc);
if (!file) return command;
file << response_file_text(rest);
if (!file) return command;
}
std::vector<std::string> result(command.begin(), command.begin() + static_cast<std::ptrdiff_t>(keep));
result.push_back("@" + path.string());
return result;
}

std::size_t command_line_length(const std::vector<std::string> &command) {
std::size_t length = 0u;
for (const std::string &argument : command) length += argument.size() + 3u; // quotes and a space
return length;
}

} // namespace portablekit::app
32 changes: 32 additions & 0 deletions apps/portablekit/src/response_file.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

// Long command lines through a response file. Windows refuses to start a
// process whose command line is longer than 32767 characters, and a large
// game's link lists hundreds of objects by full path: PSP2i (NPJH50332),
// 385 units, failed there with error 206. Compilers and linkers of every
// toolchain the app drives (clang, clang-cl, lld) read "@file" as the
// arguments in that file.

#include <filesystem>
#include <string>
#include <vector>

namespace portablekit::app {

// The file's text: one argument a line, each in double quotes, with
// backslashes written as forward slashes (every argument with a backslash
// is a Windows path, which accepts either) so that the GNU and the Windows
// rules for reading response files give the same arguments.
[[nodiscard]] std::string response_file_text(const std::vector<std::string> &arguments);

// `command` with everything after the first `keep` arguments (the program,
// usually) moved into a response file at `path`, written here. Returns the
// command unchanged if the file cannot be written.
[[nodiscard]] std::vector<std::string> with_response_file(const std::vector<std::string> &command, std::size_t keep,
const std::filesystem::path &path);

// The length of the command line the arguments make, spaces and quotes
// included, as a program starting them would build it.
[[nodiscard]] std::size_t command_line_length(const std::vector<std::string> &command);

} // namespace portablekit::app
5 changes: 5 additions & 0 deletions cmake/PortableKit.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ set(PORTABLEKIT_HOST_SOURCES
host/audio/atrac_decoder.cpp
host/movie/avc_decoder.cpp
host/movie/psmf_demuxer.cpp
host/movie/psmf_header.cpp
host/audio/audio_sink.cpp
host/audio/sas_core.cpp
host/camera_probe.cpp
Expand All @@ -45,6 +46,8 @@ set(PORTABLEKIT_HOST_SOURCES
host/system.cpp
host/kernel/kernel.cpp
host/kernel/fixed_pool.cpp
host/kernel/message_pipe.cpp
host/kernel/rtc_time.cpp
host/kernel/load_trace.cpp
host/kernel/fast_loading.cpp
host/kernel/load_detector.cpp
Expand All @@ -58,6 +61,8 @@ set(PORTABLEKIT_HOST_SOURCES
host/hle/hle_atrac.cpp
host/hle/hle_mpeg.cpp
host/hle/hle_psmfplayer.cpp
host/hle/hle_psmf.cpp
host/hle/hle_net_offline.cpp
host/fonts/game_font.cpp
host/hle/hle_font.cpp
host/hle/hle_utility.cpp
Expand Down
Loading