diff --git a/CMakeLists.txt b/CMakeLists.txt index 9385352..a15270f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ endif() set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +include("cmake/bin2h.cmake") include(FetchContent) FetchContent_Declare( tomlplusplus @@ -27,12 +28,15 @@ FetchContent_MakeAvailable(tomlplusplus) FetchContent_MakeAvailable(xxHash) add_subdirectory(${THIRDPARTY_ROOT}/disasm) +set(POWERANALYSE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/PowerAnalyse) +set(POWERRECOMP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/PowerRecomp) +set(POWERUTILS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/PowerUtils) project ("PowerRecomp-ALL") -add_subdirectory(PowerAnalyse) -add_subdirectory(PowerRecomp) -add_subdirectory(PowerUtils) +add_subdirectory(${POWERANALYSE_ROOT}) +add_subdirectory(${POWERRECOMP_ROOT}) +add_subdirectory(${POWERUTILS_ROOT}) # Only build sample and tests if this is the top level project if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) diff --git a/PowerRecomp/CMakeLists.txt b/PowerRecomp/CMakeLists.txt index c170c24..0e749ce 100644 --- a/PowerRecomp/CMakeLists.txt +++ b/PowerRecomp/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required (VERSION 3.8) project("PowerRecomp") +BIN2H(SOURCE_FILE ${POWERUTILS_ROOT}/ppc_context.h HEADER_FILE "generated/ppc_context.gen.h" VARIABLE_NAME "gPPCContextText") + add_executable(PowerRecomp "main.cpp" "pch.h" "recompiler.cpp" "recompiler.h" "swa_recompiler.cpp" "swa_recompiler.h" "test_recompiler.cpp" "test_recompiler.h") target_precompile_headers(PowerRecomp PUBLIC "pch.h") target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse tomlplusplus::tomlplusplus xxHash::xxhash) diff --git a/PowerRecomp/generated/.gitignore b/PowerRecomp/generated/.gitignore new file mode 100644 index 0000000..cec9082 --- /dev/null +++ b/PowerRecomp/generated/.gitignore @@ -0,0 +1,3 @@ +* + +!.gitignore diff --git a/PowerRecomp/pch.h b/PowerRecomp/pch.h index 572f533..0ec0b71 100644 --- a/PowerRecomp/pch.h +++ b/PowerRecomp/pch.h @@ -19,3 +19,4 @@ #include #include #include +#include "generated/ppc_context.gen.h" diff --git a/PowerRecomp/recompiler.cpp b/PowerRecomp/recompiler.cpp index 89a8dbc..15b6cee 100644 --- a/PowerRecomp/recompiler.cpp +++ b/PowerRecomp/recompiler.cpp @@ -2097,7 +2097,7 @@ void Recompiler::Recompile(const char* directoryPath) out.reserve(10 * 1024 * 1024); { - println("#pragma once\n"); + println("#pragma once"); println("#ifndef PPC_CONFIG_H_INCLUDED"); println("#define PPC_CONFIG_H_INCLUDED\n"); @@ -2124,10 +2124,19 @@ void Recompiler::Recompile(const char* directoryPath) SaveCurrentOutData(directoryPath, "ppc_config.h"); } + { + println("#pragma once"); + + println("#include \"ppc_config.h\""); + println("{}", std::string_view{gPPCContextText, gPPCContextText_SIZE}); + + SaveCurrentOutData(directoryPath, "ppc_context.h"); + } + { println("#pragma once\n"); println("#include \"ppc_config.h\""); - println("#include \n"); + println("#include \"ppc_context.h\"\n"); for (auto& symbol : image.symbols) println("PPC_EXTERN_FUNC({});", symbol.name); diff --git a/PowerUtils/ppc_context.h b/PowerUtils/ppc_context.h index d9f534a..0fc8be0 100644 --- a/PowerUtils/ppc_context.h +++ b/PowerUtils/ppc_context.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef PPC_CONTEXT_H_INCLUDED +#define PPC_CONTEXT_H_INCLUDED #ifndef PPC_CONFIG_H_INCLUDED #error "ppc_config.h must be included before ppc_context.h" @@ -579,3 +580,5 @@ inline __m128i _mm_vsr(__m128i a, __m128i b) b = _mm_srli_epi64(_mm_slli_epi64(b, 61), 61); return _mm_castps_si128(_mm_insert_ps(_mm_castsi128_ps(_mm_srl_epi64(a, b)), _mm_castsi128_ps(_mm_srl_epi64(_mm_srli_si128(a, 4), b)), 0x10)); } + +#endif diff --git a/cmake/bin2h.cmake b/cmake/bin2h.cmake new file mode 100644 index 0000000..b33e652 --- /dev/null +++ b/cmake/bin2h.cmake @@ -0,0 +1,83 @@ +# https://github.com/sivachandran/cmake-bin2h +include(CMakeParseArguments) + +# Function to wrap a given string into multiple lines at the given column position. +# Parameters: +# VARIABLE - The name of the CMake variable holding the string. +# AT_COLUMN - The column position at which string will be wrapped. +function(WRAP_STRING) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) + + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") + + while(stringLength GREATER 0) + + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() + + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") + + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() + + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) +endfunction() + +# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file +# will contain a byte array and integer variable holding the size of the array. +# Parameters +# SOURCE_FILE - The path of source file whose contents will be embedded in the header file. +# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append +# to this name and will be used a variable name for size variable. +# HEADER_FILE - The path of header file. +# APPEND - If specified appends to the header file instead of overwriting it +# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be +# useful if the source file is a text file and we want to use the file contents +# as string. But the size variable holds size of the byte array without this +# null byte. +# Usage: +# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") +function(BIN2H) + set(options APPEND NULL_TERMINATE) + set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) + cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) + + # reads source file contents as hex string + file(READ ${BIN2H_SOURCE_FILE} hexString HEX) + string(LENGTH ${hexString} hexStringLength) + + # appends null byte if asked + if(BIN2H_NULL_TERMINATE) + set(hexString "${hexString}00") + endif() + + # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) + wrap_string(VARIABLE hexString AT_COLUMN 32) + math(EXPR arraySize "${hexStringLength} / 2") + + # adds '0x' prefix and comma suffix before and after every byte respectively + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) + # removes trailing comma + string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) + + # converts the variable name into proper C identifier + string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + + # declares byte array and the length variables + set(arrayDefinition "const char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") + set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") + + set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") + if(BIN2H_APPEND) + file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") + else() + file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") + endif() +endfunction()