diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4846b979..575e9b09 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -177,6 +177,9 @@ jobs: build-macos: runs-on: macos-14 + strategy: + matrix: + arch: [x86_64, arm64] steps: - name: "Checkout repo" uses: actions/checkout@v4 @@ -236,7 +239,7 @@ jobs: cd build cmake .. ${{ env.BUILD_FLAGS }} \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \ - -DCMAKE_OSX_ARCHITECTURES=x86_64 \ + -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} \ -DMACOS_BUNDLE=ON \ -G Ninja @@ -259,7 +262,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: cemu-bin-macos-x64 + name: cemu-bin-macos-${{ matrix.arch }} path: ./bin/Cemu.dmg build-android: diff --git a/.github/workflows/generate_pot.yml b/.github/workflows/generate_pot.yml index b057d441..bd42de46 100644 --- a/.github/workflows/generate_pot.yml +++ b/.github/workflows/generate_pot.yml @@ -31,6 +31,7 @@ jobs: find src -name *.cpp -o -name *.hpp -o -name *.h | xargs xgettext --from-code=utf-8 -w 100 --keyword="_" --keyword="wxTRANSLATE" --keyword="wxPLURAL:1,2" + --keyword="_tr" --keyword="TR_NOOP" --check=space-ellipsis --omit-header -o cemu.pot diff --git a/CMakeLists.txt b/CMakeLists.txt index 05eb6a9d..23ef2a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ if (UNIX AND NOT APPLE AND NOT ANDROID) if(ENABLE_BLUEZ) find_package(bluez REQUIRED) - set(ENABLE_WIIMOTE ON) + set(SUPPORTS_WIIMOTE ON) add_compile_definitions(HAS_BLUEZ) endif() @@ -203,7 +203,7 @@ endif() if (ENABLE_HIDAPI) find_package(hidapi REQUIRED) - set(ENABLE_WIIMOTE ON) + set(SUPPORTS_WIIMOTE ON) add_compile_definitions(HAS_HIDAPI) endif () @@ -237,7 +237,12 @@ endif() add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") +if (CMAKE_OSX_ARCHITECTURES) + set(CEMU_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) +else() + set(CEMU_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +endif() +if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") add_subdirectory("dependencies/xbyak_aarch64" EXCLUDE_FROM_ALL) endif() @@ -253,4 +258,4 @@ if(ANDROID) add_subdirectory("dependencies/libucontext" EXCLUDE_FROM_ALL) endif() -add_subdirectory(src) +add_subdirectory(src) \ No newline at end of file diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index 686a9d08..a8ef3776 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -182,7 +182,13 @@ target_sources(ih264d PRIVATE "decoder/arm/ih264d_function_selector_av8.c" "decoder/arm/ih264d_function_selector.c" ) -target_compile_options(ih264d PRIVATE -DARMV8) +target_compile_options(ih264d PRIVATE -DARMV8 $<$:-Wno-unused-command-line-argument>) +if(NOT MSVC) + set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") +endif() +if(APPLE) + target_sources(ih264d PRIVATE "common/armv8/macos_arm_symbol_aliases.s") +endif() else() message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}") endif() diff --git a/dependencies/ih264d/common/armv8/ih264_intra_pred_chroma_av8.s b/dependencies/ih264d/common/armv8/ih264_intra_pred_chroma_av8.s index 39c02560..c0d9cf99 100644 --- a/dependencies/ih264d/common/armv8/ih264_intra_pred_chroma_av8.s +++ b/dependencies/ih264d/common/armv8/ih264_intra_pred_chroma_av8.s @@ -429,8 +429,13 @@ ih264_intra_pred_chroma_8x8_mode_plane_av8: rev64 v7.4h, v2.4h ld1 {v3.2s}, [x10] sub x5, x3, #8 +#ifdef __APPLE__ + adrp x12, _ih264_gai1_intrapred_chroma_plane_coeffs1@GOTPAGE + ldr x12, [x12, _ih264_gai1_intrapred_chroma_plane_coeffs1@GOTPAGEOFF] +#else adrp x12, :got:ih264_gai1_intrapred_chroma_plane_coeffs1 ldr x12, [x12, #:got_lo12:ih264_gai1_intrapred_chroma_plane_coeffs1] +#endif usubl v10.8h, v5.8b, v1.8b ld1 {v8.8b, v9.8b}, [x12] // Load multiplication factors 1 to 8 into D3 mov v8.d[1], v9.d[0] @@ -484,10 +489,13 @@ ih264_intra_pred_chroma_8x8_mode_plane_av8: zip1 v1.8h, v0.8h, v2.8h zip2 v2.8h, v0.8h, v2.8h mov v0.16b, v1.16b - +#ifdef __APPLE__ + adrp x12, _ih264_gai1_intrapred_chroma_plane_coeffs2@GOTPAGE + ldr x12, [x12, _ih264_gai1_intrapred_chroma_plane_coeffs2@GOTPAGEOFF] +#else adrp x12, :got:ih264_gai1_intrapred_chroma_plane_coeffs2 ldr x12, [x12, #:got_lo12:ih264_gai1_intrapred_chroma_plane_coeffs2] - +#endif ld1 {v8.2s, v9.2s}, [x12] mov v8.d[1], v9.d[0] mov v10.16b, v8.16b diff --git a/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_16x16_av8.s b/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_16x16_av8.s index fa19c121..2422d8cd 100644 --- a/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_16x16_av8.s +++ b/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_16x16_av8.s @@ -431,10 +431,13 @@ ih264_intra_pred_luma_16x16_mode_plane_av8: mov x10, x1 //top_left mov x4, #-1 ld1 {v2.2s}, [x1], x8 - +#ifdef __APPLE__ + adrp x7, _ih264_gai1_intrapred_luma_plane_coeffs@GOTPAGE + ldr x7, [x7, _ih264_gai1_intrapred_luma_plane_coeffs@GOTPAGEOFF] +#else adrp x7, :got:ih264_gai1_intrapred_luma_plane_coeffs ldr x7, [x7, #:got_lo12:ih264_gai1_intrapred_luma_plane_coeffs] - +#endif ld1 {v0.2s}, [x1] rev64 v2.8b, v2.8b ld1 {v6.2s, v7.2s}, [x7] diff --git a/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_8x8_av8.s b/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_8x8_av8.s index 273aa81b..6fa31ded 100644 --- a/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_8x8_av8.s +++ b/dependencies/ih264d/common/armv8/ih264_intra_pred_luma_8x8_av8.s @@ -1029,9 +1029,13 @@ ih264_intra_pred_luma_8x8_mode_horz_u_av8: mov v3.d[0], v2.d[1] ext v4.16b, v2.16b , v2.16b , #1 mov v5.d[0], v4.d[1] - +#ifdef __APPLE__ + adrp x12, _ih264_gai1_intrapred_luma_8x8_horz_u@GOTPAGE + ldr x12, [x12, _ih264_gai1_intrapred_luma_8x8_horz_u@GOTPAGEOFF] +#else adrp x12, :got:ih264_gai1_intrapred_luma_8x8_horz_u ldr x12, [x12, #:got_lo12:ih264_gai1_intrapred_luma_8x8_horz_u] +#endif uaddl v20.8h, v0.8b, v2.8b uaddl v22.8h, v1.8b, v3.8b uaddl v24.8h, v2.8b, v4.8b diff --git a/dependencies/ih264d/common/armv8/ih264_weighted_bi_pred_av8.s b/dependencies/ih264d/common/armv8/ih264_weighted_bi_pred_av8.s index 475f690e..8d6aa995 100644 --- a/dependencies/ih264d/common/armv8/ih264_weighted_bi_pred_av8.s +++ b/dependencies/ih264d/common/armv8/ih264_weighted_bi_pred_av8.s @@ -142,14 +142,22 @@ ih264_weighted_bi_pred_luma_av8: sxtw x4, w4 sxtw x5, w5 stp x19, x20, [sp, #-16]! +#ifndef __APPLE__ ldr w8, [sp, #80] //Load wt2 in w8 ldr w9, [sp, #88] //Load ofst1 in w9 - add w6, w6, #1 //w6 = log_WD + 1 - neg w10, w6 //w10 = -(log_WD + 1) - dup v0.8h, w10 //Q0 = -(log_WD + 1) (32-bit) ldr w10, [sp, #96] //Load ofst2 in w10 ldr w11, [sp, #104] //Load ht in w11 ldr w12, [sp, #112] //Load wd in w12 +#else + ldr w8, [sp, #80] //Load wt2 in w8 + ldr w9, [sp, #84] //Load ofst1 in w9 + ldr w10, [sp, #88] //Load ofst2 in w10 + ldr w11, [sp, #92] //Load ht in w11 + ldr w12, [sp, #96] //Load wd in w12 +#endif + add w6, w6, #1 //w6 = log_WD + 1 + neg w10, w6 //w10 = -(log_WD + 1) + dup v0.8h, w10 //Q0 = -(log_WD + 1) (32-bit) add w9, w9, #1 //w9 = ofst1 + 1 add w9, w9, w10 //w9 = ofst1 + ofst2 + 1 mov v2.s[0], w7 @@ -424,17 +432,24 @@ ih264_weighted_bi_pred_chroma_av8: sxtw x5, w5 stp x19, x20, [sp, #-16]! - +#ifndef __APPLE__ ldr w8, [sp, #80] //Load wt2 in w8 + ldr w9, [sp, #88] //Load ofst1 in w9 + ldr w10, [sp, #96] //Load ofst2 in w10 + ldr w11, [sp, #104] //Load ht in w11 + ldr w12, [sp, #112] //Load wd in w12 +#else + ldr w8, [sp, #80] //Load wt2 in w8 + ldr w9, [sp, #84] //Load ofst1 in w9 + ldr w10, [sp, #88] //Load ofst2 in w10 + ldr w11, [sp, #92] //Load ht in w11 + ldr w12, [sp, #96] //Load wd in w12 +#endif dup v4.4s, w8 //Q2 = (wt2_u, wt2_v) (32-bit) dup v2.4s, w7 //Q1 = (wt1_u, wt1_v) (32-bit) add w6, w6, #1 //w6 = log_WD + 1 - ldr w9, [sp, #88] //Load ofst1 in w9 - ldr w10, [sp, #96] //Load ofst2 in w10 neg w20, w6 //w20 = -(log_WD + 1) dup v0.8h, w20 //Q0 = -(log_WD + 1) (16-bit) - ldr w11, [sp, #104] //Load ht in x11 - ldr w12, [sp, #112] //Load wd in x12 dup v20.8h, w9 //0ffset1 dup v21.8h, w10 //0ffset2 srhadd v6.8b, v20.8b, v21.8b diff --git a/dependencies/ih264d/common/armv8/macos_arm_symbol_aliases.s b/dependencies/ih264d/common/armv8/macos_arm_symbol_aliases.s new file mode 100644 index 00000000..3639f1b3 --- /dev/null +++ b/dependencies/ih264d/common/armv8/macos_arm_symbol_aliases.s @@ -0,0 +1,185 @@ +// macOS clang compilers append preceding underscores to function names, this is to prevent +// mismatches with the assembly function names and the C functions as defined in the header. + +.global _ih264_deblk_chroma_horz_bs4_av8 +_ih264_deblk_chroma_horz_bs4_av8 = ih264_deblk_chroma_horz_bs4_av8 + +.global _ih264_deblk_chroma_horz_bslt4_av8 +_ih264_deblk_chroma_horz_bslt4_av8 = ih264_deblk_chroma_horz_bslt4_av8 + +.global _ih264_deblk_chroma_vert_bs4_av8 +_ih264_deblk_chroma_vert_bs4_av8 = ih264_deblk_chroma_vert_bs4_av8 + +.global _ih264_deblk_chroma_vert_bslt4_av8 +_ih264_deblk_chroma_vert_bslt4_av8 = ih264_deblk_chroma_vert_bslt4_av8 + +.global _ih264_deblk_luma_horz_bs4_av8 +_ih264_deblk_luma_horz_bs4_av8 = ih264_deblk_luma_horz_bs4_av8 + +.global _ih264_deblk_luma_horz_bslt4_av8 +_ih264_deblk_luma_horz_bslt4_av8 = ih264_deblk_luma_horz_bslt4_av8 + +.global _ih264_deblk_luma_vert_bs4_av8 +_ih264_deblk_luma_vert_bs4_av8 = ih264_deblk_luma_vert_bs4_av8 + +.global _ih264_deblk_luma_vert_bslt4_av8 +_ih264_deblk_luma_vert_bslt4_av8 = ih264_deblk_luma_vert_bslt4_av8 + +.global _ih264_default_weighted_pred_chroma_av8 +_ih264_default_weighted_pred_chroma_av8 = ih264_default_weighted_pred_chroma_av8 + +.global _ih264_default_weighted_pred_luma_av8 +_ih264_default_weighted_pred_luma_av8 = ih264_default_weighted_pred_luma_av8 + +.global _ih264_ihadamard_scaling_4x4_av8 +_ih264_ihadamard_scaling_4x4_av8 = ih264_ihadamard_scaling_4x4_av8 + +.global _ih264_inter_pred_chroma_av8 +_ih264_inter_pred_chroma_av8 = ih264_inter_pred_chroma_av8 + +.global _ih264_inter_pred_luma_copy_av8 +_ih264_inter_pred_luma_copy_av8 = ih264_inter_pred_luma_copy_av8 + +.global _ih264_inter_pred_luma_horz_av8 +_ih264_inter_pred_luma_horz_av8 = ih264_inter_pred_luma_horz_av8 + +.global _ih264_inter_pred_luma_horz_hpel_vert_hpel_av8 +_ih264_inter_pred_luma_horz_hpel_vert_hpel_av8 = ih264_inter_pred_luma_horz_hpel_vert_hpel_av8 + +.global _ih264_inter_pred_luma_horz_hpel_vert_qpel_av8 +_ih264_inter_pred_luma_horz_hpel_vert_qpel_av8 = ih264_inter_pred_luma_horz_hpel_vert_qpel_av8 + +.global _ih264_inter_pred_luma_horz_qpel_av8 +_ih264_inter_pred_luma_horz_qpel_av8 = ih264_inter_pred_luma_horz_qpel_av8 + +.global _ih264_inter_pred_luma_horz_qpel_vert_hpel_av8 +_ih264_inter_pred_luma_horz_qpel_vert_hpel_av8 = ih264_inter_pred_luma_horz_qpel_vert_hpel_av8 + +.global _ih264_inter_pred_luma_horz_qpel_vert_qpel_av8 +_ih264_inter_pred_luma_horz_qpel_vert_qpel_av8 = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8 + +.global _ih264_inter_pred_luma_vert_av8 +_ih264_inter_pred_luma_vert_av8 = ih264_inter_pred_luma_vert_av8 + +.global _ih264_inter_pred_luma_vert_qpel_av8 +_ih264_inter_pred_luma_vert_qpel_av8 = ih264_inter_pred_luma_vert_qpel_av8 + +.global _ih264_intra_pred_chroma_8x8_mode_horz_av8 +_ih264_intra_pred_chroma_8x8_mode_horz_av8 = ih264_intra_pred_chroma_8x8_mode_horz_av8 + +.global _ih264_intra_pred_chroma_8x8_mode_plane_av8 +_ih264_intra_pred_chroma_8x8_mode_plane_av8 = ih264_intra_pred_chroma_8x8_mode_plane_av8 + +.global _ih264_intra_pred_chroma_8x8_mode_vert_av8 +_ih264_intra_pred_chroma_8x8_mode_vert_av8 = ih264_intra_pred_chroma_8x8_mode_vert_av8 + +.global _ih264_intra_pred_luma_16x16_mode_dc_av8 +_ih264_intra_pred_luma_16x16_mode_dc_av8 = ih264_intra_pred_luma_16x16_mode_dc_av8 + +.global _ih264_intra_pred_luma_16x16_mode_horz_av8 +_ih264_intra_pred_luma_16x16_mode_horz_av8 = ih264_intra_pred_luma_16x16_mode_horz_av8 + +.global _ih264_intra_pred_luma_16x16_mode_plane_av8 +_ih264_intra_pred_luma_16x16_mode_plane_av8 = ih264_intra_pred_luma_16x16_mode_plane_av8 + +.global _ih264_intra_pred_luma_16x16_mode_vert_av8 +_ih264_intra_pred_luma_16x16_mode_vert_av8 = ih264_intra_pred_luma_16x16_mode_vert_av8 + +.global _ih264_intra_pred_luma_4x4_mode_dc_av8 +_ih264_intra_pred_luma_4x4_mode_dc_av8 = ih264_intra_pred_luma_4x4_mode_dc_av8 + +.global _ih264_intra_pred_luma_4x4_mode_diag_dl_av8 +_ih264_intra_pred_luma_4x4_mode_diag_dl_av8 = ih264_intra_pred_luma_4x4_mode_diag_dl_av8 + +.global _ih264_intra_pred_luma_4x4_mode_diag_dr_av8 +_ih264_intra_pred_luma_4x4_mode_diag_dr_av8 = ih264_intra_pred_luma_4x4_mode_diag_dr_av8 + +.global _ih264_intra_pred_luma_4x4_mode_horz_av8 +_ih264_intra_pred_luma_4x4_mode_horz_av8 = ih264_intra_pred_luma_4x4_mode_horz_av8 + +.global _ih264_intra_pred_luma_4x4_mode_horz_d_av8 +_ih264_intra_pred_luma_4x4_mode_horz_d_av8 = ih264_intra_pred_luma_4x4_mode_horz_d_av8 + +.global _ih264_intra_pred_luma_4x4_mode_horz_u_av8 +_ih264_intra_pred_luma_4x4_mode_horz_u_av8 = ih264_intra_pred_luma_4x4_mode_horz_u_av8 + +.global _ih264_intra_pred_luma_4x4_mode_vert_av8 +_ih264_intra_pred_luma_4x4_mode_vert_av8 = ih264_intra_pred_luma_4x4_mode_vert_av8 + +.global _ih264_intra_pred_luma_4x4_mode_vert_l_av8 +_ih264_intra_pred_luma_4x4_mode_vert_l_av8 = ih264_intra_pred_luma_4x4_mode_vert_l_av8 + +.global _ih264_intra_pred_luma_4x4_mode_vert_r_av8 +_ih264_intra_pred_luma_4x4_mode_vert_r_av8 = ih264_intra_pred_luma_4x4_mode_vert_r_av8 + +.global _ih264_intra_pred_luma_8x8_mode_dc_av8 +_ih264_intra_pred_luma_8x8_mode_dc_av8 = ih264_intra_pred_luma_8x8_mode_dc_av8 + +.global _ih264_intra_pred_luma_8x8_mode_diag_dl_av8 +_ih264_intra_pred_luma_8x8_mode_diag_dl_av8 = ih264_intra_pred_luma_8x8_mode_diag_dl_av8 + +.global _ih264_intra_pred_luma_8x8_mode_diag_dr_av8 +_ih264_intra_pred_luma_8x8_mode_diag_dr_av8 = ih264_intra_pred_luma_8x8_mode_diag_dr_av8 + +.global _ih264_intra_pred_luma_8x8_mode_horz_av8 +_ih264_intra_pred_luma_8x8_mode_horz_av8 = ih264_intra_pred_luma_8x8_mode_horz_av8 + +.global _ih264_intra_pred_luma_8x8_mode_horz_d_av8 +_ih264_intra_pred_luma_8x8_mode_horz_d_av8 = ih264_intra_pred_luma_8x8_mode_horz_d_av8 + +.global _ih264_intra_pred_luma_8x8_mode_horz_u_av8 +_ih264_intra_pred_luma_8x8_mode_horz_u_av8 = ih264_intra_pred_luma_8x8_mode_horz_u_av8 + +.global _ih264_intra_pred_luma_8x8_mode_vert_av8 +_ih264_intra_pred_luma_8x8_mode_vert_av8 = ih264_intra_pred_luma_8x8_mode_vert_av8 + +.global _ih264_intra_pred_luma_8x8_mode_vert_l_av8 +_ih264_intra_pred_luma_8x8_mode_vert_l_av8 = ih264_intra_pred_luma_8x8_mode_vert_l_av8 + +.global _ih264_intra_pred_luma_8x8_mode_vert_r_av8 +_ih264_intra_pred_luma_8x8_mode_vert_r_av8 = ih264_intra_pred_luma_8x8_mode_vert_r_av8 + +.global _ih264_iquant_itrans_recon_4x4_av8 +_ih264_iquant_itrans_recon_4x4_av8 = ih264_iquant_itrans_recon_4x4_av8 + +.global _ih264_iquant_itrans_recon_4x4_dc_av8 +_ih264_iquant_itrans_recon_4x4_dc_av8 = ih264_iquant_itrans_recon_4x4_dc_av8 + +.global _ih264_iquant_itrans_recon_8x8_av8 +_ih264_iquant_itrans_recon_8x8_av8 = ih264_iquant_itrans_recon_8x8_av8 + +.global _ih264_iquant_itrans_recon_8x8_dc_av8 +_ih264_iquant_itrans_recon_8x8_dc_av8 = ih264_iquant_itrans_recon_8x8_dc_av8 + +.global _ih264_iquant_itrans_recon_chroma_4x4_av8 +_ih264_iquant_itrans_recon_chroma_4x4_av8 = ih264_iquant_itrans_recon_chroma_4x4_av8 + +.global _ih264_iquant_itrans_recon_chroma_4x4_dc_av8 +_ih264_iquant_itrans_recon_chroma_4x4_dc_av8 = ih264_iquant_itrans_recon_chroma_4x4_dc_av8 + +.global _ih264_pad_left_chroma_av8 +_ih264_pad_left_chroma_av8 = ih264_pad_left_chroma_av8 + +.global _ih264_pad_left_luma_av8 +_ih264_pad_left_luma_av8 = ih264_pad_left_luma_av8 + +.global _ih264_pad_right_chroma_av8 +_ih264_pad_right_chroma_av8 = ih264_pad_right_chroma_av8 + +.global _ih264_pad_right_luma_av8 +_ih264_pad_right_luma_av8 = ih264_pad_right_luma_av8 + +.global _ih264_pad_top_av8 +_ih264_pad_top_av8 = ih264_pad_top_av8 + +.global _ih264_weighted_bi_pred_chroma_av8 +_ih264_weighted_bi_pred_chroma_av8 = ih264_weighted_bi_pred_chroma_av8 + +.global _ih264_weighted_bi_pred_luma_av8 +_ih264_weighted_bi_pred_luma_av8 = ih264_weighted_bi_pred_luma_av8 + +.global _ih264_weighted_pred_chroma_av8 +_ih264_weighted_pred_chroma_av8 = ih264_weighted_pred_chroma_av8 + +.global _ih264_weighted_pred_luma_av8 +_ih264_weighted_pred_luma_av8 = ih264_weighted_pred_luma_av8 \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a9823f3..79d48947 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,13 +113,21 @@ if (MACOS_BUNDLE) endforeach(folder) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/debug/lib/libusb-1.0.0.dylib") + set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/debug/lib/libusb-1.0.0.dylib") else() - set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib") + set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/lib/libusb-1.0.0.dylib") endif() + if (EXISTS "/usr/local/lib/libMoltenVK.dylib") + set(MOLTENVK_PATH "/usr/local/lib/libMoltenVK.dylib") + elseif (EXISTS "/opt/homebrew/lib/libMoltenVK.dylib") + set(MOLTENVK_PATH "/opt/homebrew/lib/libMoltenVK.dylib") + else() + message(FATAL_ERROR "failed to find libMoltenVK.dylib") + endif () + add_custom_command (TARGET CemuBin POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy "/usr/local/lib/libMoltenVK.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib" + COMMAND ${CMAKE_COMMAND} ARGS -E copy "${MOLTENVK_PATH}" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib" COMMAND ${CMAKE_COMMAND} ARGS -E copy "${LIBUSB_PATH}" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib" COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_SOURCE_DIR}/src/resource/update.sh" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/update.sh" COMMAND bash -c "install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}" @@ -163,7 +171,3 @@ if(UNIX AND NOT APPLE) # most likely not helpful in debugging problems with cemu code target_link_options(CemuBin PRIVATE "$<$:-Xlinker;--strip-debug>") endif() - -if (ENABLE_WXWIDGETS) - target_link_libraries(CemuBin PRIVATE wx::base wx::core) -endif() diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 94ee793b..f53b93c6 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -83,7 +83,15 @@ add_library(CemuCafe HW/Espresso/Recompiler/PPCRecompilerImlGenFPU.cpp HW/Espresso/Recompiler/PPCRecompilerIml.h HW/Espresso/Recompiler/PPCRecompilerIntermediate.cpp - HW/Espresso/Recompiler/RecompilerTests.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64.h + HW/Espresso/Recompiler/BackendX64/X64Emit.hpp + HW/Espresso/Recompiler/BackendX64/x86Emitter.h HW/Latte/Common/RegisterSerializer.cpp HW/Latte/Common/RegisterSerializer.h HW/Latte/Common/ShaderSerializer.cpp @@ -525,25 +533,6 @@ add_library(CemuCafe TitleList/TitleList.h ) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") - target_sources(CemuCafe PRIVATE - HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64.h - HW/Espresso/Recompiler/BackendX64/X64Emit.hpp - HW/Espresso/Recompiler/BackendX64/x86Emitter.h - ) -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") - target_sources(CemuCafe PRIVATE - HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp - HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h - ) -endif() - if(APPLE) target_sources(CemuCafe PRIVATE "HW/Latte/Renderer/Vulkan/CocoaSurface.mm") endif() @@ -558,7 +547,7 @@ if(ANDROID) endif() endif() -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") +if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") target_sources(CemuCafe PRIVATE HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h @@ -573,7 +562,7 @@ target_include_directories(CemuCafe PUBLIC "../") if (glslang_VERSION VERSION_LESS "15.0.0") set(glslang_target "glslang::SPIRV") else() - set(glslang_target "glslang") + set(glslang_target "glslang::glslang") endif() target_link_libraries(CemuCafe PRIVATE @@ -581,6 +570,7 @@ target_link_libraries(CemuCafe PRIVATE CemuCommon CemuComponents CemuConfig + CemuGui CemuInput CemuResource CemuUtil @@ -617,10 +607,6 @@ else () target_link_libraries(CemuCafe PRIVATE libusb::libusb) endif () -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") - target_link_libraries(CemuCafe PRIVATE xbyak_aarch64) -endif() - if(WIN32) target_link_libraries(CemuCafe PRIVATE iphlpapi) endif() diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 2dee538d..9e27c22d 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -1,4 +1,5 @@ #include "Cafe/OS/common/OSCommon.h" +#include "WindowSystem.h" #include "Cafe/OS/libs/gx2/GX2.h" #include "Cafe/GameProfile/GameProfile.h" #include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h" @@ -172,7 +173,7 @@ void LoadMainExecutable() applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str()); if (!applicationRPX) { - cemuLog_log(LogType::Force, "Failed to run this title because the executable is damaged"); + WindowSystem::ShowErrorDialog(_tr("Failed to run this title because the executable is damaged")); cemuLog_createLogFile(false); cemuLog_waitForFlush(); exit(0); @@ -357,9 +358,7 @@ uint32 LoadSharedData() void cemu_initForGame() { - auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); - if (cafeSystemCallbacks) - cafeSystemCallbacks->updateWindowTitles(false, true, 0.0); + WindowSystem::UpdateWindowTitles(false, true, 0.0); // input manager apply game profile InputManager::instance().apply_game_profile(); // log info for launched title @@ -874,9 +873,7 @@ namespace CafeSystem PPCTimer_waitForInit(); // start system sSystemRunning = true; - auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); - if (cafeSystemCallbacks) - cafeSystemCallbacks->notifyGameLoaded(); + WindowSystem::NotifyGameLoaded(); std::thread t(_LaunchTitleThread); t.detach(); } diff --git a/src/Cafe/Filesystem/FST/KeyCache.cpp b/src/Cafe/Filesystem/FST/KeyCache.cpp index c69c65ca..f85d2b54 100644 --- a/src/Cafe/Filesystem/FST/KeyCache.cpp +++ b/src/Cafe/Filesystem/FST/KeyCache.cpp @@ -1,5 +1,7 @@ #include +#include "Cemu/Logging/CemuLogging.h" +#include "WindowSystem.h" #include "config/ActiveSettings.h" #include "util/crypto/aes128.h" #include "Common/FileStream.h" @@ -73,7 +75,7 @@ void KeyCache_Prepare() } else { - cemuLog_log(LogType::Force, "Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to it's own directory, the disk is full or if anti-virus software is blocking Cemu."); + WindowSystem::ShowErrorDialog(_tr("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _tr("Error"), WindowSystem::ErrorCategory::KEYS_TXT_CREATION); } mtxKeyCache.unlock(); return; @@ -106,7 +108,8 @@ void KeyCache_Prepare() continue; if( strishex(line) == false ) { - cemuLog_log(LogType::Force, "rror in keys.txt in line {}", lineNumber); + auto errorMsg = _tr("Error in keys.txt at line {}", lineNumber); + WindowSystem::ShowErrorDialog(errorMsg, WindowSystem::ErrorCategory::KEYS_TXT_CREATION); continue; } if(line.size() == 32 ) diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index f21bb89d..ab4dbd3a 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -85,7 +85,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules) auto gp = std::make_shared(rulesPath, rules); // check if enabled and preset set - const auto& config_entries = g_config.data().graphic_pack_entries; + const auto& config_entries = GetConfigHandle().data().graphic_pack_entries; // legacy absolute path checking for not breaking compatibility auto file = gp->GetRulesPath(); @@ -821,7 +821,7 @@ void GraphicPack2::AddConstantsForCurrentPreset(ExpressionParser& ep) } } -void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC) +void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC, const char* virtualMountBase) { uint64 currentTitleId = CafeSystem::GetForegroundTitleId(); uint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull; @@ -836,7 +836,7 @@ void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC } else { - virtualMountPath = fs::path("vol/content/") / virtualMountPath; + virtualMountPath = fs::path(virtualMountBase) / virtualMountPath; } fscDeviceRedirect_add(virtualMountPath.generic_string(), it.file_size(), it.path().generic_string(), m_fs_priority); } @@ -861,7 +861,7 @@ void GraphicPack2::LoadReplacedFiles() { // setup redirections fscDeviceRedirect_map(); - _iterateReplacedFiles(contentPath, false); + _iterateReplacedFiles(contentPath, false, "vol/content/"); } // /aoc/ fs::path aocPath(gfxPackPath); @@ -874,7 +874,18 @@ void GraphicPack2::LoadReplacedFiles() aocTitleId |= 0x0005000c00000000ULL; // setup redirections fscDeviceRedirect_map(); - _iterateReplacedFiles(aocPath, true); + _iterateReplacedFiles(aocPath, true, nullptr); + } + + // /code/ + fs::path codePath(gfxPackPath); + codePath.append("code"); + + if (fs::exists(codePath, ec)) + { + // setup redirections + fscDeviceRedirect_map(); + _iterateReplacedFiles(codePath, false, CafeSystem::GetInternalVirtualCodeFolder().c_str()); } } diff --git a/src/Cafe/GraphicPack/GraphicPack2.h b/src/Cafe/GraphicPack/GraphicPack2.h index 9b6a86d4..fc9603cd 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.h +++ b/src/Cafe/GraphicPack/GraphicPack2.h @@ -260,7 +260,7 @@ private: CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type) const; void ApplyShaderPresets(std::string& shader_source) const; void LoadReplacedFiles(); - void _iterateReplacedFiles(const fs::path& currentPath, bool isAOC); + void _iterateReplacedFiles(const fs::path& currentPath, bool isAOC, const char* virtualMountBase); // ram mappings std::vector> m_ramMappings; diff --git a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp index 6b6915d7..8b23fe88 100644 --- a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp @@ -1,5 +1,7 @@ #include "Cafe/GraphicPack/GraphicPack2.h" +#include "Cemu/Logging/CemuLogging.h" #include "Common/FileStream.h" +#include "WindowSystem.h" #include "util/helpers/StringParser.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/OS/RPL/rpl_structs.h" @@ -41,9 +43,9 @@ void PatchErrorHandler::showStageErrorMessageBox() if (m_gp) { if (m_stage == STAGE::PARSER) - errorMsg = fmt::format("Failed to load patches for graphic pack \'{}\'", m_gp->GetName()); + errorMsg.assign(_tr("Failed to load patches for graphic pack \'{}\'", m_gp->GetName())); else - errorMsg = fmt::format("Failed to apply patches for graphic pack \'{}\'", m_gp->GetName()); + errorMsg.assign(_tr("Failed to apply patches for graphic pack \'{}\'", m_gp->GetName())); } else { @@ -51,14 +53,17 @@ void PatchErrorHandler::showStageErrorMessageBox() } if (cemuLog_isLoggingEnabled(LogType::Patches)) { - errorMsg += "\n\nDetails:\n"; + errorMsg.append("\n \n") + .append(_tr("Details:")) + .append("\n"); for (auto& itr : errorMessages) { errorMsg += itr; errorMsg += "\n"; } } - cemuLog_log(LogType::Force, "Graphic pack error: {}", errorMsg); + + WindowSystem::ShowErrorDialog(errorMsg, _tr("Graphic pack error"), WindowSystem::ErrorCategory::GRAPHIC_PACKS); } // loads Cemu-style patches (patch_.asm) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index 900fe0ef..acb5f7cc 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -1,33 +1,23 @@ +#include "Common/precompiled.h" #include "Debugger.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cemu/ExpressionParser/ExpressionParser.h" + #include "Cafe/OS/libs/coreinit/coreinit.h" +#include "OS/RPL/rpl.h" #include "util/helpers/helpers.h" #if BOOST_OS_WINDOWS #include #endif +DebuggerDispatcher g_debuggerDispatcher; + debuggerState_t debuggerState{ }; -DebuggerCallbacks* sDebuggerCallbacks = nullptr; - -void debugger_registerDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks) -{ - sDebuggerCallbacks = debuggerCallbacks; -} -void debugger_unregisterDebuggerCallbacks() -{ - sDebuggerCallbacks = nullptr; -} -DebuggerCallbacks* debugger_getDebuggerCallbacks() -{ - return sDebuggerCallbacks; -} - DebuggerBreakpoint* debugger_getFirstBP(uint32 address) { for (auto& it : debuggerState.breakpoints) @@ -349,8 +339,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b { bp->enabled = state; debugger_updateExecutionBreakpoint(address); - if (sDebuggerCallbacks) - sDebuggerCallbacks->updateViewThreadsafe(); + g_debuggerDispatcher.UpdateViewThreadsafe(); } else if (bpItr->isMemBP()) { @@ -372,8 +361,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b debugger_updateMemoryBreakpoint(bpItr); else debugger_updateMemoryBreakpoint(nullptr); - if (sDebuggerCallbacks) - sDebuggerCallbacks->updateViewThreadsafe(); + g_debuggerDispatcher.UpdateViewThreadsafe(); } return; } @@ -509,8 +497,8 @@ void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true) PPCInterpreterSlim_executeInstruction(hCPU); debugger_updateExecutionBreakpoint(initialIP); debuggerState.debugSession.instructionPointer = hCPU->instructionPointer; - if(updateDebuggerWindow && sDebuggerCallbacks) - sDebuggerCallbacks->moveIP(); + if(updateDebuggerWindow) + g_debuggerDispatcher.MoveIP(); ppcRecompilerEnabled = isRecEnabled; } @@ -529,8 +517,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) // nothing to skip, use step-into debugger_stepInto(hCPU); debugger_updateExecutionBreakpoint(initialIP); - if (sDebuggerCallbacks) - sDebuggerCallbacks->moveIP(); + g_debuggerDispatcher.MoveIP(); ppcRecompilerEnabled = isRecEnabled; return false; } @@ -538,8 +525,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) debugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT); // step over current instruction (to avoid breakpoint) debugger_stepInto(hCPU); - if (sDebuggerCallbacks) - sDebuggerCallbacks->moveIP(); + g_debuggerDispatcher.MoveIP(); // restore breakpoints debugger_updateExecutionBreakpoint(initialIP); // run @@ -637,11 +623,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) DebuggerBreakpoint* singleshotBP = debugger_getFirstBP(debuggerState.debugSession.instructionPointer, DEBUGGER_BP_T_ONE_SHOT); if (singleshotBP) debugger_deleteBreakpoint(singleshotBP); - if (sDebuggerCallbacks) - { - sDebuggerCallbacks->notifyDebugBreakpointHit(); - sDebuggerCallbacks->updateViewThreadsafe(); - } + g_debuggerDispatcher.NotifyDebugBreakpointHit(); + g_debuggerDispatcher.UpdateViewThreadsafe(); // reset step control debuggerState.debugSession.stepInto = false; debuggerState.debugSession.stepOver = false; @@ -658,16 +641,14 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) break; // if true is returned, continue with execution } debugger_createPPCStateSnapshot(hCPU); - if (sDebuggerCallbacks) - sDebuggerCallbacks->updateViewThreadsafe(); + g_debuggerDispatcher.UpdateViewThreadsafe(); debuggerState.debugSession.stepOver = false; } if (debuggerState.debugSession.stepInto) { debugger_stepInto(hCPU); debugger_createPPCStateSnapshot(hCPU); - if (sDebuggerCallbacks) - sDebuggerCallbacks->updateViewThreadsafe(); + g_debuggerDispatcher.UpdateViewThreadsafe(); debuggerState.debugSession.stepInto = false; continue; } @@ -684,11 +665,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) debuggerState.debugSession.isTrapped = false; debuggerState.debugSession.hCPU = nullptr; - if (sDebuggerCallbacks) - { - sDebuggerCallbacks->updateViewThreadsafe(); - sDebuggerCallbacks->notifyRun(); - } + g_debuggerDispatcher.UpdateViewThreadsafe(); + g_debuggerDispatcher.NotifyRun(); } void debugger_shouldBreak(PPCInterpreter_t* hCPU) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.h b/src/Cafe/HW/Espresso/Debugger/Debugger.h index bc7f78de..eac26658 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.h +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.h @@ -15,6 +15,69 @@ #define DEBUGGER_BP_T_GDBSTUB_TW 0x7C010008 #define DEBUGGER_BP_T_DEBUGGER_TW 0x7C020008 +class DebuggerCallbacks +{ + public: + virtual void UpdateViewThreadsafe() {} + virtual void NotifyDebugBreakpointHit() {} + virtual void NotifyRun() {} + virtual void MoveIP() {} + virtual void NotifyModuleLoaded(void* module) {} + virtual void NotifyModuleUnloaded(void* module) {} + virtual ~DebuggerCallbacks() = default; +}; + +class DebuggerDispatcher +{ + private: + static inline class DefaultDebuggerCallbacks : public DebuggerCallbacks + { + } s_defaultDebuggerCallbacks; + DebuggerCallbacks* m_callbacks = &s_defaultDebuggerCallbacks; + + public: + void SetDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks) + { + cemu_assert_debug(m_callbacks == &s_defaultDebuggerCallbacks); + m_callbacks = debuggerCallbacks; + } + + void ClearDebuggerCallbacks() + { + cemu_assert_debug(m_callbacks != &s_defaultDebuggerCallbacks); + m_callbacks = &s_defaultDebuggerCallbacks; + } + + void UpdateViewThreadsafe() + { + m_callbacks->UpdateViewThreadsafe(); + } + + void NotifyDebugBreakpointHit() + { + m_callbacks->NotifyDebugBreakpointHit(); + } + + void NotifyRun() + { + m_callbacks->NotifyRun(); + } + + void MoveIP() + { + m_callbacks->MoveIP(); + } + + void NotifyModuleLoaded(void* module) + { + m_callbacks->NotifyModuleLoaded(module); + } + + void NotifyModuleUnloaded(void* module) + { + m_callbacks->NotifyModuleUnloaded(module); + } +} extern g_debuggerDispatcher; struct DebuggerBreakpoint { @@ -98,20 +161,6 @@ typedef struct extern debuggerState_t debuggerState; // new API -class DebuggerCallbacks -{ - public: - virtual void updateViewThreadsafe() = 0; - virtual void notifyDebugBreakpointHit() = 0; - virtual void notifyRun() = 0; - virtual void moveIP() = 0; - virtual void notifyModuleLoaded(void* module) = 0; - virtual void notifyModuleUnloaded(void* module) = 0; -}; - -void debugger_registerDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks); -void debugger_unregisterDebuggerCallbacks(); -DebuggerCallbacks* debugger_getDebuggerCallbacks(); DebuggerBreakpoint* debugger_getFirstBP(uint32 address); void debugger_createCodeBreakpoint(uint32 address, uint8 bpType); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp index 769344f8..2fe07509 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp @@ -41,7 +41,7 @@ static void PPCInterpreter_ADD(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDO(PPCInterpreter_t* hCPU, uint32 opcode) { - // untested (Don't Starve Giant Edition uses this instruction + BSO) + // Don't Starve Giant Edition uses this instruction + BSO PPC_OPC_TEMPL3_XO(); uint32 result = hCPU->gpr[rA] + hCPU->gpr[rB]; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(hCPU->gpr[rA], hCPU->gpr[rB], result)); @@ -113,7 +113,6 @@ static void PPCInterpreter_ADDEO(PPCInterpreter_t* hCPU, uint32 opcode) else hCPU->xer_ca = 0; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD])); - // update CR if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -130,7 +129,7 @@ static void PPCInterpreter_ADDI(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDIC(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -145,7 +144,7 @@ static void PPCInterpreter_ADDIC(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDIC_(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -155,14 +154,13 @@ static void PPCInterpreter_ADDIC_(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 flags ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); } static void PPCInterpreter_ADDIS(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_Shift16(opcode, rD, rA, imm); hCPU->gpr[rD] = (rA ? hCPU->gpr[rA] : 0) + imm; @@ -185,6 +183,23 @@ static void PPCInterpreter_ADDZE(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_ADDZEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = a + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0, hCPU->gpr[rD])); + if ((a == 0xffffffff) && ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_ADDME(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); @@ -201,6 +216,23 @@ static void PPCInterpreter_ADDME(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_ADDMEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = a + ca + 0xffffffff; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0xffffffff, hCPU->gpr[rD])); + if (a || ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_SUBF(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); @@ -260,7 +292,7 @@ static void PPCInterpreter_SUBFCO(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_SUBFIC(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -284,7 +316,6 @@ static void PPCInterpreter_SUBFE(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -304,7 +335,6 @@ static void PPCInterpreter_SUBFEO(PPCInterpreter_t* hCPU, uint32 opcode) else hCPU->xer_ca = 0; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, result)); - // update cr0 if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -326,9 +356,25 @@ static void PPCInterpreter_SUBFZE(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_SUBFZEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = ~a + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0, hCPU->gpr[rD])); + if (a == 0 && ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_SUBFME(PPCInterpreter_t* hCPU, uint32 opcode) { - // untested PPC_OPC_TEMPL3_XO(); PPC_ASSERT(rB == 0); uint32 a = hCPU->gpr[rA]; @@ -339,7 +385,24 @@ static void PPCInterpreter_SUBFME(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 + if (opcode & PPC_OPC_RC) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_SUBFMEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = ~a + 0xFFFFFFFF + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0xFFFFFFFF, hCPU->gpr[rD])); + // update xer carry + if (ppc_carry_3(~a, 0xFFFFFFFF, ca)) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; if (opcode & PPC_OPC_RC) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -352,13 +415,8 @@ static void PPCInterpreter_MULHW_(PPCInterpreter_t* hCPU, uint32 opcode) sint64 b = (sint32)hCPU->gpr[rB]; sint64 c = a * b; hCPU->gpr[rD] = ((uint64)c) >> 32; - if (opcode & PPC_OPC_RC) { - // update cr0 flags -#ifdef CEMU_DEBUG_ASSERT - assert_dbg(); -#endif + if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); - } PPCInterpreter_nextInstruction(hCPU); } @@ -409,14 +467,14 @@ static void PPCInterpreter_MULLI(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVW(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - sint32 a = hCPU->gpr[rA]; - sint32 b = hCPU->gpr[rB]; + sint32 a = (sint32)hCPU->gpr[rA]; + sint32 b = (sint32)hCPU->gpr[rB]; if (b == 0) - { - cemuLog_logDebug(LogType::Force, "Error: Division by zero! [{:08x}]", (uint32)hCPU->instructionPointer); - b++; - } - hCPU->gpr[rD] = a / b; + hCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0; + else if (a == 0x80000000 && b == 0xFFFFFFFF) + hCPU->gpr[rD] = 0xFFFFFFFF; + else + hCPU->gpr[rD] = a / b; if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -425,16 +483,23 @@ static void PPCInterpreter_DIVW(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - sint32 a = hCPU->gpr[rA]; - sint32 b = hCPU->gpr[rB]; + sint32 a = (sint32)hCPU->gpr[rA]; + sint32 b = (sint32)hCPU->gpr[rB]; if (b == 0) { PPCInterpreter_setXerOV(hCPU, true); - PPCInterpreter_nextInstruction(hCPU); - return; + hCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0; + } + else if(a == 0x80000000 && b == 0xFFFFFFFF) + { + PPCInterpreter_setXerOV(hCPU, true); + hCPU->gpr[rD] = 0xFFFFFFFF; + } + else + { + hCPU->gpr[rD] = a / b; + PPCInterpreter_setXerOV(hCPU, false); } - hCPU->gpr[rD] = a / b; - PPCInterpreter_setXerOV(hCPU, false); if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -443,12 +508,14 @@ static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWU(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - if (hCPU->gpr[rB] == 0) - { - PPCInterpreter_nextInstruction(hCPU); - return; - } - hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB]; + uint32 a = hCPU->gpr[rA]; + uint32 b = hCPU->gpr[rB]; + if (b == 0) + hCPU->gpr[rD] = 0; + else if (a == 0x80000000 && b == 0xFFFFFFFF) + hCPU->gpr[rD] = 0; + else + hCPU->gpr[rD] = a / b; if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -457,14 +524,23 @@ static void PPCInterpreter_DIVWU(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWUO(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - if (hCPU->gpr[rB] == 0) + uint32 a = hCPU->gpr[rA]; + uint32 b = hCPU->gpr[rB]; + if (b == 0) { PPCInterpreter_setXerOV(hCPU, true); - PPCInterpreter_nextInstruction(hCPU); - return; + hCPU->gpr[rD] = 0; + } + else if(a == 0x80000000 && b == 0xFFFFFFFF) + { + PPCInterpreter_setXerOV(hCPU, false); + hCPU->gpr[rD] = 0; + } + else + { + hCPU->gpr[rD] = a / b; + PPCInterpreter_setXerOV(hCPU, false); } - hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB]; - PPCInterpreter_setXerOV(hCPU, false); if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -491,6 +567,13 @@ static void PPCInterpreter_CRANDC(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_CRNAND(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL_X_CR(); + ppc_setCRBit(hCPU, crD, (ppc_getCRBit(hCPU, crA)&ppc_getCRBit(hCPU, crB)) ^ 1); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_CROR(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL_X_CR(); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHLE.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHLE.cpp index 24219e66..cf7ba195 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHLE.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHLE.cpp @@ -2,62 +2,70 @@ #include "PPCInterpreterInternal.h" #include "PPCInterpreterHelper.h" -std::unordered_set sUnsupportedHLECalls; +std::unordered_set s_unsupportedHLECalls; void PPCInterpreter_handleUnsupportedHLECall(PPCInterpreter_t* hCPU) { const char* libFuncName = (char*)memory_getPointerFromVirtualOffset(hCPU->instructionPointer + 8); std::string tempString = fmt::format("Unsupported lib call: {}", libFuncName); - if (sUnsupportedHLECalls.find(tempString) == sUnsupportedHLECalls.end()) + if (s_unsupportedHLECalls.find(tempString) == s_unsupportedHLECalls.end()) { cemuLog_log(LogType::UnsupportedAPI, "{}", tempString); - sUnsupportedHLECalls.emplace(tempString); + s_unsupportedHLECalls.emplace(tempString); } hCPU->gpr[3] = 0; PPCInterpreter_nextInstruction(hCPU); } -std::vector* sPPCHLETable{}; +static constexpr size_t HLE_TABLE_CAPACITY = 0x4000; +HLECALL s_ppcHleTable[HLE_TABLE_CAPACITY]{}; +sint32 s_ppcHleTableWriteIndex = 0; +std::mutex s_ppcHleTableMutex; HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName) { - if (!sPPCHLETable) - sPPCHLETable = new std::vector(); - for (sint32 i = 0; i < sPPCHLETable->size(); i++) + std::unique_lock _l(s_ppcHleTableMutex); + if (s_ppcHleTableWriteIndex >= HLE_TABLE_CAPACITY) { - if ((*sPPCHLETable)[i] == hleCall) - return i; + cemuLog_log(LogType::Force, "HLE table is full"); + cemu_assert(false); } - HLEIDX newFuncIndex = (sint32)sPPCHLETable->size(); - sPPCHLETable->resize(sPPCHLETable->size() + 1); - (*sPPCHLETable)[newFuncIndex] = hleCall; - return newFuncIndex; + for (sint32 i = 0; i < s_ppcHleTableWriteIndex; i++) + { + if (s_ppcHleTable[i] == hleCall) + { + return i; + } + } + cemu_assert(s_ppcHleTableWriteIndex < HLE_TABLE_CAPACITY); + s_ppcHleTable[s_ppcHleTableWriteIndex] = hleCall; + HLEIDX funcIndex = s_ppcHleTableWriteIndex; + s_ppcHleTableWriteIndex++; + return funcIndex; } HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex) { - if (funcIndex < 0 || funcIndex >= sPPCHLETable->size()) + if (funcIndex < 0 || funcIndex >= HLE_TABLE_CAPACITY) return nullptr; - return sPPCHLETable->data()[funcIndex]; + return s_ppcHleTable[funcIndex]; } -std::mutex g_hleLogMutex; +std::mutex s_hleLogMutex; void PPCInterpreter_virtualHLE(PPCInterpreter_t* hCPU, unsigned int opcode) { uint32 hleFuncId = opcode & 0xFFFF; - if (hleFuncId == 0xFFD0) + if (hleFuncId == 0xFFD0) [[unlikely]] { - g_hleLogMutex.lock(); + s_hleLogMutex.lock(); PPCInterpreter_handleUnsupportedHLECall(hCPU); - g_hleLogMutex.unlock(); - return; + s_hleLogMutex.unlock(); } else { // os lib function - cemu_assert(hleFuncId < sPPCHLETable->size()); - auto hleCall = (*sPPCHLETable)[hleFuncId]; + auto hleCall = PPCInterpreter_getHLECall(hleFuncId); cemu_assert(hleCall); hleCall(hCPU); } diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp index cacfa4a9..547472ab 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp @@ -428,9 +428,6 @@ public: } }; -uint32 testIP[100]; -uint32 testIPC = 0; - template class PPCInterpreterContainer { @@ -466,6 +463,10 @@ public: case 1: // virtual HLE PPCInterpreter_virtualHLE(hCPU, opcode); break; + case 3: + cemuLog_logDebug(LogType::Force, "Unsupported TWI instruction executed at {:08x}", hCPU->instructionPointer); + PPCInterpreter_nextInstruction(hCPU); + break; case 4: switch (PPC_getBits(opcode, 30, 5)) { @@ -482,8 +483,9 @@ public: PPCInterpreter_PS_CMPU1(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->0] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->0] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -509,8 +511,9 @@ public: PPCInterpreter_PS_ABS(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->8] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->8] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -548,8 +551,9 @@ public: PPCInterpreter_PS_MERGE11(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->16] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); - debugBreakpoint(); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->16] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -590,8 +594,9 @@ public: PPCInterpreter_PS_NMADD(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4] at %08X\n", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4] at {:08x}", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -623,12 +628,15 @@ public: PPCInterpreter_BCX(hCPU, opcode); break; case 17: - if (PPC_getBits(opcode, 30, 1) == 1) { + if (PPC_getBits(opcode, 30, 1) == 1) + { PPCInterpreter_SC(hCPU, opcode); } - else { - debug_printf("Unsupported Opcode [0x17 --> 0x0]\n"); + else + { + cemuLog_logDebug(LogType::Force, "Unsupported Opcode [0x17 --> 0x0]"); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; } break; case 18: @@ -658,6 +666,9 @@ public: case 193: PPCInterpreter_CRXOR(hCPU, opcode); break; + case 225: + PPCInterpreter_CRNAND(hCPU, opcode); + break; case 257: PPCInterpreter_CRAND(hCPU, opcode); break; @@ -674,8 +685,9 @@ public: PPCInterpreter_BCCTR(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [19] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [19] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -713,9 +725,6 @@ public: PPCInterpreter_CMP(hCPU, opcode); break; case 4: - #ifdef CEMU_DEBUG_ASSERT - debug_printf("TW instruction executed at %08x\n", hCPU->instructionPointer); - #endif PPCInterpreter_TW(hCPU, opcode); break; case 8: @@ -895,6 +904,12 @@ public: case 522: PPCInterpreter_ADDCO(hCPU, opcode); break; + case 523: // 11 | OE + PPCInterpreter_MULHWU_(hCPU, opcode); // OE is ignored + break; + case 533: + PPCInterpreter_LSWX(hCPU, opcode); + break; case 534: PPCInterpreter_LWBRX(hCPU, opcode); break; @@ -913,6 +928,9 @@ public: case 567: PPCInterpreter_LFSUX(hCPU, opcode); break; + case 587: // 75 | OE + PPCInterpreter_MULHW_(hCPU, opcode); // OE is ignored for MULHW + break; case 595: PPCInterpreter_MFSR(hCPU, opcode); break; @@ -943,15 +961,30 @@ public: case 663: PPCInterpreter_STFSX(hCPU, opcode); break; + case 661: + PPCInterpreter_STSWX(hCPU, opcode); + break; case 695: PPCInterpreter_STFSUX(hCPU, opcode); break; + case 712: // 200 | OE + PPCInterpreter_SUBFZEO(hCPU, opcode); + break; + case 714: // 202 | OE + PPCInterpreter_ADDZEO(hCPU, opcode); + break; case 725: PPCInterpreter_STSWI(hCPU, opcode); break; case 727: PPCInterpreter_STFDX(hCPU, opcode); break; + case 744: // 232 | OE + PPCInterpreter_SUBFMEO(hCPU, opcode); + break; + case 746: // 234 | OE + PPCInterpreter_ADDMEO(hCPU, opcode); + break; case 747: PPCInterpreter_MULLWO(hCPU, opcode); break; @@ -998,10 +1031,8 @@ public: PPCInterpreter_DCBZ(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [31] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); - #ifdef CEMU_DEBUG_ASSERT - assert_dbg(); - #endif + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [31] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemu_assert_unimplemented(); hCPU->instructionPointer += 4; break; } @@ -1084,7 +1115,7 @@ public: case 57: PPCInterpreter_PSQ_LU(hCPU, opcode); break; - case 59: //Opcode category + case 59: // opcode category switch (PPC_getBits(opcode, 30, 5)) { case 18: @@ -1115,8 +1146,9 @@ public: PPCInterpreter_FNMADDS(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [59] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [59] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -1195,18 +1227,19 @@ public: case 583: PPCInterpreter_MFFS(hCPU, opcode); break; - case 711: // IBM documentation has this wrong as 771? + case 711: PPCInterpreter_MTFSF(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [63] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [63] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + PPCInterpreter_nextInstruction(hCPU); break; } } break; default: - debug_printf("Unknown execute %04X at %08X\n", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} at {:08x}\n", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer); cemu_assert_unimplemented(); } } diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp index 26467458..ea7bb038 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp @@ -31,7 +31,7 @@ static void PPCInterpreter_STW(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU32(hCPU, hCPU->gpr[rA] + imm, hCPU->gpr[rS]); @@ -42,7 +42,7 @@ static void PPCInterpreter_STWU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -103,7 +103,7 @@ static void PPCInterpreter_STWCX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]); if (rA) @@ -113,7 +113,7 @@ static void PPCInterpreter_STWUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWBRX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU32(hCPU->gpr[rS])); PPCInterpreter_nextInstruction(hCPU); @@ -121,7 +121,7 @@ static void PPCInterpreter_STWBRX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STMW(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rS, rA; + sint32 rS, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); uint32 ea = (rA ? hCPU->gpr[rA] : 0) + imm; @@ -136,7 +136,7 @@ static void PPCInterpreter_STMW(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STH(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]); @@ -145,7 +145,7 @@ static void PPCInterpreter_STH(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]); @@ -156,7 +156,7 @@ static void PPCInterpreter_STHU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -164,7 +164,7 @@ static void PPCInterpreter_STHX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]); if (rA) @@ -174,7 +174,7 @@ static void PPCInterpreter_STHUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHBRX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU16((uint16)hCPU->gpr[rS])); PPCInterpreter_nextInstruction(hCPU); @@ -182,7 +182,7 @@ static void PPCInterpreter_STHBRX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STB(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint8)hCPU->gpr[rS]); @@ -191,7 +191,7 @@ static void PPCInterpreter_STB(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU8(hCPU, hCPU->gpr[rA] + imm, (uint8)hCPU->gpr[rS]); @@ -201,7 +201,7 @@ static void PPCInterpreter_STBU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -209,7 +209,7 @@ static void PPCInterpreter_STBX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]); if (rA) @@ -219,7 +219,7 @@ static void PPCInterpreter_STBUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STSWI(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, nb; + sint32 rA, rS, nb; PPC_OPC_TEMPL_X(Opcode, rS, rA, nb); if (nb == 0) nb = 32; uint32 ea = rA ? hCPU->gpr[rA] : 0; @@ -229,7 +229,39 @@ static void PPCInterpreter_STSWI(PPCInterpreter_t* hCPU, uint32 Opcode) { if (i == 0) { - r = hCPU->gpr[rS]; + r = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds? + rS++; + rS %= 32; + i = 4; + } + ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, (r >> 24)); + r <<= 8; + ea++; + i--; + nb--; + } + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_STSWX(PPCInterpreter_t* hCPU, uint32 Opcode) +{ + sint32 rA, rS, rB; + PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); + sint32 nb = hCPU->spr.XER&0x7F; + if (nb == 0) + { + PPCInterpreter_nextInstruction(hCPU); + return; + } + uint32 ea = rA ? hCPU->gpr[rA] : 0; + ea += hCPU->gpr[rB]; + uint32 r = 0; + int i = 0; + while (nb > 0) + { + if (i == 0) + { + r = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds? rS++; rS %= 32; i = 4; @@ -460,7 +492,6 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) PPC_OPC_TEMPL_X(Opcode, rD, rA, nb); if (nb == 0) nb = 32; - uint32 ea = rA ? hCPU->gpr[rA] : 0; uint32 r = 0; int i = 4; @@ -470,7 +501,8 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) if (i == 0) { i = 4; - hCPU->gpr[rD] = r; + if(rD < 32) + hCPU->gpr[rD] = r; rD++; rD %= 32; r = 0; @@ -487,7 +519,52 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) r <<= 8; i--; } - hCPU->gpr[rD] = r; + if(rD < 32) + hCPU->gpr[rD] = r; + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_LSWX(PPCInterpreter_t* hCPU, uint32 Opcode) +{ + sint32 rA, rD, rB; + PPC_OPC_TEMPL_X(Opcode, rD, rA, rB); + // byte count comes from XER + uint32 nb = (hCPU->spr.XER>>0)&0x7F; + if (nb == 0) + { + PPCInterpreter_nextInstruction(hCPU); + return; // no-op + } + uint32 ea = rA ? hCPU->gpr[rA] : 0; + ea += hCPU->gpr[rB]; + uint32 r = 0; + int i = 4; + uint8 v; + while (nb>0) + { + if (i == 0) + { + i = 4; + if(rD < 32) + hCPU->gpr[rD] = r; + rD++; + rD %= 32; + r = 0; + } + v = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea); + r <<= 8; + r |= v; + ea++; + i--; + nb--; + } + while (i) + { + r <<= 8; + i--; + } + if(rD < 32) + hCPU->gpr[rD] = r; PPCInterpreter_nextInstruction(hCPU); } diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp index 08d6765a..4449f135 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp @@ -77,7 +77,8 @@ uint32 PPCInterpreter_getXER(PPCInterpreter_t* hCPU) void PPCInterpreter_setXER(PPCInterpreter_t* hCPU, uint32 v) { - hCPU->spr.XER = v; + const uint32 XER_MASK = 0xE0FFFFFF; // some bits are masked out. Figure out which ones exactly + hCPU->spr.XER = v & XER_MASK; hCPU->xer_ca = (v >> XER_BIT_CA) & 1; hCPU->xer_so = (v >> XER_BIT_SO) & 1; hCPU->xer_ov = (v >> XER_BIT_OV) & 1; diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp index d6b643ee..7809a01d 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp @@ -93,7 +93,6 @@ void PPCInterpreter_MTCRF(PPCInterpreter_t* hCPU, uint32 Opcode) { // frequently used by GCC compiled code (e.g. SM64 port) // tested - uint32 rS; uint32 crfMask; PPC_OPC_TEMPL_XFX(Opcode, rS, crfMask); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp index 718162be..9bfcd53d 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp @@ -68,6 +68,8 @@ static void PPCInterpreter_TW(PPCInterpreter_t* hCPU, uint32 opcode) PPC_OPC_TEMPL_X(opcode, to, rA, rB); cemu_assert_debug(to == 0); + if(to != 0) + PPCInterpreter_nextInstruction(hCPU); if (rA == DEBUGGER_BP_T_DEBUGGER) debugger_enterTW(hCPU); diff --git a/src/Cafe/HW/Espresso/PPCState.h b/src/Cafe/HW/Espresso/PPCState.h index 179e2687..fd943d39 100644 --- a/src/Cafe/HW/Espresso/PPCState.h +++ b/src/Cafe/HW/Espresso/PPCState.h @@ -230,9 +230,9 @@ static inline float flushDenormalToZero(float f) // HLE interface -typedef void(*HLECALL)(PPCInterpreter_t* hCPU); +using HLECALL = void(*)(PPCInterpreter_t*); +using HLEIDX = sint32; -typedef sint32 HLEIDX; HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName); HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex); diff --git a/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp b/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp index 6f62572c..ccefd3f5 100644 --- a/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp @@ -174,8 +174,10 @@ struct AArch64GenContext_t : CodeGenerator bool processAllJumps() { - for (auto&& [jumpStart, jumpInfo] : jumps) + for (auto jump : jumps) { + auto jumpStart = jump.first; + auto jumpInfo = jump.second; bool success = std::visit( [&, this](const auto& jump) { setSize(jumpStart); diff --git a/src/Cafe/HW/Latte/Core/Latte.h b/src/Cafe/HW/Latte/Core/Latte.h index e5e9dd5c..2636467b 100644 --- a/src/Cafe/HW/Latte/Core/Latte.h +++ b/src/Cafe/HW/Latte/Core/Latte.h @@ -47,8 +47,6 @@ struct LatteGPUState_t gx2GPUSharedArea_t* sharedArea; // quick reference to shared area MPTR sharedAreaAddr; // other - // todo: Currently we have the command buffer logic implemented as a FIFO ringbuffer. On real HW it's handled as a series of command buffers that are pushed individually. - std::atomic lastSubmittedCommandBufferTimestamp; uint32 gx2InitCalled; // incremented every time GX2Init() is called // OpenGL control uint32 glVendor; // GLVENDOR_* @@ -75,8 +73,6 @@ struct LatteGPUState_t extern LatteGPUState_t LatteGPUState; -extern uint8* gxRingBufferReadPtr; // currently active read pointer (gx2 ring buffer or display list) - // texture #include "Cafe/HW/Latte/Core/LatteTexture.h" diff --git a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp index f592cc9e..4385cf49 100644 --- a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp +++ b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp @@ -13,6 +13,7 @@ #include "Cafe/HW/Latte/Core/LattePM4.h" #include "Cafe/OS/libs/coreinit/coreinit_Time.h" +#include "Cafe/OS/libs/TCL/TCL.h" // TCL currently handles the GPU command ringbuffer #include "Cafe/CafeSystem.h" @@ -28,11 +29,6 @@ typedef uint32be* LatteCMDPtr; #define LatteReadCMD() ((uint32)*(cmd++)) #define LatteSkipCMD(_nWords) cmd += (_nWords) -uint8* gxRingBufferReadPtr; // currently active read pointer (gx2 ring buffer or display list) -uint8* gx2CPParserDisplayListPtr; -uint8* gx2CPParserDisplayListStart; // used for debugging -uint8* gx2CPParserDisplayListEnd; - void LatteThread_HandleOSScreen(); void LatteThread_Exit(); @@ -155,16 +151,12 @@ void LatteCP_signalEnterWait() */ uint32 LatteCP_readU32Deprc() { - uint32 v; - uint8* gxRingBufferWritePtr; - sint32 readDistance; // no display list active while (true) { - gxRingBufferWritePtr = gx2WriteGatherPipe.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex]; - readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr); - if (readDistance != 0) - break; + uint32 cmdWord; + if ( TCL::TCLGPUReadRBWord(cmdWord) ) + return cmdWord; g_renderer->NotifyLatteCommandProcessorIdle(); // let the renderer know in case it wants to flush any commands performanceMonitor.gpuTime_idleTime.beginMeasuring(); @@ -175,56 +167,8 @@ uint32 LatteCP_readU32Deprc() } LatteThread_HandleOSScreen(); // check if new frame was presented via OSScreen API - readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr); - if (readDistance != 0) - break; - if (Latte_GetStopSignal()) - LatteThread_Exit(); - - // still no command data available, do some other tasks - LatteTiming_HandleTimedVsync(); - LatteAsyncCommands_checkAndExecute(); - std::this_thread::yield(); - performanceMonitor.gpuTime_idleTime.endMeasuring(); - } - v = *(uint32*)gxRingBufferReadPtr; - gxRingBufferReadPtr += 4; -#ifdef CEMU_DEBUG_ASSERT - if (v == 0xcdcdcdcd) - assert_dbg(); -#endif - v = _swapEndianU32(v); - return v; -} - -void LatteCP_waitForNWords(uint32 numWords) -{ - uint8* gxRingBufferWritePtr; - sint32 readDistance; - bool isFlushed = false; - sint32 waitDistance = numWords * sizeof(uint32be); - // no display list active - while (true) - { - gxRingBufferWritePtr = gx2WriteGatherPipe.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex]; - readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr); - if (readDistance < 0) - return; // wrap around means there is at least one full command queued after this - if (readDistance >= waitDistance) - break; - g_renderer->NotifyLatteCommandProcessorIdle(); // let the renderer know in case it wants to flush any commands - performanceMonitor.gpuTime_idleTime.beginMeasuring(); - // no command data available, spin in a busy loop for a while then check again - for (sint32 busy = 0; busy < 80; busy++) - { - _mm_pause(); - } - readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr); - if (readDistance < 0) - return; // wrap around means there is at least one full command queued after this - if (readDistance >= waitDistance) - break; - + if ( TCL::TCLGPUReadRBWord(cmdWord) ) + return cmdWord; if (Latte_GetStopSignal()) LatteThread_Exit(); @@ -234,6 +178,7 @@ void LatteCP_waitForNWords(uint32 numWords) std::this_thread::yield(); performanceMonitor.gpuTime_idleTime.endMeasuring(); } + UNREACHABLE; } template @@ -270,21 +215,23 @@ void LatteCP_itIndirectBufferDepr(LatteCMDPtr cmd, uint32 nWords) cemu_assert_debug(nWords == 3); uint32 physicalAddress = LatteReadCMD(); uint32 physicalAddressHigh = LatteReadCMD(); // unused - uint32 sizeInDWords = LatteReadCMD(); - uint32 displayListSize = sizeInDWords * 4; - DrawPassContext drawPassCtx; + uint32 sizeInU32s = LatteReadCMD(); #ifdef LATTE_CP_LOGGING if (GetAsyncKeyState('A')) LatteCP_DebugPrintCmdBuffer(MEMPTR(physicalAddress), displayListSize); #endif - uint32be* buf = MEMPTR(physicalAddress).GetPtr(); - drawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInDWords); + if (sizeInU32s > 0) + { + DrawPassContext drawPassCtx; + uint32be* buf = MEMPTR(physicalAddress).GetPtr(); + drawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInU32s); - LatteCP_processCommandBuffer(drawPassCtx); - if (drawPassCtx.isWithinDrawPass()) - drawPassCtx.endDrawPass(); + LatteCP_processCommandBuffer(drawPassCtx); + if (drawPassCtx.isWithinDrawPass()) + drawPassCtx.endDrawPass(); + } } // pushes the command buffer to the stack @@ -294,11 +241,12 @@ void LatteCP_itIndirectBuffer(LatteCMDPtr cmd, uint32 nWords, DrawPassContext& d uint32 physicalAddress = LatteReadCMD(); uint32 physicalAddressHigh = LatteReadCMD(); // unused uint32 sizeInDWords = LatteReadCMD(); - uint32 displayListSize = sizeInDWords * 4; - cemu_assert_debug(displayListSize >= 4); - - uint32be* buf = MEMPTR(physicalAddress).GetPtr(); - drawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInDWords); + if (sizeInDWords > 0) + { + uint32 displayListSize = sizeInDWords * 4; + uint32be* buf = MEMPTR(physicalAddress).GetPtr(); + drawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInDWords); + } } LatteCMDPtr LatteCP_itStreamoutBufferUpdate(LatteCMDPtr cmd, uint32 nWords) @@ -565,26 +513,55 @@ LatteCMDPtr LatteCP_itMemWrite(LatteCMDPtr cmd, uint32 nWords) if (word1 == 0x40000) { // write U32 - *memPtr = word2; + stdx::atomic_ref atomicRef(*memPtr); + atomicRef.store(word2); } else if (word1 == 0x00000) { - // write U64 (as two U32) - // note: The U32s are swapped - memPtr[0] = word2; - memPtr[1] = word3; + // write U64 + // note: The U32s are swapped here, but needs verification. Also, it seems like the two U32 halves are written independently and the U64 as a whole is not atomic -> investiagte + stdx::atomic_ref atomicRef(*(uint64be*)memPtr); + atomicRef.store(((uint64le)word2 << 32) | word3); } else if (word1 == 0x20000) { // write U64 (little endian) - memPtr[0] = _swapEndianU32(word2); - memPtr[1] = _swapEndianU32(word3); + stdx::atomic_ref atomicRef(*(uint64le*)memPtr); + atomicRef.store(((uint64le)word3 << 32) | word2); } else cemu_assert_unimplemented(); return cmd; } +LatteCMDPtr LatteCP_itEventWriteEOP(LatteCMDPtr cmd, uint32 nWords) +{ + cemu_assert_debug(nWords == 5); + uint32 word0 = LatteReadCMD(); + uint32 word1 = LatteReadCMD(); + uint32 word2 = LatteReadCMD(); + uint32 word3 = LatteReadCMD(); // value low bits + uint32 word4 = LatteReadCMD(); // value high bits + + cemu_assert_debug(word2 == 0x40000000 || word2 == 0x42000000); + + if (word0 == 0x504 && (word2&0x40000000)) // todo - figure out the flags + { + stdx::atomic_ref atomicRef(*(uint64be*)memory_getPointerFromPhysicalOffset(word1)); + uint64 val = ((uint64)word4 << 32) | word3; + atomicRef.store(val); + } + else + { cemu_assert_unimplemented(); + } + bool triggerInterrupt = (word2 & 0x2000000) != 0; + if (triggerInterrupt) + { + // todo - timestamp interrupt + } + TCL::TCLGPUNotifyNewRetirementTimestamp(); + return cmd; +} LatteCMDPtr LatteCP_itMemSemaphore(LatteCMDPtr cmd, uint32 nWords) { @@ -783,16 +760,6 @@ LatteCMDPtr LatteCP_itDrawImmediate(LatteCMDPtr cmd, uint32 nWords, DrawPassCont drawPassCtx.executeDraw(count, false, _tempIndexArrayMPTR); return cmd; - -} - -LatteCMDPtr LatteCP_itHLEFifoWrapAround(LatteCMDPtr cmd, uint32 nWords) -{ - cemu_assert_debug(nWords == 1); - uint32 unused = LatteReadCMD(); - gxRingBufferReadPtr = gx2WriteGatherPipe.gxRingBuffer; - cmd = (LatteCMDPtr)gxRingBufferReadPtr; - return cmd; } LatteCMDPtr LatteCP_itHLESampleTimer(LatteCMDPtr cmd, uint32 nWords) @@ -819,16 +786,6 @@ LatteCMDPtr LatteCP_itHLESpecialState(LatteCMDPtr cmd, uint32 nWords) return cmd; } -LatteCMDPtr LatteCP_itHLESetRetirementTimestamp(LatteCMDPtr cmd, uint32 nWords) -{ - cemu_assert_debug(nWords == 2); - uint32 timestampHigh = (uint32)LatteReadCMD(); - uint32 timestampLow = (uint32)LatteReadCMD(); - uint64 timestamp = ((uint64)timestampHigh << 32ULL) | (uint64)timestampLow; - GX2::__GX2NotifyNewRetirementTimestamp(timestamp); - return cmd; -} - LatteCMDPtr LatteCP_itHLEBeginOcclusionQuery(LatteCMDPtr cmd, uint32 nWords) { cemu_assert_debug(nWords == 1); @@ -1145,9 +1102,10 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx) LatteCMDPtr cmd, cmdStart, cmdEnd; if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) break; + uint32 itHeader; while (cmd < cmdEnd) { - uint32 itHeader = LatteReadCMD(); + itHeader = LatteReadCMD(); uint32 itHeaderType = (itHeader >> 30) & 3; if (itHeaderType == 3) { @@ -1361,11 +1319,6 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx) LatteCP_itHLEEndOcclusionQuery(cmdData, nWords); break; } - case IT_HLE_SET_CB_RETIREMENT_TIMESTAMP: - { - LatteCP_itHLESetRetirementTimestamp(cmdData, nWords); - break; - } case IT_HLE_BOTTOM_OF_PIPE_CB: { LatteCP_itHLEBottomOfPipeCB(cmdData, nWords); @@ -1421,6 +1374,7 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx) void LatteCP_ProcessRingbuffer() { sint32 timerRecheck = 0; // estimates how much CP processing time has elapsed based on the executed commands, if the value exceeds CP_TIMER_RECHECK then _handleTimers() is called + uint32be tmpBuffer[128]; while (true) { uint32 itHeader = LatteCP_readU32Deprc(); @@ -1429,10 +1383,13 @@ void LatteCP_ProcessRingbuffer() { uint32 itCode = (itHeader >> 8) & 0xFF; uint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1; - LatteCP_waitForNWords(nWords); - LatteCMDPtr cmd = (LatteCMDPtr)gxRingBufferReadPtr; - uint8* cmdEnd = gxRingBufferReadPtr + nWords * 4; - gxRingBufferReadPtr = cmdEnd; + cemu_assert(nWords < 128); + for (sint32 i=0; i +#elif defined(__aarch64__) +#include #endif struct @@ -502,6 +504,114 @@ void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDat indexMax = std::max(indexMax, _maxIndex); indexMin = std::min(indexMin, _minIndex); } +#elif defined(__aarch64__) + +void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) +{ + const uint16* indicesU16BE = (const uint16*)indexDataInput; + uint16* indexOutput = (uint16*)indexDataOutput; + sint32 count8 = count >> 3; + sint32 countRemaining = count & 7; + + if (count8) + { + uint16x8_t mMin = vdupq_n_u16(0xFFFF); + uint16x8_t mMax = vdupq_n_u16(0x0000); + uint16x8_t mTemp; + uint16x8_t* mRawIndices = (uint16x8_t*) indicesU16BE; + indicesU16BE += count8 * 8; + uint16x8_t* mOutputIndices = (uint16x8_t*) indexOutput; + indexOutput += count8 * 8; + + while (count8--) + { + mTemp = vld1q_u16((uint16*)mRawIndices); + mRawIndices++; + mTemp = vrev16q_u8(mTemp); + mMin = vminq_u16(mMin, mTemp); + mMax = vmaxq_u16(mMax, mTemp); + vst1q_u16((uint16*)mOutputIndices, mTemp); + mOutputIndices++; + } + + uint16* mMaxU16 = (uint16*)&mMax; + uint16* mMinU16 = (uint16*)&mMin; + + for (int i = 0; i < 8; ++i) { + indexMax = std::max(indexMax, (uint32)mMaxU16[i]); + indexMin = std::min(indexMin, (uint32)mMinU16[i]); + } + } + // process remaining indices + uint32 _minIndex = 0xFFFFFFFF; + uint32 _maxIndex = 0; + for (sint32 i = countRemaining; (--i) >= 0;) + { + uint16 idx = _swapEndianU16(*indicesU16BE); + *indexOutput = idx; + indexOutput++; + indicesU16BE++; + _maxIndex = std::max(_maxIndex, (uint32)idx); + _minIndex = std::min(_minIndex, (uint32)idx); + } + // update min/max + indexMax = std::max(indexMax, _maxIndex); + indexMin = std::min(indexMin, _minIndex); +} + +void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) +{ + const uint32* indicesU32BE = (const uint32*)indexDataInput; + uint32* indexOutput = (uint32*)indexDataOutput; + sint32 count8 = count >> 2; + sint32 countRemaining = count & 3; + + if (count8) + { + uint32x4_t mMin = vdupq_n_u32(0xFFFFFFFF); + uint32x4_t mMax = vdupq_n_u32(0x00000000); + uint32x4_t mTemp; + uint32x4_t* mRawIndices = (uint32x4_t*) indicesU32BE; + indicesU32BE += count8 * 4; + uint32x4_t* mOutputIndices = (uint32x4_t*) indexOutput; + indexOutput += count8 * 4; + + while (count8--) + { + mTemp = vld1q_u32((uint32*)mRawIndices); + mRawIndices++; + mTemp = vrev32q_u8(mTemp); + mMin = vminq_u32(mMin, mTemp); + mMax = vmaxq_u32(mMax, mTemp); + vst1q_u32((uint32*)mOutputIndices, mTemp); + mOutputIndices++; + } + + uint32* mMaxU32 = (uint32*)&mMax; + uint32* mMinU32 = (uint32*)&mMin; + + for (int i = 0; i < 4; ++i) { + indexMax = std::max(indexMax, mMaxU32[i]); + indexMin = std::min(indexMin, mMinU32[i]); + } + } + // process remaining indices + uint32 _minIndex = 0xFFFFFFFF; + uint32 _maxIndex = 0; + for (sint32 i = countRemaining; (--i) >= 0;) + { + uint32 idx = _swapEndianU32(*indicesU32BE); + *indexOutput = idx; + indexOutput++; + indicesU32BE++; + _maxIndex = std::max(_maxIndex, idx); + _minIndex = std::min(_minIndex, idx); + } + // update min/max + indexMax = std::max(indexMax, _maxIndex); + indexMin = std::min(indexMin, _minIndex); +} + #endif template @@ -688,27 +798,31 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 { if (indexType == LatteIndexType::U16_BE) { - #if defined(ARCH_X86_64) +#if defined(ARCH_X86_64) if (g_CPUFeatures.x86.avx2) LatteIndices_fastConvertU16_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax); else if (g_CPUFeatures.x86.sse4_1 && g_CPUFeatures.x86.ssse3) LatteIndices_fastConvertU16_SSE41(indexData, indexOutputPtr, count, indexMin, indexMax); else LatteIndices_convertBE(indexData, indexOutputPtr, count, indexMin, indexMax); - #else +#elif defined(__aarch64__) + LatteIndices_fastConvertU16_NEON(indexData, indexOutputPtr, count, indexMin, indexMax); +#else LatteIndices_convertBE(indexData, indexOutputPtr, count, indexMin, indexMax); - #endif +#endif } else if (indexType == LatteIndexType::U32_BE) { - #if defined(ARCH_X86_64) +#if defined(ARCH_X86_64) if (g_CPUFeatures.x86.avx2) LatteIndices_fastConvertU32_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax); else LatteIndices_convertBE(indexData, indexOutputPtr, count, indexMin, indexMax); - #else +#elif defined(__aarch64__) + LatteIndices_fastConvertU32_NEON(indexData, indexOutputPtr, count, indexMin, indexMax); +#else LatteIndices_convertBE(indexData, indexOutputPtr, count, indexMin, indexMax); - #endif +#endif } else if (indexType == LatteIndexType::U16_LE) { diff --git a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp index 19c9ecbd..7499d743 100644 --- a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp +++ b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp @@ -1,5 +1,6 @@ #include "Cafe/HW/Latte/Core/LatteOverlay.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" +#include "WindowSystem.h" #include "config/CemuConfig.h" @@ -13,8 +14,6 @@ #include "input/InputManager.h" #include "util/SystemInfo/SystemInfo.h" -#include "Cemu/GuiSystem/GuiSystem.h" - #include struct OverlayStats @@ -520,17 +519,17 @@ void LatteOverlay_render(bool pad_view) return; sint32 w = 0, h = 0; - if (pad_view && GuiSystem::isPadWindowOpen()) - GuiSystem::getPadWindowPhysSize(w, h); + if (pad_view && WindowSystem::IsPadWindowOpen()) + WindowSystem::GetPadWindowPhysSize(w, h); else - GuiSystem::getWindowPhysSize(w, h); + WindowSystem::GetWindowPhysSize(w, h); if (w == 0 || h == 0) return; const Vector2f window_size{ (float)w,(float)h }; - float fontDPIScale = !pad_view ? GuiSystem::getWindowDPIScale() : GuiSystem::getPadDPIScale(); + float fontDPIScale = !pad_view ? WindowSystem::GetWindowDPIScale() : WindowSystem::GetPadDPIScale(); float overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale; diff --git a/src/Cafe/HW/Latte/Core/LattePM4.h b/src/Cafe/HW/Latte/Core/LattePM4.h index 8079a89c..1f5d2129 100644 --- a/src/Cafe/HW/Latte/Core/LattePM4.h +++ b/src/Cafe/HW/Latte/Core/LattePM4.h @@ -14,6 +14,7 @@ #define IT_MEM_WRITE 0x3D #define IT_SURFACE_SYNC 0x43 #define IT_EVENT_WRITE 0x46 +#define IT_EVENT_WRITE_EOP 0x47 // end of pipe #define IT_LOAD_CONFIG_REG 0x60 #define IT_LOAD_CONTEXT_REG 0x61 @@ -47,14 +48,12 @@ #define IT_HLE_WAIT_FOR_FLIP 0xF1 #define IT_HLE_BOTTOM_OF_PIPE_CB 0xF2 #define IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER 0xF3 -#define IT_HLE_FIFO_WRAP_AROUND 0xF4 #define IT_HLE_CLEAR_COLOR_DEPTH_STENCIL 0xF5 #define IT_HLE_SAMPLE_TIMER 0xF7 #define IT_HLE_TRIGGER_SCANBUFFER_SWAP 0xF8 #define IT_HLE_SPECIAL_STATE 0xF9 #define IT_HLE_BEGIN_OCCLUSION_QUERY 0xFA #define IT_HLE_END_OCCLUSION_QUERY 0xFB -#define IT_HLE_SET_CB_RETIREMENT_TIMESTAMP 0xFD #define pm4HeaderType3(__itCode, __dataDWordCount) (0xC0000000|((uint32)(__itCode)<<8)|((uint32)((__dataDWordCount)-1)<<16)) #define pm4HeaderType2Filler() (0x80000000) diff --git a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp index aca7c3fd..a3bcb63e 100644 --- a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp +++ b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp @@ -1,6 +1,6 @@ #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" -#include "Cafe/CafeSystem.h" +#include "WindowSystem.h" performanceMonitor_t performanceMonitor{}; @@ -103,18 +103,15 @@ void LattePerformanceMonitor_frameEnd() // next update in 1 second performanceMonitor.cycle[performanceMonitor.cycleIndex].lastUpdate = GetTickCount(); - auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); if (isFirstUpdate) { LatteOverlay_updateStats(0.0, 0, 0); - if (cafeSystemCallbacks) - cafeSystemCallbacks->updateWindowTitles(false, false, 0.0); + WindowSystem::UpdateWindowTitles(false, false, 0.0); } else { LatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames, fastDrawCallCounter / elapsedFrames); - if (cafeSystemCallbacks) - cafeSystemCallbacks->updateWindowTitles(false, false, fps); + WindowSystem::UpdateWindowTitles(false, false, fps); } } } diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 66e8d4f8..dd4fdd17 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -11,8 +11,7 @@ #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/ActiveSettings.h" -#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h" -#include "Cemu/GuiSystem/GuiSystem.h" +#include "WindowSystem.h" #include "Cafe/OS/libs/erreula/erreula.h" #include "input/InputManager.h" #include "Cafe/OS/libs/swkbd/swkbd.h" @@ -839,10 +838,10 @@ sint32 _currentOutputImageHeight = 0; void LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView) { int w, h; - if(padView && GuiSystem::isPadWindowOpen()) - GuiSystem::getPadWindowPhysSize(w, h); + if(padView && WindowSystem::IsPadWindowOpen()) + WindowSystem::GetPadWindowPhysSize(w, h); else - GuiSystem::getWindowPhysSize(w, h); + WindowSystem::GetWindowPhysSize(w, h); sint32 scaledOutputX; sint32 scaledOutputY; @@ -1002,8 +1001,8 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin return {pressed && !toggle, pressed && toggle}; }; - const bool tabPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::TAB); - const bool ctrlPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::LCONTROL); + const bool tabPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::TAB); + const bool ctrlPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::LCONTROL); const auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0); const auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1); diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index 58f9c567..737e9201 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -4,9 +4,9 @@ #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h" #include "Cafe/HW/Latte/Core/FetchShader.h" -#include "Cafe/GameProfile/GameProfile.h" #include "Cemu/FileCache/FileCache.h" -#include "Cemu/GuiSystem/GuiSystem.h" +#include "Cafe/GameProfile/GameProfile.h" +#include "WindowSystem.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h" @@ -23,6 +23,7 @@ #include "Cafe/HW/Latte/Common/RegisterSerializer.h" #include "Cafe/HW/Latte/Common/ShaderSerializer.h" #include "util/helpers/Serializer.h" + #include