From 0c98f9aedbe3bdf17393dac1684ace7a0dcd1137 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Fri, 16 Jan 2015 15:41:40 -0300 Subject: [PATCH] merge latest master changes --- .mailmap | 54 + Data/Sys/GC/font-licenses.txt | 212 +++ Data/Sys/GC/font_ansi.bin | Bin 6733 -> 6478 bytes Data/Sys/GC/font_sjis.bin | Bin 143863 -> 259626 bytes Data/Sys/GameSettings/DVDXDV.ini | 19 - Data/Sys/GameSettings/GZLE01.ini | 3 + Source/Core/Common/Arm64Emitter.cpp | 535 +++++- Source/Core/Common/Arm64Emitter.h | 108 +- Source/Core/Common/BitSet.h | 10 +- Source/Core/Common/MemoryUtil.cpp | 6 +- Source/Core/Core/BootManager.cpp | 2 + Source/Core/Core/CMakeLists.txt | 3 + Source/Core/Core/ConfigManager.h | 2 +- Source/Core/Core/CoreTiming.cpp | 2 +- Source/Core/Core/HLE/HLE_OS.cpp | 2 +- Source/Core/Core/HW/Memmap.cpp | 38 - Source/Core/Core/HW/MemmapFunctions.cpp | 108 +- Source/Core/Core/HW/SI_DeviceGCController.cpp | 144 +- Source/Core/Core/HW/SI_DeviceGCController.h | 14 +- .../Core/Core/HW/SI_DeviceGCSteeringWheel.cpp | 4 +- .../Core/Core/HW/SI_DeviceGCSteeringWheel.h | 6 +- Source/Core/Core/HW/WiimoteReal/IONix.cpp | 6 +- .../Core/Core/HW/WiimoteReal/WiimoteReal.cpp | 33 +- .../IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp | 2 +- .../Interpreter/Interpreter_Tables.cpp | 8 +- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 73 +- Source/Core/Core/PowerPC/Jit64/Jit.h | 1 + .../Core/PowerPC/Jit64/Jit_FloatingPoint.cpp | 8 +- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 77 +- .../Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp | 13 +- .../PowerPC/Jit64/Jit_LoadStorePaired.cpp | 13 +- .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 59 +- Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp | 9 - Source/Core/Core/PowerPC/JitArm32/Jit.cpp | 9 +- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 31 +- Source/Core/Core/PowerPC/JitArm64/Jit.h | 74 +- .../PowerPC/JitArm64/JitArm64_BackPatch.cpp | 171 +- .../JitArm64/JitArm64_FloatingPoint.cpp | 376 ++++ .../PowerPC/JitArm64/JitArm64_Integer.cpp | 279 +++ .../PowerPC/JitArm64/JitArm64_LoadStore.cpp | 17 +- .../JitArm64/JitArm64_LoadStoreFloating.cpp | 394 ++++ .../Core/PowerPC/JitArm64/JitArm64_Paired.cpp | 495 +++++ .../PowerPC/JitArm64/JitArm64_RegCache.cpp | 142 +- .../Core/PowerPC/JitArm64/JitArm64_RegCache.h | 56 +- .../JitArm64/JitArm64_SystemRegisters.cpp | 87 + .../Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 184 +- .../Core/PowerPC/JitCommon/JitAsmCommon.cpp | 36 +- Source/Core/Core/PowerPC/JitCommon/JitBase.h | 6 +- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 578 +++--- Source/Core/Core/PowerPC/JitInterface.cpp | 432 ++--- Source/Core/Core/PowerPC/PPCAnalyst.cpp | 1602 +++++++++-------- Source/Core/Core/PowerPC/PPCAnalyst.h | 7 +- Source/Core/DiscIO/FileSystemGCWii.cpp | 67 +- Source/Core/DiscIO/Filesystem.h | 20 +- Source/Core/DiscIO/Volume.h | 2 +- Source/Core/DiscIO/VolumeCommon.cpp | 1 + Source/Core/DiscIO/VolumeDirectory.cpp | 10 +- Source/Core/DolphinQt/GameList/GameFile.cpp | 4 +- Source/Core/DolphinQt/MainWindow.cpp | 106 +- Source/Core/DolphinQt/MainWindow.h | 5 +- .../DolphinQt/VideoInterface/RenderWidget.cpp | 11 +- Source/Core/DolphinWX/ConfigMain.cpp | 18 +- Source/Core/DolphinWX/ConfigMain.h | 8 +- .../Core/DolphinWX/ControllerConfigDiag.cpp | 30 +- Source/Core/DolphinWX/ControllerConfigDiag.h | 1 + Source/Core/DolphinWX/ISOProperties.cpp | 42 + Source/Core/DolphinWX/ISOProperties.h | 10 + Source/Core/DolphinWX/X11Utils.cpp | 28 +- .../ControllerInterface/SDL/SDL.cpp | 118 +- .../InputCommon/ControllerInterface/SDL/SDL.h | 50 +- Source/Core/VideoCommon/CommandProcessor.cpp | 2 +- Source/Core/VideoCommon/MainBase.cpp | 5 + docs/gc-font-tool.cpp | 1377 ++++++++++++++ 73 files changed, 6460 insertions(+), 2005 deletions(-) create mode 100644 .mailmap create mode 100644 Data/Sys/GC/font-licenses.txt delete mode 100644 Data/Sys/GameSettings/DVDXDV.ini create mode 100644 Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp create mode 100644 Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp create mode 100644 Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp create mode 100644 docs/gc-font-tool.cpp diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..5a39dd5b9 --- /dev/null +++ b/.mailmap @@ -0,0 +1,54 @@ +# This file exists to enable "git shortlog -s" to group by person. +Andrew de los Reyes +Augustin Cavalier +Benjamin Przybocki +Dolphin Bots +Dolphin Bots +Dolphin Bots +Grant Paul +Henrik Rydgård +Jack Frost +James Dunne +John Chadwick +John Peterson +John Peterson +Jordan Cristiano +Jordan Cristiano +Jordan Woyak +Jordan Woyak +Jules Blok Armada +Lioncash +Lioncash Lioncash +Lioncash +Maarten ter Huurne +Marcos Vitali +Markus Wick +Matthew Parlane +Matthew Parlane +Oussama Danba +Pascal Jouy +Pierre +Pierre Bourdon +Rodolfo Bogado +Rog +RolandMunsil +Runo +Ryan Houdek +Ryan Houdek +Ryan Houdek +Ryan Houdek +Sacha +Sean Maas +Shawn Hoffman +Steven V. +Steven V. +Tony Wasserka +Tony Wasserka +TotalNerd +booto +i418c +luisr142004 +magumagu +masken +nitsuja +skidau diff --git a/Data/Sys/GC/font-licenses.txt b/Data/Sys/GC/font-licenses.txt new file mode 100644 index 000000000..9c33438ea --- /dev/null +++ b/Data/Sys/GC/font-licenses.txt @@ -0,0 +1,212 @@ +The two fonts in this directory (font_ansi.bin and font_sjis.bin) were +generated using gc-font-tool which can be found in the docs/ directory in the +dolphin source code. + +Both fonts are based on Droid Sans + +Copyright 2006-2014, Google Corporation +Licensed under the Apache License 2.0 + +==== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Data/Sys/GC/font_ansi.bin b/Data/Sys/GC/font_ansi.bin index 33b20041cc0cdf57501a28b7c5cd312d93f91453..863f877e9f33bc571f05d56605306680a6c68a55 100644 GIT binary patch literal 6478 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 Og1M2k;{Wf*!|*@iX1>w@ literal 6733 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 diff --git a/Data/Sys/GC/font_sjis.bin b/Data/Sys/GC/font_sjis.bin index c8d25fdcd0ce73f39e48489c1bdd21be9bc0b677..132dbfc2c3bc5b7d663eb45a09f2a8e3ea02340b 100644 GIT binary patch literal 259626 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

If>E2xf_pZ3KY%5js>(nfh^$jXjaDπ>wDaW6 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≥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 F{|l3t3*-O* literal 143863 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

&$89ua+2>JTwwx9sD2WzYJ$C|#7 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�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�}fdKWjpRB4mGwhnp7^26tW4*@fD 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%0ANd{5goGxxD9pS!fSD(B{?vIWL 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 Z-Uq(^Z5kVITU)+T_`m=E_P>As{{}b;q=Wzf diff --git a/Data/Sys/GameSettings/DVDXDV.ini b/Data/Sys/GameSettings/DVDXDV.ini deleted file mode 100644 index d30f9d5d1..000000000 --- a/Data/Sys/GameSettings/DVDXDV.ini +++ /dev/null @@ -1,19 +0,0 @@ -# DVDXDV - Unknown - -[Core] -# Values set here will override the main dolphin settings. - -[EmuState] -# The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationStateId = 0 -EmulationIssues = - -[OnLoad] -# Add memory patches to be loaded once on boot here. - -[OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. - diff --git a/Data/Sys/GameSettings/GZLE01.ini b/Data/Sys/GameSettings/GZLE01.ini index 1efac5d49..3f3055b95 100644 --- a/Data/Sys/GameSettings/GZLE01.ini +++ b/Data/Sys/GameSettings/GZLE01.ini @@ -368,3 +368,6 @@ EFBCopyEnable = True [Video_Settings] FastDepthCalc = False + +[Video_Stereoscopy] +StereoConvergenceMinimum = 115 diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 3d1c9801b..d5e082aa2 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -377,7 +377,7 @@ void ARM64XEmitter::EncodeLoadStoreExcInst(u32 instenc, void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) { bool b64Bit = Is64Bit(Rt); - bool b128Bit = Is128Bit(Rt); + bool b128Bit = IsQuad(Rt); bool bVec = IsVector(Rt); if (b128Bit) @@ -417,15 +417,17 @@ void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (offset << 12) | (op2 << 10) | (Rn << 5) | Rt); } -void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) +void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size) { bool b64Bit = Is64Bit(Rt); bool bVec = IsVector(Rt); - if (b64Bit) + if (size == 64) imm >>= 3; - else + else if (size == 32) imm >>= 2; + else if (size == 16) + imm >>= 1; _assert_msg_(DYNA_REC, imm < 0, "%s(INDEX_UNSIGNED): offset must be positive", __FUNCTION__); _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, imm); @@ -799,7 +801,7 @@ void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Optio void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - ADD(Rd, Rn, Rm, ArithOption(Rd)); + EncodeArithmeticInst(0, true, Rd, Rn, Rm, ArithOption(Rd)); } void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) @@ -819,7 +821,7 @@ void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Optio void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - SUB(Rd, Rn, Rm, ArithOption(Rd)); + EncodeArithmeticInst(1, false, Rd, Rn, Rm, ArithOption(Rd)); } void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) @@ -1020,6 +1022,14 @@ void ARM64XEmitter::UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { EncodeData3SrcInst(7, Rd, Rn, Rm, Ra); } +void ARM64XEmitter::MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EncodeData3SrcInst(0, Rd, Rn, Rm, SP); +} +void ARM64XEmitter::MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EncodeData3SrcInst(1, Rd, Rn, Rm, SP); +} // Logical (shifted register) void ARM64XEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) @@ -1282,7 +1292,7 @@ void ARM64XEmitter::LDNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) void ARM64XEmitter::STRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x0E4, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(0x0E4, Rt, Rn, imm, 8); else EncodeLoadStoreIndexedInst(0x0E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1290,7 +1300,7 @@ void ARM64XEmitter::STRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x0E5, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(0x0E5, Rt, Rn, imm, 8); else EncodeLoadStoreIndexedInst(0x0E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1298,7 +1308,7 @@ void ARM64XEmitter::LDRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDRSB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E6 : 0x0E7, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E6 : 0x0E7, Rt, Rn, imm, 8); else EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E2 : 0x0E3, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1306,7 +1316,7 @@ void ARM64XEmitter::LDRSB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::STRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x1E4, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(0x1E4, Rt, Rn, imm, 16); else EncodeLoadStoreIndexedInst(0x1E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1314,7 +1324,7 @@ void ARM64XEmitter::STRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x1E5, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(0x1E5, Rt, Rn, imm, 16); else EncodeLoadStoreIndexedInst(0x1E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1322,7 +1332,7 @@ void ARM64XEmitter::LDRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDRSH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E6 : 0x1E7, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E6 : 0x1E7, Rt, Rn, imm, 16); else EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E2 : 0x1E3, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1330,7 +1340,7 @@ void ARM64XEmitter::LDRSH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::STR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E4 : 0x2E4, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E4 : 0x2E4, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); else EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E0 : 0x2E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1338,7 +1348,7 @@ void ARM64XEmitter::STR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E5 : 0x2E5, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E5 : 0x2E5, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); else EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E1 : 0x2E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1346,7 +1356,7 @@ void ARM64XEmitter::LDR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) void ARM64XEmitter::LDRSW(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x2E6, Rt, Rn, imm); + EncodeLoadStoreIndexedInst(0x2E6, Rt, Rn, imm, 32); else EncodeLoadStoreIndexedInst(0x2E2, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); @@ -1431,7 +1441,7 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize) // Max unsigned value // Set to ~ZR ARM64Reg ZR = Is64Bit(Rd) ? SP : WSP; - ORN(Rd, Rd, ZR, ArithOption(ZR, ST_LSL, 0)); + ORN(Rd, ZR, ZR, ArithOption(ZR, ST_LSL, 0)); return; } @@ -1597,5 +1607,498 @@ void ARM64XEmitter::ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask) } } +// Float Emitter +void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) +{ + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + u32 encoded_size = 0; + u32 encoded_imm = 0; + + if (size == 8) + encoded_size = 0; + else if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; + else if (size == 128) + encoded_size = 0; + + if (type == INDEX_UNSIGNED) + { + _assert_msg_(DYNA_REC, imm & (size - 1), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size!", __FUNCTION__); + _assert_msg_(DYNA_REC, imm < 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__); + if (size == 16) + imm >>= 1; + else if (size == 32) + imm >>= 2; + else if (size == 64) + imm >>= 3; + else if (size == 128) + imm >>= 4; + encoded_imm = (imm & 0xFFF); + } + else + { + _assert_msg_(DYNA_REC, imm < -256 || imm > 255, "%s immediate offset must be within range of -256 to 256!", __FUNCTION__); + encoded_imm = (imm & 0x1FF) << 2; + if (type == INDEX_POST) + encoded_imm |= 1; + else + encoded_imm |= 3; + } + + Write32((encoded_size << 30) | (0b1111 << 26) | (type == INDEX_UNSIGNED ? (1 << 24) : 0) | \ + (size == 128 ? (1 << 23) : 0) | (opc << 22) | (encoded_imm << 10) | (Rn << 5) | Rt); +} + +void ARM64FloatEmitter::Emit2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + _assert_msg_(DYNA_REC, IsQuad(Rd), "%s only supports double and single registers!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + + Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (type << 22) | (Rm << 16) | \ + (opcode << 12) | (1 << 11) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + _assert_msg_(DYNA_REC, IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + + Write32((quad << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | \ + (Rm << 16) | (opcode << 11) | (1 << 10) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn) +{ + _assert_msg_(DYNA_REC, Rn <= SP, "%s only supports VFP registers!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + + Write32((Q << 30) | (op << 29) | (0b111 << 25) | (imm5 << 16) | (imm4 << 11) | \ + (1 << 10) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::Emit2RegMisc(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +{ + _assert_msg_(DYNA_REC, IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + + Write32((quad << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | \ + (opcode << 12) | (1 << 11) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn) +{ + _assert_msg_(DYNA_REC, IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + + Write32((quad << 30) | (0b1101 << 24) | (L << 22) | (R << 21) | (opcode << 13) | \ + (S << 12) | (size << 10) | (Rn << 5) | Rt); +} + +void ARM64FloatEmitter::Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +{ + _assert_msg_(DYNA_REC, IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + + Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (type << 22) | (opcode << 15) | \ + (1 << 14) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +{ + _assert_msg_(DYNA_REC, !(Rn <= SP), "%s only supports GPR as source!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + + Write32((sf << 31) | (S << 29) | (0b11110001 << 21) | (type << 22) | (rmode << 19) | \ + (opcode << 16) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm) +{ + bool is_double = !IsSingle(Rn); + + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + + Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (is_double << 22) | (Rm << 16) | \ + (op << 14) | (1 << 13) | (Rn << 5) | opcode2); +} + +void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + bool is_double = !IsSingle(Rd); + + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + + Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (is_double << 22) | (Rm << 16) | \ + (cond << 12) | (0b11 << 10) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + _assert_msg_(DYNA_REC, IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + + bool quad = IsQuad(Rd); + + u32 encoded_size = 0; + if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; + + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + + Write32((quad << 30) | (0b111 << 25) | (encoded_size << 22) | (Rm << 16) | (op << 12) | \ + (1 << 11) | (Rn << 5) | Rd); +} + +void ARM64FloatEmitter::LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) +{ + EmitLoadStoreImmediate(size, 1, type, Rt, Rn, imm); +} +void ARM64FloatEmitter::STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) +{ + EmitLoadStoreImmediate(size, 0, type, Rt, Rn, imm); +} + +// Loadstore single structure +void ARM64FloatEmitter::LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn) +{ + EmitLoadStoreSingleStructure(1, 0, 0b110, 0, size >> 4, Rt, Rn); +} + +// Scalar - 2 Source +void ARM64FloatEmitter::FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + Emit2Source(0, 0, IsDouble(Rd), 0, Rd, Rn, Rm); +} + +// Vector +void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, 0, 0b00011, Rd, Rn, Rm); +} +void ARM64FloatEmitter::BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, 1, 0b00011, Rd, Rn, Rm); +} +void ARM64FloatEmitter::DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) +{ + u32 imm5 = 0; + + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index << 4; + } + + EmitCopy(IsQuad(Rd), 0, imm5, 0, Rd, Rn); +} +void ARM64FloatEmitter::FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, 2 | (size >> 6), 0b01111, Rd, Rn); +} +void ARM64FloatEmitter::FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, size >> 6, 0b11010, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, size >> 6, 0b10111, Rd, Rn); +} +void ARM64FloatEmitter::FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, size >> 6, 0b11111, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, size >> 6, 0b11011, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, 2 | (size >> 6), 0b01111, Rd, Rn); +} +void ARM64FloatEmitter::FRSQRTE(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, 2 | (size >> 6), 0b11101, Rd, Rn); +} +void ARM64FloatEmitter::FSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, 2 | (size >> 6), 0b11010, Rd, Rn, Rm); +} +void ARM64FloatEmitter::NOT(ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, 0, 0b00101, Rd, Rn); +} +void ARM64FloatEmitter::ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, 2, 0b00011, Rd, Rn, Rm); +} +void ARM64FloatEmitter::REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, 1 | (size >> 4), 0, Rd, Rn); +} +void ARM64FloatEmitter::REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, size >> 4, 0, Rd, Rn); +} +void ARM64FloatEmitter::REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, size >> 4, 0, Rd, Rn); +} + +// Move +void ARM64FloatEmitter::DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + u32 imm5 = 0; + + if (size == 8) + imm5 = 1; + else if (size == 16) + imm5 = 2; + else if (size == 32) + imm5 = 4; + else if (size == 64) + imm5 = 8; + + EmitCopy(IsQuad(Rd), 0, imm5, 0b0001, Rd, Rn); + +} +void ARM64FloatEmitter::INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn) +{ + u32 imm5 = 0; + + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index << 4; + } + + EmitCopy(1, 0, imm5, 0b0011, Rd, Rn); +} +void ARM64FloatEmitter::INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2) +{ + u32 imm5 = 0, imm4 = 0; + + if (size == 8) + { + imm5 = 1; + imm5 |= index1 << 1; + imm4 = index2; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index1 << 2; + imm4 = index2 << 1; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index1 << 3; + imm4 = index2 << 2; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index1 << 4; + imm4 = index2 << 3; + } + + EmitCopy(1, 1, imm5, imm4, Rd, Rn); +} + +// One source +void ARM64FloatEmitter::FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn) +{ + u32 dst_encoding = 0; + u32 src_encoding = 0; + + if (size_to == 16) + dst_encoding = 3; + else if (size_to == 32) + dst_encoding = 0; + else if (size_to == 64) + dst_encoding = 1; + + if (size_from == 16) + src_encoding = 3; + else if (size_from == 32) + src_encoding = 0; + else if (size_from == 64) + src_encoding = 1; + + Emit1Source(0, 0, src_encoding, 0b100 | dst_encoding, Rd, Rn); +} + +// Conversion between float and integer +void ARM64FloatEmitter::FMOV(u8 size, bool top, ARM64Reg Rd, ARM64Reg Rn) +{ + bool sf = size == 64 ? true : false; + u32 type = 0; + u32 rmode = top ? 1 : 0; + if (size == 64) + { + if (top) + type = 2; + else + type = 1; + } + + EmitConversion(sf, 0, type, rmode, IsVector(Rd) ? 0b111 : 0b110, Rd, Rn); +} + +void ARM64FloatEmitter::FCMP(ARM64Reg Rn, ARM64Reg Rm) +{ + EmitCompare(0, 0, 0, 0, Rn, Rm); +} +void ARM64FloatEmitter::FCMP(ARM64Reg Rn) +{ + EmitCompare(0, 0, 0, 0b01000, Rn, (ARM64Reg)0); +} +void ARM64FloatEmitter::FCMPE(ARM64Reg Rn, ARM64Reg Rm) +{ + EmitCompare(0, 0, 0, 0b10000, Rn, Rm); +} +void ARM64FloatEmitter::FCMPE(ARM64Reg Rn) +{ + EmitCompare(0, 0, 0, 0b11000, Rn, (ARM64Reg)0); +} +void ARM64FloatEmitter::FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, size >> 6, 0b11100, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, 2 | (size >> 6), 0b01101, Rd, Rn); +} +void ARM64FloatEmitter::FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, size >> 6, 0b11100, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, 2 | (size >> 6), 0b01100, Rd, Rn); +} +void ARM64FloatEmitter::FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, 2 | (size >> 6), 0b11100, Rd, Rn, Rm); +} +void ARM64FloatEmitter::FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, 2 | (size >> 6), 0b01100, Rd, Rn); +} +void ARM64FloatEmitter::FCMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(1, 2 | (size >> 6), 0b01101, Rd, Rn); +} +void ARM64FloatEmitter::FCMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(0, 2 | (size >> 6), 0b01110, Rd, Rn); +} + +void ARM64FloatEmitter::FCSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) +{ + EmitCondSelect(0, 0, cond, Rd, Rn, Rm); +} + +// Permute +void ARM64FloatEmitter::UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b001, Rd, Rn, Rm); +} +void ARM64FloatEmitter::TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b010, Rd, Rn, Rm); +} +void ARM64FloatEmitter::ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b011, Rd, Rn, Rm); +} +void ARM64FloatEmitter::UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b101, Rd, Rn, Rm); +} +void ARM64FloatEmitter::TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b110, Rd, Rn, Rm); +} +void ARM64FloatEmitter::ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitPermute(size, 0b111, Rd, Rn, Rm); +} + +void ARM64FloatEmitter::ABI_PushRegisters(BitSet32 registers) +{ + for (auto it : registers) + STR(128, INDEX_PRE, (ARM64Reg)(Q0 + it), SP, -16); + +} +void ARM64FloatEmitter::ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask) +{ + for (int i = 31; i >= 0; --i) + { + if (!registers[i]) + continue; + + if (ignore_mask[i]) + m_emit->ADD(SP, SP, 16); + else + LDR(128, INDEX_POST, (ARM64Reg)(Q0 + i), SP, 16); + } +} + } diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 02e70336d..f6e09e661 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -76,7 +76,9 @@ enum ARM64Reg }; inline bool Is64Bit(ARM64Reg reg) { return reg & 0x20; } -inline bool Is128Bit(ARM64Reg reg) { return reg & 0xC0; } +inline bool IsSingle(ARM64Reg reg) { return reg & 0x40; } +inline bool IsDouble(ARM64Reg reg) { return reg & 0x80; } +inline bool IsQuad(ARM64Reg reg) { return (reg & 0xC0) == 0xC0; } inline bool IsVector(ARM64Reg reg) { return (reg & 0xC0) != 0; } inline ARM64Reg DecodeReg(ARM64Reg reg) { return (ARM64Reg)(reg & 0x1F); } inline ARM64Reg EncodeRegTo64(ARM64Reg reg) { return (ARM64Reg)(reg | 0x20); } @@ -238,9 +240,17 @@ public: m_shifttype = shift_type; m_type = TYPE_SHIFTEDREG; if (Is64Bit(Rd)) + { m_width = WIDTH_64BIT; + if (shift == 64) + m_shift = 0; + } else + { m_width = WIDTH_32BIT; + if (shift == 32) + m_shift = 0; + } } TypeSpecifier GetType() const { @@ -270,6 +280,8 @@ public: class ARM64XEmitter { + friend class ARM64FloatEmitter; + private: u8* m_code; u8* m_startcode; @@ -294,7 +306,7 @@ private: void EncodeLoadStoreExcInst(u32 instenc, ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, ARM64Reg Rt); void EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); void EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size); void EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos); void EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend); @@ -452,6 +464,8 @@ public: void UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); void UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); void UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); // Logical (shifted register) void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); @@ -565,6 +579,96 @@ public: void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0)); }; +class ARM64FloatEmitter +{ +public: + ARM64FloatEmitter(ARM64XEmitter* emit) : m_emit(emit) {} + + void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + + // Loadstore single structure + void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn); + + // Scalar - 2 Source + void FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + + // Vector + void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); + void FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FRSQRTE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void NOT(ARM64Reg Rd, ARM64Reg Rn); + void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn); + + // Move + void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn); + void INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2); + + // One source + void FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn); + + // Conversion between float and integer + void FMOV(u8 size, bool top, ARM64Reg Rd, ARM64Reg Rn); + + // Float comparison + void FCMP(ARM64Reg Rn, ARM64Reg Rm); + void FCMP(ARM64Reg Rn); + void FCMPE(ARM64Reg Rn, ARM64Reg Rm); + void FCMPE(ARM64Reg Rn); + void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + + // Conditional select + void FCSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + + // Permute + void UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + + // ABI related + void ABI_PushRegisters(BitSet32 registers); + void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0)); + +private: + ARM64XEmitter* m_emit; + inline void Write32(u32 value) { m_emit->Write32(value); } + + // Emitting functions + void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void Emit2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn); + void Emit2RegMisc(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn); + void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm); + void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); +}; + class ARM64CodeBlock : public CodeBlock { private: diff --git a/Source/Core/Common/BitSet.h b/Source/Core/Common/BitSet.h index 23fdf7a60..70b9204fa 100644 --- a/Source/Core/Common/BitSet.h +++ b/Source/Core/Common/BitSet.h @@ -16,10 +16,10 @@ static inline int CountSetBits(T v) // from https://graphics.stanford.edu/~seander/bithacks.html // GCC has this built in, but MSVC's intrinsic will only emit the actual // POPCNT instruction, which we're not depending on - v = v - ((v >> 1) & (T)~(T)0 / 3); - v = (v & (T)~(T)0 / 15 * 3) + ((v >> 2) & (T)~(T)0 / 15 * 3); - v = (v + (v >> 4)) & (T)~(T)0 / 255 * 15; - return (T)(v * ((T)~(T)0 / 255)) >> (sizeof(T) - 1) * 8; + v = v - ((v >> 1) & (T)~(T)0/3); + v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); + v = (v + (v >> 4)) & (T)~(T)0/255*15; + return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; } static inline int LeastSignificantSetBit(u8 val) { @@ -148,7 +148,7 @@ public: static BitSet AllTrue(size_t count) { - return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); + return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); } Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } diff --git a/Source/Core/Common/MemoryUtil.cpp b/Source/Core/Common/MemoryUtil.cpp index fd8872681..e36babb03 100644 --- a/Source/Core/Common/MemoryUtil.cpp +++ b/Source/Core/Common/MemoryUtil.cpp @@ -21,6 +21,10 @@ #include #endif +// Valgrind doesn't support MAP_32BIT. +// Uncomment the following line to be able to run Dolphin in Valgrind. +//#undef MAP_32BIT + #if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) #include #define PAGE_MASK (getpagesize() - 1) @@ -65,7 +69,7 @@ void* AllocateExecutableMemory(size_t size, bool low) { ptr = nullptr; #endif - PanicAlert("Failed to allocate executable memory"); + PanicAlert("Failed to allocate executable memory. If you are running Dolphin in Valgrind, try '#undef MAP_32BIT'."); } #if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) else diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 2578e5a22..34b2ca8d5 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -250,6 +250,8 @@ bool BootCore(const std::string& _rFilename) StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard; StartUp.iCPUCore = g_NetPlaySettings.m_CPUcore; SConfig::GetInstance().m_DSPEnableJIT = g_NetPlaySettings.m_DSPEnableJIT; + SConfig::GetInstance().m_OCEnable = g_NetPlaySettings.m_OCEnable; + SConfig::GetInstance().m_OCFactor = g_NetPlaySettings.m_OCFactor; SConfig::GetInstance().m_EXIDevice[0] = g_NetPlaySettings.m_EXIDevice[0]; SConfig::GetInstance().m_EXIDevice[1] = g_NetPlaySettings.m_EXIDevice[1]; config_cache.bSetEXIDevice[0] = true; diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 3af53428a..7cbf4509f 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -225,8 +225,11 @@ elseif(_M_ARM_64) PowerPC/JitArm64/JitArm64_RegCache.cpp PowerPC/JitArm64/JitArm64_BackPatch.cpp PowerPC/JitArm64/JitArm64_Branch.cpp + PowerPC/JitArm64/JitArm64_FloatingPoint.cpp PowerPC/JitArm64/JitArm64_Integer.cpp PowerPC/JitArm64/JitArm64_LoadStore.cpp + PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp + PowerPC/JitArm64/JitArm64_Paired.cpp PowerPC/JitArm64/JitArm64_SystemRegisters.cpp PowerPC/JitArm64/JitArm64_Tables.cpp) endif() diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 5fcc0d8a1..45e00c289 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -50,8 +50,8 @@ struct SConfig : NonCopyable int m_InterfaceLanguage; // framelimit choose unsigned int m_Framelimit; - float m_OCFactor; bool m_OCEnable; + float m_OCFactor; // other interface settings bool m_InterfaceToolbar; bool m_InterfaceStatusbar; diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index cb2c1436e..ff50f5b38 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -477,7 +477,7 @@ void Idle() } } - idledCycles += PowerPC::ppcState.downcount; + idledCycles += DowncountToCycles(PowerPC::ppcState.downcount); PowerPC::ppcState.downcount = 0; Advance(); diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 66b6f3af2..b1dc19f21 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -88,7 +88,7 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg) } else { - if (string[i - 1] == 'l' && string[i - 2] == 'l') // hax, just seen this on sysmenu osreport + if (string[i-1] == 'l' && string[i-2] == 'l') // hax, just seen this on sysmenu osreport { Parameter = GPR(++ParameterCounter); Parameter = (Parameter<<32)|GPR(++ParameterCounter); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index d97aff3a2..fc8dc39f3 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -243,44 +243,6 @@ void ClearCacheLine(const u32 address) Write_U64(0, address + i); } -void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks) -{ - const u8* src = m_pL1Cache + (cacheAddr & 0x3FFFF); - u8* dst = GetPointer(memAddr); - - if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0) - { - memcpy(dst, src, 32 * numBlocks); - } - else - { - for (u32 i = 0; i < 32 * numBlocks; i++) - { - u8 Temp = Read_U8(cacheAddr + i); - Write_U8(Temp, memAddr + i); - } - } -} - -void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks) -{ - const u8* src = GetPointer(memAddr); - u8* dst = m_pL1Cache + (cacheAddr & 0x3FFFF); - - if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0) - { - memcpy(dst, src, 32 * numBlocks); - } - else - { - for (u32 i = 0; i < 32 * numBlocks; i++) - { - u8 Temp = Read_U8(memAddr + i); - Write_U8(Temp, cacheAddr + i); - } - } -} - std::string GetString(u32 em_address, size_t size) { const char* ptr = reinterpret_cast(GetPointer(em_address)); diff --git a/Source/Core/Core/HW/MemmapFunctions.cpp b/Source/Core/Core/HW/MemmapFunctions.cpp index d52bb6f5a..f8380ac18 100644 --- a/Source/Core/Core/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/HW/MemmapFunctions.cpp @@ -90,6 +90,24 @@ static u32 EFB_Read(const u32 addr) return var; } +static void EFB_Write(u32 data, u32 addr) +{ + int x = (addr & 0xfff) >> 2; + int y = (addr >> 12) & 0x3ff; + + if (addr & 0x00400000) + { + g_video_backend->Video_AccessEFB(POKE_Z, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", data, x, y); + } + else + { + g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", data, x, y); + } +} + + static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite); template @@ -193,20 +211,8 @@ __forceinline void WriteToHardware(u32 em_address, const T data) { if (em_address < 0xcc000000) { - int x = (em_address & 0xfff) >> 2; - int y = (em_address >> 12) & 0x3ff; - - // TODO figure out a way to send data without falling into the template trap - if (em_address & 0x00400000) - { - g_video_backend->Video_AccessEFB(POKE_Z, x, y, (u32)data); - DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", (u32)data, x, y); - } - else - { - g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, (u32)data); - DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", (u32)data, x, y); - } + // TODO: This only works correctly for 32-bit writes. + EFB_Write((u32)data, em_address); return; } else @@ -460,6 +466,78 @@ void WriteUnchecked_U32(const u32 var, const u32 address) WriteToHardware(address, var); } +void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks) +{ + // TODO: It's not completely clear this is the right spot for this code; + // what would happen if, for example, the DVD drive tried to write to the EFB? + // TODO: This is terribly slow. + // TODO: Refactor. + // Avatar: The Last Airbender (GC) uses this for videos. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i+=4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + EFB_Write(data, memAddr + i); + } + return; + } + + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + mmio_mapping->Write(memAddr + i, data); + } + return; + } + + const u8* src = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + u8* dst = Memory::GetPointer(memAddr); + if (dst == nullptr) + return; + + memcpy(dst, src, 32 * numBlocks); +} + +void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks) +{ + const u8* src = Memory::GetPointer(memAddr); + u8* dst = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = EFB_Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } + + // No known game uses this. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = mmio_mapping->Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } + + if (src == nullptr) + return; + + memcpy(dst, src, 32 * numBlocks); +} + // ********************************************************************************* // Warning: Test Area // @@ -616,7 +694,7 @@ enum TLBLookupResult static __forceinline TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32 vpa, u32 *paddr) { - int tag = vpa >> HW_PAGE_INDEX_SHIFT; + u32 tag = vpa >> HW_PAGE_INDEX_SHIFT; PowerPC::tlb_entry *tlbe = &PowerPC::ppcState.tlb[flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK]; if (tlbe->tag[0] == tag) { diff --git a/Source/Core/Core/HW/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI_DeviceGCController.cpp index 1f9cd45b5..ffb911b06 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCController.cpp @@ -28,16 +28,16 @@ CSIDevice_GCController::CSIDevice_GCController(SIDevices device, int _iDeviceNum memset(&m_Origin, 0, sizeof(SOrigin)); memset(&pad_origin, 0, sizeof(GCPadStatus)); - pad_origin.button = 0x00; - pad_origin.stickX = 0x80; // center - pad_origin.stickY = 0x80; - pad_origin.substickX = 0x80; - pad_origin.substickY = 0x80; - pad_origin.triggerLeft = 0x1F; // 0-30 is the lower deadzone + pad_origin.button = 0x00; + pad_origin.stickX = 0x80; // center + pad_origin.stickY = 0x80; + pad_origin.substickX = 0x80; + pad_origin.substickY = 0x80; + pad_origin.triggerLeft = 0x1F; // 0-30 is the lower deadzone pad_origin.triggerRight = 0x1F; // Dunno if we need to do this, game/lib should set it? - m_Mode = 0x03; + m_Mode = 0x03; #if defined(__LIBUSB__) || defined (_WIN32) if (SI_GCAdapter::IsDetected()) @@ -71,48 +71,48 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength) break; case CMD_DIRECT: - { - INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength); - u32 high, low; - GetData(high, low); - for (int i = 0; i < (_iLength - 1) / 2; i++) { - _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; - _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; + INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength); + u32 high, low; + GetData(high, low); + for (int i = 0; i < (_iLength - 1) / 2; i++) + { + _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; + _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; + } } - } - break; + break; case CMD_ORIGIN: - { - INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); - u8* pCalibration = reinterpret_cast(&m_Origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) { - _pBuffer[i ^ 3] = *pCalibration++; + INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } } - } - break; + break; // Recalibrate (FiRES: i am not 100 percent sure about this) case CMD_RECALIBRATE: - { - INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate"); - u8* pCalibration = reinterpret_cast(&m_Origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) { - _pBuffer[i ^ 3] = *pCalibration++; + INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate"); + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } } - } - break; + break; // DEFAULT default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); - PanicAlert("SI: Unknown command (0x%x)", command); - } - break; + { + ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); + PanicAlert("SI: Unknown command (0x%x)", command); + } + break; } return _iLength; @@ -168,7 +168,7 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) // Low bits are packed differently per mode if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7) { - _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits @@ -177,7 +177,7 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) } else if (m_Mode == 1) { - _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits _Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits _Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits @@ -186,7 +186,7 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) } else if (m_Mode == 2) { - _Low = (u8)(PadStatus.analogB); // All 8 bits + _Low = (u8)(PadStatus.analogB); // All 8 bits _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 16); // Top 4 bits _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 20); // Top 4 bits @@ -196,14 +196,14 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) else if (m_Mode == 3) { // Analog A/B are always 0 - _Low = (u8)PadStatus.triggerRight; // All 8 bits + _Low = (u8)PadStatus.triggerRight; // All 8 bits _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits } else if (m_Mode == 4) { - _Low = (u8)(PadStatus.analogB); // All 8 bits + _Low = (u8)(PadStatus.analogB); // All 8 bits _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits // triggerLeft/Right are always 0 _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits @@ -218,7 +218,7 @@ u32 CSIDevice_GCController::MapPadStatus(const GCPadStatus& pad_status) { // Thankfully changing mode does not change the high bits ;) u32 _Hi = 0; - _Hi = (u32)((u8)pad_status.stickY); + _Hi = (u32)((u8)pad_status.stickY); _Hi |= (u32)((u8)pad_status.stickX << 8); _Hi |= (u32)((u16)(pad_status.button | PAD_USE_ORIGIN) << 16); return _Hi; @@ -228,9 +228,9 @@ void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) { // Keep track of the special button combos (embedded in controller hardware... :( ) EButtonCombo tempCombo; - if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y | PAD_BUTTON_X | PAD_BUTTON_START)) + if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START)) tempCombo = COMBO_ORIGIN; - else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B | PAD_BUTTON_X | PAD_BUTTON_START)) + else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START)) tempCombo = COMBO_RESET; else tempCombo = COMBO_NONE; @@ -249,12 +249,12 @@ void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) ProcessorInterface::ResetButton_Tap(); else if (m_LastButtonCombo == COMBO_ORIGIN) { - m_Origin.uOriginStickX = pad_status.stickX; - m_Origin.uOriginStickY = pad_status.stickY; + m_Origin.uOriginStickX = pad_status.stickX; + m_Origin.uOriginStickY = pad_status.stickY; m_Origin.uSubStickStickX = pad_status.substickX; m_Origin.uSubStickStickY = pad_status.substickY; - m_Origin.uTrigger_L = pad_status.triggerLeft; - m_Origin.uTrigger_R = pad_status.triggerRight; + m_Origin.uTrigger_L = pad_status.triggerLeft; + m_Origin.uTrigger_R = pad_status.triggerRight; } m_LastButtonCombo = COMBO_NONE; } @@ -268,43 +268,43 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll) switch (command.Command) { - // Costis sent it in some demos :) + // Costis sent it in some demos :) case 0x00: break; case CMD_WRITE: - { - unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard - unsigned int uStrength = command.Parameter2; + { + unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + unsigned int uStrength = command.Parameter2; - // get the correct pad number that should rumble locally when using netplay - const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); #if defined(__LIBUSB__) || defined (_WIN32) - SI_GCAdapter::Output(numPAD, command.Parameter1 & 0xff); + SI_GCAdapter::Output(numPAD, command.Parameter1 & 0xff); #endif - if (numPAD < 4) - { - if (uType == 1 && uStrength > 2) - Pad::Rumble(numPAD, 1.0); - else - Pad::Rumble(numPAD, 0.0); - } + if (numPAD < 4) + { + if (uType == 1 && uStrength > 2) + Pad::Rumble(numPAD, 1.0); + else + Pad::Rumble(numPAD, 0.0); + } - if (!_Poll) - { - m_Mode = command.Parameter2; - INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + if (!_Poll) + { + m_Mode = command.Parameter2; + INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + } } - } - break; + break; default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); - PanicAlert("SI: Unknown direct command"); - } - break; + { + ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); + PanicAlert("SI: Unknown direct command"); + } + break; } } diff --git a/Source/Core/Core/HW/SI_DeviceGCController.h b/Source/Core/Core/HW/SI_DeviceGCController.h index 0a1adf12e..3b0346cbe 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.h +++ b/Source/Core/Core/HW/SI_DeviceGCController.h @@ -14,9 +14,9 @@ protected: // Commands enum EBufferCommands { - CMD_RESET = 0x00, - CMD_DIRECT = 0x40, - CMD_ORIGIN = 0x41, + CMD_RESET = 0x00, + CMD_DIRECT = 0x40, + CMD_ORIGIN = 0x41, CMD_RECALIBRATE = 0x42, }; @@ -47,11 +47,11 @@ protected: { u32 Parameter1 : 8; u32 Parameter2 : 8; - u32 Command : 8; - u32: 8; + u32 Command : 8; + u32 : 8; }; - UCommand() { Hex = 0; } - UCommand(u32 _iValue) { Hex = _iValue; } + UCommand() {Hex = 0;} + UCommand(u32 _iValue) {Hex = _iValue;} }; enum EButtonCombo diff --git a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp index 5ff546137..e0d43b2b0 100644 --- a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp @@ -24,11 +24,11 @@ int CSIDevice_GCSteeringWheel::RunBuffer(u8* _pBuffer, int _iLength) *(u32*)&_pBuffer[0] = SI_GC_STEERING; break; - // Seen in F-Zero GX + // Seen in F-Zero GX case CMD_MOTOR_OFF: break; - // DEFAULT + // DEFAULT default: { return CSIDevice_GCController::RunBuffer(_pBuffer, _iLength); diff --git a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h index 66c257d92..791e30aca 100644 --- a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h +++ b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h @@ -12,10 +12,10 @@ private: // Commands enum EBufferCommands { - CMD_RESET = 0x00, - CMD_ORIGIN = 0x41, + CMD_RESET = 0x00, + CMD_ORIGIN = 0x41, CMD_RECALIBRATE = 0x42, - CMD_MOTOR_OFF = 0xff, + CMD_MOTOR_OFF = 0xff, }; enum EDirectCommands diff --git a/Source/Core/Core/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/HW/WiimoteReal/IONix.cpp index 371a0c12b..d28712138 100644 --- a/Source/Core/Core/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IONix.cpp @@ -174,7 +174,7 @@ bool WiimoteLinux::ConnectInternal() // Output channel addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { WARN_LOG(WIIMOTE, "Unable to open output socket to wiimote: %s", strerror(errno)); close(m_cmd_sock); @@ -185,7 +185,7 @@ bool WiimoteLinux::ConnectInternal() // Input channel addr.l2_psm = htobs(WM_INPUT_CHANNEL); if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { WARN_LOG(WIIMOTE, "Unable to open input socket from wiimote: %s", strerror(errno)); close(m_int_sock); @@ -262,7 +262,7 @@ int WiimoteLinux::IORead(u8* buf) { // This can happen if the bluetooth dongle is disconnected ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. " - "Wiimote %i will be disconnected.", m_index + 1); + "Wiimote %i will be disconnected.", m_index + 1); } r = 0; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 7266b2bc6..dfa201dce 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -116,8 +116,7 @@ void Wiimote::ClearReadQueue() // The "Clear" function isn't thread-safe :/ while (m_read_reports.Pop(rpt)) - { - } + {} } void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size) @@ -175,8 +174,8 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const } } else if (rpt[1] == WM_WRITE_SPEAKER_DATA && - (!SConfig::GetInstance().m_WiimoteEnableSpeaker || - (!wm->m_status.speaker || wm->m_speaker_mute))) + (!SConfig::GetInstance().m_WiimoteEnableSpeaker || + (!wm->m_status.speaker || wm->m_speaker_mute))) { // Translate speaker data reports into rumble reports. rpt[1] = WM_RUMBLE; @@ -196,13 +195,13 @@ bool Wiimote::Read() if (result > 0 && m_channel > 0) { if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && - m_index == WIIMOTE_BALANCE_BOARD) + m_index == WIIMOTE_BALANCE_BOARD) { static sf::UdpSocket Socket; Socket.send((char*)rpt.data(), - rpt.size(), - sf::IpAddress::LocalHost, - SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort); + rpt.size(), + sf::IpAddress::LocalHost, + SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort); } // Add it to queue @@ -308,22 +307,22 @@ void Wiimote::Prepare(int _index) bool Wiimote::PrepareOnThread() { // core buttons, no continuous reporting - u8 static const mode_report[] = { WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE }; + u8 static const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE}; // Set the active LEDs and turn on rumble. - u8 static const led_report[] = { WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (m_index%WIIMOTE_BALANCE_BOARD) | 0x1) }; + u8 static const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (m_index%WIIMOTE_BALANCE_BOARD) | 0x1)}; // Turn off rumble - u8 static const rumble_report[] = { WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0 }; + u8 static const rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0}; // Request status report - u8 static const req_status_report[] = { WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0 }; + u8 static const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; // TODO: check for sane response? return (IOWrite(mode_report, sizeof(mode_report)) && - IOWrite(led_report, sizeof(led_report)) && - (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))) && - IOWrite(req_status_report, sizeof(req_status_report))); + IOWrite(led_report, sizeof(led_report)) && + (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))) && + IOWrite(req_status_report, sizeof(req_status_report))); } void Wiimote::EmuStart() @@ -571,7 +570,7 @@ void LoadSettings() IniFile inifile; inifile.Load(ini_filename); - for (unsigned int i = 0; i dropped on blr. -R5-R12 are volatile -> dropped on blr. -* classic inlining across calls. -* Track which registers a block clobbers without using, then take advantage of this knowledge -when compiling a block that links to that block. -* Track more dependencies between instructions, e.g. avoiding PPC_FP code, single/double -conversion, movddup on non-paired singles, etc where possible. -* Support loads/stores directly from xmm registers in jit_util and the backpatcher; this might -help AMD a lot since gpr/xmm transfers are slower there. -* Smarter register allocation in general; maybe learn to drop values once we know they won't be -used again before being overwritten? -* More flexible reordering; there's limits to how far we can go because of exception handling -and such, but it's currently limited to integer ops only. This can definitely be made better. + * Assume SP is in main RAM (in Wii mode too?) - partly done + * Assume all floating point loads and double precision loads+stores are to/from main ram + (single precision stores can be used in write gather pipe, specialized fast check added) + * AMD only - use movaps instead of movapd when loading ps from memory? + * HLE functions like floorf, sin, memcpy, etc - they can be much faster + * ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching. + CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr. + R5-R12 are volatile -> dropped on blr. + * classic inlining across calls. + * Track which registers a block clobbers without using, then take advantage of this knowledge + when compiling a block that links to that block. + * Track more dependencies between instructions, e.g. avoiding PPC_FP code, single/double + conversion, movddup on non-paired singles, etc where possible. + * Support loads/stores directly from xmm registers in jit_util and the backpatcher; this might + help AMD a lot since gpr/xmm transfers are slower there. + * Smarter register allocation in general; maybe learn to drop values once we know they won't be + used again before being overwritten? + * More flexible reordering; there's limits to how far we can go because of exception handling + and such, but it's currently limited to integer ops only. This can definitely be made better. */ // The BLR optimization is nice, but it means that JITted code can overflow the @@ -494,11 +494,11 @@ void Jit64::Trace() void Jit64::Jit(u32 em_address) { if (GetSpaceLeft() < 0x10000 || - farcode.GetSpaceLeft() < 0x10000 || - trampolines.GetSpaceLeft() < 0x10000 || - blocks.IsFull() || - SConfig::GetInstance().m_LocalCoreStartupParameter.bJITNoBlockCache || - m_clear_cache_asap) + farcode.GetSpaceLeft() < 0x10000 || + trampolines.GetSpaceLeft() < 0x10000 || + blocks.IsFull() || + SConfig::GetInstance().m_LocalCoreStartupParameter.bJITNoBlockCache || + m_clear_cache_asap) { ClearCache(); } @@ -522,6 +522,7 @@ void Jit64::Jit(u32 em_address) jo.enableBlocklink = false; analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); + analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); } Trace(); @@ -603,7 +604,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address); - js.skipnext = false; + js.skipInstructions = 0; js.carryFlagSet = false; js.carryFlagInverted = false; js.assumeNoPairedQuantize = false; @@ -651,12 +652,9 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (i == (code_block.m_num_instructions - 1)) { - // WARNING - cmp->branch merging will screw this up. - js.isLastInstruction = true; - js.next_inst = 0; - js.next_inst_bp = false; if (Profiler::g_ProfileBlocks) { + // WARNING - cmp->branch merging will screw this up. PROFILER_VPUSH; // get end tic PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStop); @@ -664,14 +662,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc PROFILER_UPDATE_TIME(b); PROFILER_VPOP; } - } - else - { - // help peephole optimizations - js.next_inst = ops[i + 1].inst; - js.next_compilerPC = ops[i + 1].address; - js.next_op = &ops[i + 1]; - js.next_inst_bp = SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i + 1].address); + js.isLastInstruction = true; } if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) @@ -856,11 +847,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); } #endif - if (js.skipnext) - { - js.skipnext = false; - i++; // Skip next instruction - } + i += js.skipInstructions; + js.skipInstructions = 0; } u32 function = HLE::GetFunctionIndex(js.blockStart); @@ -919,5 +907,6 @@ void Jit64::EnableOptimization() { analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index 7da231d70..a2d6c3026 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -115,6 +115,7 @@ public: void GenerateConstantOverflow(bool overflow); void GenerateConstantOverflow(s64 val); void GenerateOverflow(); + bool MergeAllowedNextInstructions(int count); void FinalizeCarryOverflow(bool oe, bool inv = false); void FinalizeCarry(Gen::CCFlags cond); void FinalizeCarry(bool ca); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index 5eb13bec7..55de79567 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -346,10 +346,12 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper) int output[4] = { CR_SO, CR_EQ, CR_GT, CR_LT }; // Merge neighboring fcmp and cror (the primary use of cror). - UGeckoInstruction next = js.next_inst; - if (next.OPCD == 19 && next.SUBOP10 == 449 && (next.CRBA >> 2) == crf && (next.CRBB >> 2) == crf && (next.CRBD >> 2) == crf) + UGeckoInstruction next = js.op[1].inst; + if (analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE) && + MergeAllowedNextInstructions(1) && next.OPCD == 19 && next.SUBOP10 == 449 && + (next.CRBA >> 2) == crf && (next.CRBB >> 2) == crf && (next.CRBD >> 2) == crf) { - js.skipnext = true; + js.skipInstructions = 1; js.downcountAmount++; int dst = 3 - (next.CRBD & 3); output[3 - (next.CRBD & 3)] &= ~(1 << dst); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index c0015a19e..57e3d110f 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -50,14 +50,30 @@ void Jit64::GenerateOverflow() SetJumpTarget(exit); } +bool Jit64::MergeAllowedNextInstructions(int count) +{ + if (PowerPC::GetState() == PowerPC::CPU_STEPPING || js.instructionsLeft < count) + return false; + // Be careful: a breakpoint kills flags in between instructions + for (int i = 1; i <= count; i++) + { + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging && + PowerPC::breakpoints.IsAddressBreakPoint(js.op[i].address)) + return false; + if (js.op[i].isBranchTarget) + return false; + } + return true; +} + void Jit64::FinalizeCarry(CCFlags cond) { js.carryFlagSet = false; js.carryFlagInverted = false; if (js.op->wantsCA) { - // Be careful: a breakpoint kills flags in between instructions - if (!js.isLastInstruction && js.next_op->wantsCAInFlags && !js.next_inst_bp) + // Not actually merging instructions, but the effect is equivalent (we can't have breakpoints/etc in between). + if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) { if (cond == CC_C || cond == CC_NC) { @@ -86,7 +102,7 @@ void Jit64::FinalizeCarry(bool ca) js.carryFlagInverted = false; if (js.op->wantsCA) { - if (!js.isLastInstruction && js.next_op->wantsCAInFlags && !js.next_inst_bp) + if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) { if (ca) STC(); @@ -331,7 +347,10 @@ bool Jit64::CheckMergedBranch(int crf) if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE)) return false; - const UGeckoInstruction& next = js.next_inst; + if (!MergeAllowedNextInstructions(1)) + return false; + + const UGeckoInstruction& next = js.op[1].inst; return (((next.OPCD == 16 /* bcx */) || ((next.OPCD == 19) && (next.SUBOP10 == 528) /* bcctrx */) || ((next.OPCD == 19) && (next.SUBOP10 == 16) /* bclrx */)) && @@ -343,33 +362,35 @@ bool Jit64::CheckMergedBranch(int crf) void Jit64::DoMergedBranch() { // Code that handles successful PPC branching. - if (js.next_inst.OPCD == 16) // bcx + const UGeckoInstruction& next = js.op[1].inst; + const u32 nextPC = js.op[1].address; + if (next.OPCD == 16) // bcx { - if (js.next_inst.LK) - MOV(32, M(&LR), Imm32(js.next_compilerPC + 4)); + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); u32 destination; - if (js.next_inst.AA) - destination = SignExt16(js.next_inst.BD << 2); + if (next.AA) + destination = SignExt16(next.BD << 2); else - destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2); - WriteExit(destination, js.next_inst.LK, js.next_compilerPC + 4); + destination = nextPC + SignExt16(next.BD << 2); + WriteExit(destination, next.LK, nextPC + 4); } - else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 528)) // bcctrx + else if ((next.OPCD == 19) && (next.SUBOP10 == 528)) // bcctrx { - if (js.next_inst.LK) - MOV(32, M(&LR), Imm32(js.next_compilerPC + 4)); + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); MOV(32, R(RSCRATCH), M(&CTR)); AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - WriteExitDestInRSCRATCH(js.next_inst.LK, js.next_compilerPC + 4); + WriteExitDestInRSCRATCH(next.LK, nextPC + 4); } - else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 16)) // bclrx + else if ((next.OPCD == 19) && (next.SUBOP10 == 16)) // bclrx { MOV(32, R(RSCRATCH), M(&LR)); if (!m_enable_blr_optimization) AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - if (js.next_inst.LK) - MOV(32, M(&LR), Imm32(js.next_compilerPC + 4)); + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); WriteBLRExit(); } else @@ -381,9 +402,11 @@ void Jit64::DoMergedBranch() void Jit64::DoMergedBranchCondition() { js.downcountAmount++; - js.skipnext = true; - int test_bit = 8 >> (js.next_inst.BI & 3); - bool condition = !!(js.next_inst.BO & BO_BRANCH_IF_TRUE); + js.skipInstructions = 1; + const UGeckoInstruction& next = js.op[1].inst; + int test_bit = 8 >> (next.BI & 3); + bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); + const u32 nextPC = js.op[1].address; gpr.UnlockAll(); gpr.UnlockAllX(); @@ -408,16 +431,18 @@ void Jit64::DoMergedBranchCondition() { gpr.Flush(); fpr.Flush(); - WriteExit(js.next_compilerPC + 4); + WriteExit(nextPC + 4); } } void Jit64::DoMergedBranchImmediate(s64 val) { js.downcountAmount++; - js.skipnext = true; - int test_bit = 8 >> (js.next_inst.BI & 3); - bool condition = !!(js.next_inst.BO & BO_BRANCH_IF_TRUE); + js.skipInstructions = 1; + const UGeckoInstruction& next = js.op[1].inst; + int test_bit = 8 >> (next.BI & 3); + bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); + const u32 nextPC = js.op[1].address; gpr.UnlockAll(); gpr.UnlockAllX(); @@ -441,7 +466,7 @@ void Jit64::DoMergedBranchImmediate(s64 val) { gpr.Flush(); fpr.Flush(); - WriteExit(js.next_compilerPC + 4); + WriteExit(nextPC + 4); } } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index c322c2248..0c0a23acf 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -95,15 +95,12 @@ void Jit64::lXXx(UGeckoInstruction inst) } // PowerPC has no 8-bit sign extended load, but x86 does, so merge extsb with the load if we find it. - if (accessSize == 8 && js.next_inst.OPCD == 31 && js.next_inst.SUBOP10 == 954 && - js.next_inst.RS == inst.RD && js.next_inst.RA == inst.RD && !js.next_inst.Rc) + if (MergeAllowedNextInstructions(1) && accessSize == 8 && js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 954 && + js.op[1].inst.RS == inst.RD && js.op[1].inst.RA == inst.RD && !js.op[1].inst.Rc) { - if (PowerPC::GetState() != PowerPC::CPU_STEPPING) - { - js.downcountAmount++; - js.skipnext = true; - signExtend = true; - } + js.downcountAmount++; + js.skipInstructions = 1; + signExtend = true; } // TODO(ector): Make it dynamically enable/disable idle skipping where appropriate diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index 4327d4c95..275c0b70f 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -20,7 +20,7 @@ using namespace Gen; void Jit64::psq_stXX(UGeckoInstruction inst) { INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); + JITDISABLE(bJITLoadStorePairedOff); s32 offset = inst.SIMM_12; bool indexed = inst.OPCD == 4; @@ -38,7 +38,10 @@ void Jit64::psq_stXX(UGeckoInstruction inst) int storeOffset = 0; gpr.BindToRegister(a, true, update); X64Reg addr = gpr.RX(a); - if (update && js.memcheck) + // TODO: this is kind of ugly :/ we should probably create a universal load/store address calculation + // function that handles all these weird cases, e.g. how non-fastmem loadstores clobber addresses. + bool storeAddress = (update && js.memcheck) || !SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem; + if (storeAddress) { addr = RSCRATCH2; MOV(32, R(addr), gpr.R(a)); @@ -86,11 +89,11 @@ void Jit64::psq_stXX(UGeckoInstruction inst) } BitSet32 registersInUse = CallerSavedRegistersInUse(); - if (update && js.memcheck) + if (update && storeAddress) registersInUse[addr] = true; SafeWriteRegToReg(RSCRATCH, addr, w ? 32 : 64, storeOffset, registersInUse); MemoryExceptionCheck(); - if (update && js.memcheck) + if (update && storeAddress) MOV(32, gpr.R(a), R(addr)); gpr.UnlockAll(); fpr.UnlockAll(); @@ -154,7 +157,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst) void Jit64::psq_lXX(UGeckoInstruction inst) { INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); + JITDISABLE(bJITLoadStorePairedOff); s32 offset = inst.SIMM_12; bool indexed = inst.OPCD == 4; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 1b3772ff5..46aaddb1f 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -282,38 +282,38 @@ void Jit64::mfspr(UGeckoInstruction inst) ADD(64, R(RAX), R(RDX)); MOV(64, PPCSTATE(spr[SPR_TL]), R(RAX)); - // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them - // if we can. - u32 nextIndex = (js.next_inst.SPRU << 5) | (js.next_inst.SPRL & 0x1F); - // Be careful; the actual opcode is for mftb (371), not mfspr (339) - int n = js.next_inst.RD; - if (js.next_inst.OPCD == 31 && js.next_inst.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && - PowerPC::GetState() != PowerPC::CPU_STEPPING && n != d) + if (MergeAllowedNextInstructions(1)) { - js.downcountAmount++; - js.skipnext = true; - gpr.Lock(d, n); - gpr.BindToRegister(d, false); - gpr.BindToRegister(n, false); - if (iIndex == SPR_TL) - MOV(32, gpr.R(d), R(RAX)); - if (nextIndex == SPR_TL) - MOV(32, gpr.R(n), R(RAX)); - SHR(64, R(RAX), Imm8(32)); - if (iIndex == SPR_TU) - MOV(32, gpr.R(d), R(RAX)); - if (nextIndex == SPR_TU) - MOV(32, gpr.R(n), R(RAX)); - } - else - { - gpr.Lock(d); - gpr.BindToRegister(d, false); - if (iIndex == SPR_TU) + const UGeckoInstruction& next = js.op[1].inst; + // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them + // if we can. + u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); + // Be careful; the actual opcode is for mftb (371), not mfspr (339) + int n = next.RD; + if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && n != d) + { + js.downcountAmount++; + js.skipInstructions = 1; + gpr.Lock(d, n); + gpr.BindToRegister(d, false); + gpr.BindToRegister(n, false); + if (iIndex == SPR_TL) + MOV(32, gpr.R(d), R(RAX)); + if (nextIndex == SPR_TL) + MOV(32, gpr.R(n), R(RAX)); SHR(64, R(RAX), Imm8(32)); - MOV(32, gpr.R(d), R(RAX)); + if (iIndex == SPR_TU) + MOV(32, gpr.R(d), R(RAX)); + if (nextIndex == SPR_TU) + MOV(32, gpr.R(n), R(RAX)); + break; + } } - gpr.UnlockAllX(); + gpr.Lock(d); + gpr.BindToRegister(d, false); + if (iIndex == SPR_TU) + SHR(64, R(RAX), Imm8(32)); + MOV(32, gpr.R(d), R(RAX)); break; } case SPR_XER: @@ -341,6 +341,7 @@ void Jit64::mfspr(UGeckoInstruction inst) MOV(32, gpr.R(d), PPCSTATE(spr[iIndex])); break; } + gpr.UnlockAllX(); gpr.UnlockAll(); } diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index b30515c10..49863e010 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -610,16 +610,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc js.downcountAmount += opinfo->numCycles; if (i == (code_block.m_num_instructions - 1)) - { js.isLastInstruction = true; - js.next_inst = 0; - } - else - { - // help peephole optimizations - js.next_inst = ops[i + 1].inst; - js.next_compilerPC = ops[i + 1].address; - } u32 function = HLE::GetFunctionIndex(ops[i].address); if (function != 0) diff --git a/Source/Core/Core/PowerPC/JitArm32/Jit.cpp b/Source/Core/Core/PowerPC/JitArm32/Jit.cpp index e3deb7144..ab796df34 100644 --- a/Source/Core/Core/PowerPC/JitArm32/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm32/Jit.cpp @@ -443,7 +443,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); - js.skipnext = false; + js.skipInstructions = 0; js.compilerPC = nextPC; // Translate instructions @@ -459,13 +459,6 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo { // WARNING - cmp->branch merging will screw this up. js.isLastInstruction = true; - js.next_inst = 0; - } - else - { - // help peephole optimizations - js.next_inst = ops[i + 1].inst; - js.next_compilerPC = ops[i + 1].address; } if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 6f1b08785..543d18658 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -16,6 +16,7 @@ void JitArm64::Init() { AllocCodeSpace(CODE_SIZE); jo.enableBlocklink = true; + jo.optimizeGatherPipe = true; gpr.Init(this); fpr.Init(this); @@ -179,6 +180,14 @@ void JitArm64::WriteExitDestInR(ARM64Reg Reg) BR(EncodeRegTo64(Reg)); } +void JitArm64::DumpCode(const u8* start, const u8* end) +{ + std::string output = ""; + for (u8* code = (u8*)start; code < end; code += 4) + output += StringFromFormat("%08x", Common::swap32(*(u32*)code)); + WARN_LOG(DYNA_REC, "Code dump from %p to %p:\n%s", start, end, output.c_str()); +} + void JitArm64::Run() { CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; @@ -223,7 +232,7 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.blockStart = em_address; js.fifoBytesThisBlock = 0; js.downcountAmount = 0; - js.skipnext = false; + js.skipInstructions = 0; js.curBlock = b; u32 nextPC = em_address; @@ -272,13 +281,21 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB { // WARNING - cmp->branch merging will screw this up. js.isLastInstruction = true; - js.next_inst = 0; } - else + + if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) { - // help peephole optimizations - js.next_inst = ops[i + 1].inst; - js.next_compilerPC = ops[i + 1].address; + js.fifoBytesThisBlock -= 32; + + gpr.Lock(W30); + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + regs_in_use[W30] = 0; + + ABI_PushRegisters(regs_in_use); + MOVI2R(X30, (u64)&GPFifo::CheckGatherPipe); + BLR(X30); + ABI_PopRegisters(regs_in_use); + gpr.Unlock(W30); } if (!ops[i].skip) @@ -294,6 +311,8 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB // If we have a register that will never be used again, flush it. for (int j : ~ops[i].gprInUse) gpr.StoreRegister(j); + for (int j : ~ops[i].fprInUse) + fpr.StoreRegister(j); if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) { diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index b0c4689bf..94e9e945e 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -21,11 +21,13 @@ // Some asserts to make sure we will be able to load everything static_assert(PPCSTATE_OFF(spr[1023]) <= 16380, "LDR(32bit) can't reach the last SPR"); static_assert((PPCSTATE_OFF(ps[0][0]) % 8) == 0, "LDR(64bit VFP) requires FPRs to be 8 byte aligned"); +static_assert(PPCSTATE_OFF(xer_ca) < 4096, "STRB can't store xer_ca!"); +static_assert(PPCSTATE_OFF(xer_so_ov) < 4096, "STRB can't store xer_so_ov!"); class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock { public: - JitArm64() : code_buffer(32000) {} + JitArm64() : code_buffer(32000), m_float_emit(this) {} ~JitArm64() {} void Init(); @@ -80,6 +82,7 @@ public: // Integer void arith_imm(UGeckoInstruction inst); void boolX(UGeckoInstruction inst); + void addx(UGeckoInstruction inst); void extsXx(UGeckoInstruction inst); void cntlzwx(UGeckoInstruction inst); void negx(UGeckoInstruction inst); @@ -87,6 +90,14 @@ public: void cmpl(UGeckoInstruction inst); void cmpi(UGeckoInstruction inst); void cmpli(UGeckoInstruction inst); + void rlwinmx(UGeckoInstruction inst); + void srawix(UGeckoInstruction inst); + void mullwx(UGeckoInstruction inst); + void addic(UGeckoInstruction inst); + void mulli(UGeckoInstruction inst); + void addzex(UGeckoInstruction inst); + void subfx(UGeckoInstruction inst); + void addcx(UGeckoInstruction inst); // System Registers void mtmsr(UGeckoInstruction inst); @@ -97,12 +108,66 @@ public: void mfsrin(UGeckoInstruction inst); void mtsrin(UGeckoInstruction inst); void twx(UGeckoInstruction inst); + void mfspr(UGeckoInstruction inst); + void mftb(UGeckoInstruction inst); + void mtspr(UGeckoInstruction inst); // LoadStore void icbi(UGeckoInstruction inst); void lXX(UGeckoInstruction inst); void stX(UGeckoInstruction inst); + // LoadStore floating point + void lfXX(UGeckoInstruction inst); + void stfXX(UGeckoInstruction inst); + + // Floating point + void fabsx(UGeckoInstruction inst); + void faddsx(UGeckoInstruction inst); + void faddx(UGeckoInstruction inst); + void fmaddsx(UGeckoInstruction inst); + void fmaddx(UGeckoInstruction inst); + void fmrx(UGeckoInstruction inst); + void fmsubsx(UGeckoInstruction inst); + void fmsubx(UGeckoInstruction inst); + void fmulsx(UGeckoInstruction inst); + void fmulx(UGeckoInstruction inst); + void fnabsx(UGeckoInstruction inst); + void fnegx(UGeckoInstruction inst); + void fnmaddsx(UGeckoInstruction inst); + void fnmaddx(UGeckoInstruction inst); + void fnmsubsx(UGeckoInstruction inst); + void fnmsubx(UGeckoInstruction inst); + void fselx(UGeckoInstruction inst); + void fsubsx(UGeckoInstruction inst); + void fsubx(UGeckoInstruction inst); + + // Paired + void ps_abs(UGeckoInstruction inst); + void ps_add(UGeckoInstruction inst); + void ps_div(UGeckoInstruction inst); + void ps_madd(UGeckoInstruction inst); + void ps_madds0(UGeckoInstruction inst); + void ps_madds1(UGeckoInstruction inst); + void ps_merge00(UGeckoInstruction inst); + void ps_merge01(UGeckoInstruction inst); + void ps_merge10(UGeckoInstruction inst); + void ps_merge11(UGeckoInstruction inst); + void ps_mr(UGeckoInstruction inst); + void ps_msub(UGeckoInstruction inst); + void ps_mul(UGeckoInstruction inst); + void ps_muls0(UGeckoInstruction inst); + void ps_muls1(UGeckoInstruction inst); + void ps_nabs(UGeckoInstruction inst); + void ps_nmadd(UGeckoInstruction inst); + void ps_nmsub(UGeckoInstruction inst); + void ps_neg(UGeckoInstruction inst); + void ps_res(UGeckoInstruction inst); + void ps_sel(UGeckoInstruction inst); + void ps_sub(UGeckoInstruction inst); + void ps_sum0(UGeckoInstruction inst); + void ps_sum1(UGeckoInstruction inst); + private: Arm64GPRCache gpr; Arm64FPRCache fpr; @@ -112,6 +177,11 @@ private: PPCAnalyst::CodeBuffer code_buffer; + ARM64FloatEmitter m_float_emit; + + // Dump a memory range of code + void DumpCode(const u8* start, const u8* end); + // The key is the backpatch flags std::map m_backpatch_info; @@ -137,6 +207,8 @@ private: void ComputeRC(Arm64Gen::ARM64Reg reg, int crf = 0); void ComputeRC(u32 imm, int crf = 0); + void ComputeCarry(bool Carry); + void ComputeCarry(); typedef u32 (*Operation)(u32, u32); void reg_imm(u32 d, u32 a, bool binary, u32 value, Operation do_op, void (ARM64XEmitter::*op)(Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, ArithOption), bool Rc = false); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp index 0b813e4b7..ff185214a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp @@ -29,7 +29,8 @@ static void DoBacktrace(uintptr_t access_address, SContext* ctx) for (u64 pc = (ctx->CTX_PC - 32); pc < (ctx->CTX_PC + 32); pc += 16) { pc_memory += StringFromFormat("%08x%08x%08x%08x", - *(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12)); + Common::swap32(*(u32*)pc), Common::swap32(*(u32*)(pc + 4)), + Common::swap32(*(u32*)(pc + 8)), Common::swap32(*(u32*)(pc + 12))); ERROR_LOG(DYNA_REC, "0x%016lx: %08x %08x %08x %08x", pc, *(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12)); @@ -51,10 +52,34 @@ bool JitArm64::DisasmLoadStore(const u8* ptr, u32* flags, ARM64Reg* reg) *flags |= BackPatchInfo::FLAG_SIZE_8; else if (size == 1) // 16-bit *flags |= BackPatchInfo::FLAG_SIZE_16; - else // 32-bit + else if (size == 2) // 32-bit *flags |= BackPatchInfo::FLAG_SIZE_32; + else if (size == 3) // 64-bit + *flags |= BackPatchInfo::FLAG_SIZE_F64; - if (op == 0xE5) // Load + if (op == 0xF5) // NEON LDR + { + if (size == 2) // 32-bit float + { + *flags &= ~BackPatchInfo::FLAG_SIZE_32; + *flags |= BackPatchInfo::FLAG_SIZE_F32; + } + *flags |= BackPatchInfo::FLAG_LOAD; + *reg = (ARM64Reg)(inst & 0x1F); + return true; + } + else if (op == 0xF4) // NEON STR + { + if (size == 2) // 32-bit float + { + *flags &= ~BackPatchInfo::FLAG_SIZE_32; + *flags |= BackPatchInfo::FLAG_SIZE_F32; + } + *flags |= BackPatchInfo::FLAG_STORE; + *reg = (ARM64Reg)(inst & 0x1F); + return true; + } + else if (op == 0xE5) // Load { *flags |= BackPatchInfo::FLAG_LOAD; *reg = (ARM64Reg)(inst & 0x1F); @@ -90,10 +115,38 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem, if (flags & BackPatchInfo::FLAG_STORE && flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) { + ARM64FloatEmitter float_emit(emit); + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + float_emit.FCVT(32, 64, Q0, RS); + float_emit.REV32(8, D0, D0); + trouble_offset = (emit->GetCodePtr() - code_base) / 4; + float_emit.STR(32, INDEX_UNSIGNED, D0, addr, 0); + } + else + { + float_emit.REV64(8, Q0, RS); + trouble_offset = (emit->GetCodePtr() - code_base) / 4; + float_emit.STR(64, INDEX_UNSIGNED, Q0, addr, 0); + } } else if (flags & BackPatchInfo::FLAG_LOAD && flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) { + ARM64FloatEmitter float_emit(emit); + trouble_offset = (emit->GetCodePtr() - code_base) / 4; + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + float_emit.LD1R(32, RS, addr); + float_emit.REV64(8, RS, RS); + float_emit.FCVTL(64, RS, RS); + } + else + { + float_emit.LDR(64, INDEX_UNSIGNED, Q0, addr, 0); + float_emit.REV64(8, Q0, Q0); + float_emit.INS(64, RS, 0, Q0, 0); + } } else if (flags & BackPatchInfo::FLAG_STORE) { @@ -143,10 +196,39 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem, if (flags & BackPatchInfo::FLAG_STORE && flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) { + ARM64FloatEmitter float_emit(emit); + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + float_emit.FCVT(32, 64, Q0, RS); + float_emit.FMOV(32, false, W0, Q0); + emit->MOVI2R(X30, (u64)&Memory::Write_U32); + emit->BLR(X30); + } + else + { + emit->MOVI2R(X30, (u64)&Memory::Write_F64); + float_emit.DUP(64, Q0, RS); + emit->BLR(X30); + } + } else if (flags & BackPatchInfo::FLAG_LOAD && flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) { + ARM64FloatEmitter float_emit(emit); + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + emit->MOVI2R(X30, (u64)&Memory::Read_U32); + emit->BLR(X30); + float_emit.DUP(32, RS, X0); + float_emit.FCVTL(64, RS, RS); + } + else + { + emit->MOVI2R(X30, (u64)&Memory::Read_F64); + emit->BLR(X30); + float_emit.INS(64, RS, 0, X0); + } } else if (flags & BackPatchInfo::FLAG_STORE) { @@ -245,7 +327,8 @@ bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) ctx->CTX_PC = new_pc; // Wipe the top bits of the addr_register - if (flags & BackPatchInfo::FLAG_STORE) + if (flags & BackPatchInfo::FLAG_STORE && + !(flags & BackPatchInfo::FLAG_SIZE_F64)) ctx->CTX_REG(1) &= 0xFFFFFFFFUll; else ctx->CTX_REG(0) &= 0xFFFFFFFFUll; @@ -382,6 +465,46 @@ void JitArm64::InitBackpatch() SetCodePtr(code_base); + m_backpatch_info[flags] = info; + } + // 32bit float + { + flags = + BackPatchInfo::FLAG_LOAD | + BackPatchInfo::FLAG_SIZE_F32; + EmitBackpatchRoutine(this, flags, false, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_slowmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + info.m_fastmem_trouble_inst_offset = + EmitBackpatchRoutine(this, flags, true, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_fastmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + m_backpatch_info[flags] = info; + } + // 64bit float + { + flags = + BackPatchInfo::FLAG_LOAD | + BackPatchInfo::FLAG_SIZE_F64; + EmitBackpatchRoutine(this, flags, false, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_slowmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + info.m_fastmem_trouble_inst_offset = + EmitBackpatchRoutine(this, flags, true, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_fastmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + m_backpatch_info[flags] = info; } } @@ -446,6 +569,46 @@ void JitArm64::InitBackpatch() SetCodePtr(code_base); + m_backpatch_info[flags] = info; + } + // 32bit float + { + flags = + BackPatchInfo::FLAG_STORE | + BackPatchInfo::FLAG_SIZE_F32; + EmitBackpatchRoutine(this, flags, false, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_slowmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + info.m_fastmem_trouble_inst_offset = + EmitBackpatchRoutine(this, flags, true, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_fastmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + m_backpatch_info[flags] = info; + } + // 64bit float + { + flags = + BackPatchInfo::FLAG_STORE | + BackPatchInfo::FLAG_SIZE_F64; + EmitBackpatchRoutine(this, flags, false, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_slowmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + + info.m_fastmem_trouble_inst_offset = + EmitBackpatchRoutine(this, flags, true, false, Q0, X1); + code_end = GetWritableCodePtr(); + info.m_fastmem_size = (code_end - code_base) / 4; + + SetCodePtr(code_base); + m_backpatch_info[flags] = info; } } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp new file mode 100644 index 000000000..a670edccc --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp @@ -0,0 +1,376 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/Arm64Emitter.h" +#include "Common/Common.h" +#include "Common/StringUtil.h" + +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/JitArm64/JitAsm.h" + +using namespace Arm64Gen; + +void JitArm64::fabsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FB); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FABS(64, V0, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::faddsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FB); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + + m_float_emit.FADD(64, VD, VA, VB); + m_float_emit.INS(64, VD, 1, VD, 0); +} + +void JitArm64::faddx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FB); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FADD(64, V0, VA, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::fmaddsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, V0, V0, VB); + m_float_emit.DUP(64, VD, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fmaddx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, V0, V0, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fmrx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FB); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + + m_float_emit.INS(64, VD, 0, VB, 0); +} + +void JitArm64::fmsubsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, V0, V0, VB); + m_float_emit.DUP(64, VD, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fmsubx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, V0, V0, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fmulsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FC); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VC = fpr.R(inst.FC); + ARM64Reg VD = fpr.R(inst.FD); + + m_float_emit.FMUL(64, VD, VA, VC); + m_float_emit.INS(64, VD, 1, VD, 0); +} + +void JitArm64::fmulx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FC); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VC = fpr.R(inst.FC); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::fnabsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FB); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FABS(64, V0, VB); + m_float_emit.FNEG(64, V0, V0); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::fnegx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FB); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FNEG(64, V0, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::fnmaddsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, V0, V0, VB); + m_float_emit.FNEG(64, V0, V0); + m_float_emit.DUP(64, VD, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fnmaddx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, V0, V0, VB); + m_float_emit.FNEG(64, V0, V0); + m_float_emit.INS(64, VD, 0, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fnmsubsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, V0, V0, VB); + m_float_emit.FNEG(64, V0, V0); + m_float_emit.DUP(64, VD, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fnmsubx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, V0, V0, VB); + m_float_emit.FNEG(64, V0, V0); + m_float_emit.INS(64, VD, 0, V0, 0); + fpr.Unlock(V0); +} + +void JitArm64::fselx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + fpr.BindToRegister(inst.FD, + inst.FD == inst.FA || + inst.FD == inst.FB || + inst.FD == inst.FC); + + ARM64Reg V0 = fpr.GetReg(); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VC = gpr.R(inst.FC); + + m_float_emit.FCMPE(VA); + m_float_emit.FCSEL(V0, VC, VB, CC_GE); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} + +void JitArm64::fsubsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FB); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + + m_float_emit.FSUB(64, VD, VA, VB); + m_float_emit.INS(64, VD, 1, VD, 0); +} + +void JitArm64::fsubx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + + fpr.BindToRegister(inst.FD, inst.FD == inst.FA || inst.FD == inst.FB); + ARM64Reg VA = fpr.R(inst.FA); + ARM64Reg VB = fpr.R(inst.FB); + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FSUB(64, V0, VA, VB); + m_float_emit.INS(64, VD, 0, V0, 0); + + fpr.Unlock(V0); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index a1a7ffa00..14da56ec7 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -39,6 +39,28 @@ void JitArm64::ComputeRC(u32 imm, int crf) gpr.Unlock(WA); } +void JitArm64::ComputeCarry(bool Carry) +{ + if (Carry) + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, 1); + STRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); + return; + } + + STRB(INDEX_UNSIGNED, WSP, X29, PPCSTATE_OFF(xer_ca)); +} + +void JitArm64::ComputeCarry() +{ + ARM64Reg WA = gpr.GetReg(); + CSINC(WA, WSP, WSP, CC_CC); + STRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); +} + // Following static functions are used in conjunction with reg_imm static u32 Add(u32 a, u32 b) { @@ -245,6 +267,29 @@ void JitArm64::boolX(UGeckoInstruction inst) } } +void JitArm64::addx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, b = inst.RB, d = inst.RD; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); + gpr.SetImmediate(d, i + j); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + ADD(gpr.R(d), gpr.R(a), gpr.R(b)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } +} + void JitArm64::extsXx(UGeckoInstruction inst) { INSTRUCTION_START @@ -415,3 +460,237 @@ void JitArm64::cmpli(UGeckoInstruction inst) FALLBACK_IF(true); } +void JitArm64::rlwinmx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + + u32 mask = Helper_Mask(inst.MB,inst.ME); + if (gpr.IsImm(inst.RS)) + { + gpr.SetImmediate(inst.RA, _rotl(gpr.GetImm(inst.RS), inst.SH) & mask); + if (inst.Rc) + ComputeRC(gpr.GetImm(inst.RA), 0); + return; + } + + gpr.BindToRegister(inst.RA, inst.RA == inst.RS); + + ARM64Reg WA = gpr.GetReg(); + ArithOption Shift(gpr.R(inst.RS), ST_ROR, 32 - inst.SH); + MOVI2R(WA, mask); + AND(gpr.R(inst.RA), WA, gpr.R(inst.RS), Shift); + gpr.Unlock(WA); + + if (inst.Rc) + ComputeRC(gpr.R(inst.RA), 0); +} + +void JitArm64::srawix(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + + int a = inst.RA; + int s = inst.RS; + int amount = inst.SH; + + if (gpr.IsImm(s)) + { + s32 imm = (s32)gpr.GetImm(s); + gpr.SetImmediate(a, imm >> amount); + + if (amount != 0 && (imm < 0) && (imm << (32 - amount))) + ComputeCarry(true); + else + ComputeCarry(false); + } + else if (amount != 0) + { + gpr.BindToRegister(a, a == s); + ARM64Reg RA = gpr.R(a); + ARM64Reg RS = gpr.R(s); + ARM64Reg WA = gpr.GetReg(); + + ORR(WA, WSP, RS, ArithOption(RS, ST_LSL, 32 - amount)); + ORR(RA, WSP, RS, ArithOption(RS, ST_ASR, amount)); + if (inst.Rc) + ComputeRC(RA, 0); + + ANDS(WSP, WA, RA, ArithOption(RA, ST_LSL, 0)); + CSINC(WA, WSP, WSP, CC_EQ); + STRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); + } + else + { + gpr.BindToRegister(a, a == s); + ARM64Reg RA = gpr.R(a); + ARM64Reg RS = gpr.R(s); + MOV(RA, RS); + STRB(INDEX_UNSIGNED, WSP, X29, PPCSTATE_OFF(xer_ca)); + } +} + +void JitArm64::addic(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + + int a = inst.RA, d = inst.RD; + bool rc = inst.OPCD == 13; + s32 simm = inst.SIMM_16; + u32 imm = (u32)simm; + + if (gpr.IsImm(a)) + { + + u32 i = gpr.GetImm(a); + gpr.SetImmediate(d, i + imm); + + bool has_carry = Interpreter::Helper_Carry(i, imm); + ComputeCarry(has_carry); + if (rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a); + if (imm < 4096) + { + ADDS(gpr.R(d), gpr.R(a), imm); + } + else if (simm > -4096 && simm < 0) + { + SUBS(gpr.R(d), gpr.R(a), std::abs(simm)); + } + else + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, imm); + ADDS(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } + + ComputeCarry(); + if (rc) + ComputeRC(gpr.R(d), 0); + } +} + +void JitArm64::mulli(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, d = inst.RD; + + if (gpr.IsImm(a)) + { + s32 i = (s32)gpr.GetImm(a); + gpr.SetImmediate(d, i * inst.SIMM_16); + } + else + { + gpr.BindToRegister(d, d == a); + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, (u32)(s32)inst.SIMM_16); + MUL(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } +} + +void JitArm64::mullwx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, b = inst.RB, d = inst.RD; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); + gpr.SetImmediate(d, i * j); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + MUL(gpr.R(d), gpr.R(a), gpr.R(b)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } +} + +void JitArm64::addzex(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, d = inst.RD; + + gpr.BindToRegister(d, d == a); + ARM64Reg WA = gpr.GetReg(); + LDRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); + CMP(WA, 1); + CSINC(gpr.R(d), gpr.R(a), gpr.R(a), CC_NEQ); + CMP(gpr.R(d), 0); + gpr.Unlock(WA); + ComputeCarry(); +} + +void JitArm64::subfx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, b = inst.RB, d = inst.RD; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, j - i); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + SUB(gpr.R(d), gpr.R(b), gpr.R(a)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } +} + +void JitArm64::addcx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); + + int a = inst.RA, b = inst.RB, d = inst.RD; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, i * j); + + bool has_carry = Interpreter::Helper_Carry(i, j); + ComputeCarry(has_carry); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + ADDS(gpr.R(d), gpr.R(a), gpr.R(b)); + + ComputeCarry(); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 58c152389..c0a317630 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -41,6 +41,7 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o off_reg = gpr.R(offsetReg); BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); BitSet32 ignore_mask(0); regs_in_use[W0] = 0; regs_in_use[W30] = 0; @@ -114,25 +115,24 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o if (is_immediate) MOVI2R(XA, imm_addr); + if (update) + MOV(gpr.R(addr), addr_reg); + if (is_immediate && Memory::IsRAMAddress(imm_addr)) { EmitBackpatchRoutine(this, flags, true, false, dest_reg, XA); - - if (update) - MOVI2R(up_reg, imm_addr); } else { - if (update) - MOV(up_reg, addr_reg); - // Has a chance of being backpatched which will destroy our state // push and pop everything in this instance ABI_PushRegisters(regs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use); EmitBackpatchRoutine(this, flags, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, dest_reg, XA); + m_float_emit.ABI_PopRegisters(fprs_in_use); ABI_PopRegisters(regs_in_use, ignore_mask); } @@ -155,6 +155,7 @@ void JitArm64::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s reg_dest = gpr.R(dest); BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); regs_in_use[W0] = 0; regs_in_use[W1] = 0; regs_in_use[W30] = 0; @@ -237,10 +238,12 @@ void JitArm64::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s // Has a chance of being backpatched which will destroy our state // push and pop everything in this instance ABI_PushRegisters(regs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use); EmitBackpatchRoutine(this, flags, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, RS, XA); + m_float_emit.ABI_PopRegisters(fprs_in_use); ABI_PopRegisters(regs_in_use); } @@ -321,8 +324,6 @@ void JitArm64::lXX(UGeckoInstruction inst) break; } - FALLBACK_IF(update); - SafeLoadToReg(d, update ? a : (a ? a : -1), offsetReg, flags, offset, update); // LWZ idle skipping diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp new file mode 100644 index 000000000..49c40a905 --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp @@ -0,0 +1,394 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/Arm64Emitter.h" +#include "Common/Common.h" + +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/JitArm64/JitAsm.h" + +using namespace Arm64Gen; + +void JitArm64::lfXX(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + + u32 a = inst.RA, b = inst.RB; + + s32 offset = inst.SIMM_16; + u32 flags = BackPatchInfo::FLAG_LOAD; + bool update = false; + s32 offset_reg = -1; + + switch (inst.OPCD) + { + case 31: + switch (inst.SUBOP10) + { + case 567: // lfsux + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + offset_reg = b; + break; + case 535: // lfsx + flags |= BackPatchInfo::FLAG_SIZE_F32; + offset_reg = b; + break; + case 631: // lfdux + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + offset_reg = b; + break; + case 599: // lfdx + flags |= BackPatchInfo::FLAG_SIZE_F64; + offset_reg = b; + break; + } + break; + case 49: // lfsu + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + break; + case 48: // lfs + flags |= BackPatchInfo::FLAG_SIZE_F32; + break; + case 51: // lfdu + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + break; + case 50: // lfd + flags |= BackPatchInfo::FLAG_SIZE_F64; + break; + } + + u32 imm_addr = 0; + bool is_immediate = false; + + ARM64Reg VD = fpr.R(inst.FD); + ARM64Reg addr_reg = W0; + + gpr.Lock(W0, W30); + fpr.Lock(Q0); + + if (update) + { + // Always uses RA + if (gpr.IsImm(a) && offset_reg == -1) + { + is_immediate = true; + imm_addr = offset + gpr.GetImm(a); + } + else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else + { + if (offset_reg == -1) + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + else + { + ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); + } + } + } + else + { + if (offset_reg == -1) + { + if (a && gpr.IsImm(a)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + offset; + } + else if (a) + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else if (!a && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(offset_reg); + } + else if (a) + { + ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); + } + else + { + MOV(addr_reg, gpr.R(offset_reg)); + } + } + } + + ARM64Reg XA = EncodeRegTo64(addr_reg); + + if (is_immediate) + MOVI2R(XA, imm_addr); + + if (update) + MOV(gpr.R(a), addr_reg); + + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + BitSet32 fpr_ignore_mask(0); + regs_in_use[W0] = 0; + regs_in_use[W30] = 0; + fprs_in_use[0] = 0; // Q0 + fpr_ignore_mask[VD - Q0] = 1; + + if (is_immediate && Memory::IsRAMAddress(imm_addr)) + { + EmitBackpatchRoutine(this, flags, true, false, VD, XA); + } + else + { + // Has a chance of being backpatched which will destroy our state + // push and pop everything in this instance + ABI_PushRegisters(regs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use); + EmitBackpatchRoutine(this, flags, + SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, + SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, + VD, XA); + m_float_emit.ABI_PopRegisters(fprs_in_use, fpr_ignore_mask); + ABI_PopRegisters(regs_in_use); + } + + gpr.Unlock(W0, W30); + fpr.Unlock(Q0); +} + +void JitArm64::stfXX(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + + u32 a = inst.RA, b = inst.RB; + + s32 offset = inst.SIMM_16; + u32 flags = BackPatchInfo::FLAG_STORE; + bool update = false; + s32 offset_reg = -1; + + switch (inst.OPCD) + { + case 31: + switch (inst.SUBOP10) + { + case 663: // stfsx + flags |= BackPatchInfo::FLAG_SIZE_F32; + offset_reg = b; + break; + case 695: // stfsux + flags |= BackPatchInfo::FLAG_SIZE_F32; + offset_reg = b; + break; + case 727: // stfdx + flags |= BackPatchInfo::FLAG_SIZE_F64; + offset_reg = b; + break; + case 759: // stfdux + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + offset_reg = b; + break; + } + break; + case 53: // stfsu + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + break; + case 52: // stfs + flags |= BackPatchInfo::FLAG_SIZE_F32; + break; + case 55: // stfdu + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + break; + case 54: // stfd + flags |= BackPatchInfo::FLAG_SIZE_F64; + break; + } + + u32 imm_addr = 0; + bool is_immediate = false; + + ARM64Reg V0 = fpr.R(inst.FS); + ARM64Reg addr_reg; + if (flags & BackPatchInfo::FLAG_SIZE_F64) + addr_reg = W0; + else + addr_reg = W1; + + gpr.Lock(W0, W1, W30); + fpr.Lock(Q0); + + if (update) + { + // Always uses RA + if (gpr.IsImm(a) && offset_reg == -1) + { + is_immediate = true; + imm_addr = offset + gpr.GetImm(a); + } + else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else + { + if (offset_reg == -1) + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + else + { + ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); + } + } + } + else + { + if (offset_reg == -1) + { + if (a && gpr.IsImm(a)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + offset; + } + else if (a) + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else if (!a && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(offset_reg); + } + else if (a) + { + ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); + } + else + { + MOV(addr_reg, gpr.R(offset_reg)); + } + } + } + + ARM64Reg XA = EncodeRegTo64(addr_reg); + + if (is_immediate) + MOVI2R(XA, imm_addr); + + if (update) + MOV(gpr.R(a), addr_reg); + + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + regs_in_use[W0] = 0; + regs_in_use[W1] = 0; + regs_in_use[W30] = 0; + fprs_in_use[0] = 0; // Q0 + + if (is_immediate) + { + if ((imm_addr & 0xFFFFF000) == 0xCC008000 && jit->jo.optimizeGatherPipe) + { + int accessSize; + if (flags & BackPatchInfo::FLAG_SIZE_F64) + accessSize = 64; + else + accessSize = 32; + + MOVI2R(X30, (u64)&GPFifo::m_gatherPipeCount); + MOVI2R(X1, (u64)GPFifo::m_gatherPipe); + LDR(INDEX_UNSIGNED, W0, X30, 0); + ADD(X1, X1, X0); + if (accessSize == 64) + { + m_float_emit.REV64(8, Q0, V0); + m_float_emit.STR(64, INDEX_UNSIGNED, Q0, X1, 0); + } + else if (accessSize == 32) + { + m_float_emit.FCVT(32, 64, Q0, V0); + m_float_emit.REV32(8, D0, D0); + m_float_emit.STR(32, INDEX_UNSIGNED, D0, X1, 0); + } + ADD(W0, W0, accessSize >> 3); + STR(INDEX_UNSIGNED, W0, X30, 0); + jit->js.fifoBytesThisBlock += accessSize >> 3; + + } + else if (Memory::IsRAMAddress(imm_addr)) + { + EmitBackpatchRoutine(this, flags, true, false, V0, XA); + } + else + { + ABI_PushRegisters(regs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use); + EmitBackpatchRoutine(this, flags, false, false, V0, XA); + m_float_emit.ABI_PopRegisters(fprs_in_use); + ABI_PopRegisters(regs_in_use); + } + } + else + { + // Has a chance of being backpatched which will destroy our state + // push and pop everything in this instance + ABI_PushRegisters(regs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use); + EmitBackpatchRoutine(this, flags, + SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, + SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, + V0, XA); + m_float_emit.ABI_PopRegisters(fprs_in_use); + ABI_PopRegisters(regs_in_use); + } + gpr.Unlock(W0, W1, W30); + fpr.Unlock(Q0); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp new file mode 100644 index 000000000..e90ee63c6 --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp @@ -0,0 +1,495 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/Arm64Emitter.h" +#include "Common/Common.h" +#include "Common/StringUtil.h" + +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/JitArm64/JitAsm.h" + +using namespace Arm64Gen; + +void JitArm64::ps_abs(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == b); + + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FABS(64, VD, VB); +} + +void JitArm64::ps_add(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FADD(64, VD, VA, VB); +} + +void JitArm64::ps_div(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FDIV(64, VD, VA, VB); +} + +void JitArm64::ps_madd(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, VD, V0, VB); + + fpr.Unlock(V0); +} + +void JitArm64::ps_madds0(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VC, 0); + m_float_emit.FMUL(64, V0, V0, VA); + m_float_emit.FADD(64, VD, V0, VB); + + fpr.Unlock(V0); +} + +void JitArm64::ps_madds1(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VC, 1); + m_float_emit.FMUL(64, V0, V0, VA); + m_float_emit.FADD(64, VD, V0, VB); + + fpr.Unlock(V0); +} + +void JitArm64::ps_merge00(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.TRN1(64, VD, VA, VB); +} + +void JitArm64::ps_merge01(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.INS(64, VD, 0, VA, 0); + m_float_emit.INS(64, VD, 1, VB, 1); +} + +void JitArm64::ps_merge10(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + if (d != a && d != b) + { + m_float_emit.INS(64, VD, 0, VA, 1); + m_float_emit.INS(64, VD, 1, VB, 0); + } + else + { + ARM64Reg V0 = fpr.GetReg(); + m_float_emit.INS(64, V0, 0, VA, 1); + m_float_emit.INS(64, V0, 1, VB, 0); + m_float_emit.ORR(VD, V0, V0); + fpr.Unlock(V0); + } +} + +void JitArm64::ps_merge11(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.TRN2(64, VD, VA, VB); +} + +void JitArm64::ps_mr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 b = inst.FB, d = inst.FD; + + if (d == b) + return; + + fpr.BindToRegister(d, false); + + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.ORR(VD, VB, VB); +} + +void JitArm64::ps_mul(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FMUL(64, VD, VA, VC); +} + +void JitArm64::ps_muls0(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VC, 0); + m_float_emit.FMUL(64, VD, VA, V0); + fpr.Unlock(V0); +} + +void JitArm64::ps_muls1(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VC, 1); + m_float_emit.FMUL(64, VD, VA, V0); + fpr.Unlock(V0); +} + +void JitArm64::ps_msub(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, VD, V0, VB); + + fpr.Unlock(V0); +} + +void JitArm64::ps_nabs(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == b); + + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FABS(64, VD, VB); + m_float_emit.FNEG(64, VD, VD); +} + +void JitArm64::ps_neg(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == b); + + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FNEG(64, VD, VB); +} + +void JitArm64::ps_nmadd(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FADD(64, VD, V0, VB); + m_float_emit.FNEG(64, VD, VD); + + fpr.Unlock(V0); +} + +void JitArm64::ps_nmsub(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.FMUL(64, V0, VA, VC); + m_float_emit.FSUB(64, VD, V0, VB); + m_float_emit.FNEG(64, VD, VD); + + fpr.Unlock(V0); +} + +void JitArm64::ps_res(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == b); + + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FRSQRTE(64, VD, VB); +} + +void JitArm64::ps_sel(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + + if (d != a && d != b && d != c) + { + m_float_emit.FCMGE(64, VD, VA); + m_float_emit.BSL(VD, VC, VB); + } + else + { + ARM64Reg V0 = fpr.GetReg(); + m_float_emit.FCMGE(64, V0, VA); + m_float_emit.BSL(V0, VC, VB); + m_float_emit.ORR(VD, V0, V0); + fpr.Unlock(V0); + } +} + +void JitArm64::ps_sub(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VD = fpr.R(d); + + m_float_emit.FSUB(64, VD, VA, VB); +} + +void JitArm64::ps_sum0(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VB, 1); + if (d != c) + { + m_float_emit.FADD(64, VD, V0, VA); + m_float_emit.INS(64, VD, 1, VC, 1); + } + else + { + m_float_emit.FADD(64, V0, V0, VA); + m_float_emit.INS(64, VD, 0, V0, 0); + } + + fpr.Unlock(V0); +} + +void JitArm64::ps_sum1(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + fpr.BindToRegister(d, d == a || d == b || d == c); + + ARM64Reg VA = fpr.R(a); + ARM64Reg VB = fpr.R(b); + ARM64Reg VC = fpr.R(c); + ARM64Reg VD = fpr.R(d); + ARM64Reg V0 = fpr.GetReg(); + + m_float_emit.DUP(64, V0, VA, 0); + if (d != c) + { + m_float_emit.FADD(64, VD, V0, VB); + m_float_emit.INS(64, VD, 0, VC, 0); + } + else + { + m_float_emit.FADD(64, V0, V0, VB); + m_float_emit.INS(64, VD, 1, V0, 1); + } + + fpr.Unlock(V0); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index fc7fc952d..0abcb29ab 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -10,6 +10,7 @@ using namespace Arm64Gen; void Arm64RegCache::Init(ARM64XEmitter *emitter) { m_emit = emitter; + m_float_emit.reset(new ARM64FloatEmitter(m_emit)); GetAllocationOrder(); } @@ -56,6 +57,23 @@ void Arm64RegCache::UnlockRegister(ARM64Reg host_reg) reg->Unlock(); } +void Arm64RegCache::FlushMostStaleRegister() +{ + u32 most_stale_preg = 0; + u32 most_stale_amount = 0; + for (u32 i = 0; i < 32; ++i) + { + u32 last_used = m_guest_registers[i].GetLastUsed(); + if (last_used > most_stale_amount && + m_guest_registers[i].GetType() == REG_REG) + { + most_stale_preg = i; + most_stale_amount = last_used; + } + } + FlushRegister(most_stale_preg, false); +} + // GPR Cache void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats &stats) { @@ -212,23 +230,6 @@ void Arm64GPRCache::GetAllocationOrder() m_host_registers.push_back(HostReg(reg)); } -void Arm64GPRCache::FlushMostStaleRegister() -{ - u32 most_stale_preg = 0; - u32 most_stale_amount = 0; - for (u32 i = 0; i < 32; ++i) - { - u32 last_used = m_guest_registers[i].GetLastUsed(); - if (last_used > most_stale_amount && - m_guest_registers[i].GetType() == REG_REG) - { - most_stale_preg = i; - most_stale_amount = last_used; - } - } - FlushRegister(most_stale_preg, false); -} - BitSet32 Arm64GPRCache::GetCallerSavedUsed() { BitSet32 registers(0); @@ -254,35 +255,120 @@ void Arm64GPRCache::FlushByHost(ARM64Reg host_reg) // FPR Cache void Arm64FPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op) { - // XXX: Flush our stuff + for (int i = 0; i < 32; ++i) + { + bool flush = true; + if (mode == FLUSH_INTERPRETER) + { + if (!(op->regsOut[i] || op->regsIn[i])) + { + // This interpreted instruction doesn't use this register + flush = false; + } + } + + if (m_guest_registers[i].GetType() == REG_REG) + { + // Has to be flushed if it isn't in a callee saved register + ARM64Reg host_reg = m_guest_registers[i].GetReg(); + if (flush || !IsCalleeSaved(host_reg)) + FlushRegister(i, mode == FLUSH_MAINTAIN_STATE); + } + } } ARM64Reg Arm64FPRCache::R(u32 preg) { - // XXX: return a host reg holding a guest register + OpArg& reg = m_guest_registers[preg]; + IncrementAllUsed(); + reg.ResetLastUsed(); + + switch (reg.GetType()) + { + case REG_REG: // already in a reg + return reg.GetReg(); + break; + case REG_NOTLOADED: // Register isn't loaded at /all/ + { + ARM64Reg host_reg = GetReg(); + reg.LoadToReg(host_reg); + m_float_emit->LDR(128, INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(ps[preg][0])); + return host_reg; + } + break; + default: + _dbg_assert_msg_(DYNA_REC, false, "Invalid OpArg Type!"); + break; + } + // We've got an issue if we end up here + return INVALID_REG; +} + +void Arm64FPRCache::BindToRegister(u32 preg, bool do_load) +{ + OpArg& reg = m_guest_registers[preg]; + + if (reg.GetType() == REG_NOTLOADED) + { + ARM64Reg host_reg = GetReg(); + reg.LoadToReg(host_reg); + if (do_load) + m_float_emit->LDR(128, INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(ps[preg][0])); + } } void Arm64FPRCache::GetAllocationOrder() { const std::vector allocation_order = { - D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, - D11, D12, D13, D14, D15, D16, D17, D18, D19, - D20, D21, D22, D23, D24, D25, D26, D27, D28, - D29, D30, D31, + // Callee saved + Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, + + // Caller saved + Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, + Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, + Q7, Q6, Q5, Q4, Q3, Q2, Q1, Q0 }; for (ARM64Reg reg : allocation_order) m_host_registers.push_back(HostReg(reg)); } -void Arm64FPRCache::FlushMostStaleRegister() -{ - // XXX: Flush a register -} - void Arm64FPRCache::FlushByHost(ARM64Reg host_reg) { // XXX: Scan guest registers and flush if found } +bool Arm64FPRCache::IsCalleeSaved(ARM64Reg reg) +{ + static std::vector callee_regs = + { + Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, INVALID_REG, + }; + return std::find(callee_regs.begin(), callee_regs.end(), EncodeRegTo64(reg)) != callee_regs.end(); +} + +void Arm64FPRCache::FlushRegister(u32 preg, bool maintain_state) +{ + OpArg& reg = m_guest_registers[preg]; + if (reg.GetType() == REG_REG) + { + ARM64Reg host_reg = reg.GetReg(); + + m_float_emit->STR(128, INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(ps[preg][0])); + if (!maintain_state) + { + UnlockRegister(host_reg); + reg.Flush(); + } + } +} + +BitSet32 Arm64FPRCache::GetCallerSavedUsed() +{ + BitSet32 registers(0); + for (auto& it : m_host_registers) + if (it.IsLocked()) + registers[Q0 - it.GetReg()] = 1; + return registers; +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index d032a16f8..115fad072 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -119,7 +119,7 @@ private: class Arm64RegCache { public: - Arm64RegCache() : m_emit(nullptr), m_reg_stats(nullptr) {}; + Arm64RegCache() : m_emit(nullptr), m_float_emit(nullptr), m_reg_stats(nullptr) {}; virtual ~Arm64RegCache() {}; void Init(ARM64XEmitter *emitter); @@ -133,10 +133,14 @@ public: // Will dump an immediate to the host register as well virtual ARM64Reg R(u32 reg) = 0; + virtual BitSet32 GetCallerSavedUsed() = 0; + // Returns a temporary register for use // Requires unlocking after done ARM64Reg GetReg(); + void StoreRegister(u32 preg) { FlushRegister(preg, false); } + // Locks a register so a cache cannot use it // Useful for function calls template @@ -166,7 +170,7 @@ protected: virtual void GetAllocationOrder() = 0; // Flushes the most stale register - virtual void FlushMostStaleRegister() = 0; + void FlushMostStaleRegister(); // Lock a register void LockRegister(ARM64Reg host_reg); @@ -177,15 +181,31 @@ protected: // Flushes a guest register by host provided virtual void FlushByHost(ARM64Reg host_reg) = 0; + virtual void FlushRegister(u32 preg, bool maintain_state) = 0; + // Get available host registers u32 GetUnlockedRegisterCount(); + void IncrementAllUsed() + { + for (auto& reg : m_guest_registers) + reg.IncrementLastUsed(); + } + // Code emitter ARM64XEmitter *m_emit; + // Float emitter + std::unique_ptr m_float_emit; + // Host side registers that hold the host registers in order of use std::vector m_host_registers; + // Our guest GPRs + // PowerPC has 32 GPRs + // PowerPC also has 32 paired FPRs + OpArg m_guest_registers[32]; + // Register stats for the current block PPCAnalyst::BlockRegStats *m_reg_stats; }; @@ -215,34 +235,20 @@ public: void BindToRegister(u32 preg, bool do_load); - void StoreRegister(u32 preg) { FlushRegister(preg, false); } - - BitSet32 GetCallerSavedUsed(); + BitSet32 GetCallerSavedUsed() override; protected: // Get the order of the host registers void GetAllocationOrder(); - // Flushes the most stale register - void FlushMostStaleRegister(); - // Flushes a guest register by host provided void FlushByHost(ARM64Reg host_reg) override; - // Our guest GPRs - // PowerPC has 32 GPRs - OpArg m_guest_registers[32]; + void FlushRegister(u32 preg, bool maintain_state) override; private: bool IsCalleeSaved(ARM64Reg reg); - void IncrementAllUsed() - { - for (auto& reg : m_guest_registers) - reg.IncrementLastUsed(); - } - - void FlushRegister(u32 preg, bool maintain_state); }; class Arm64FPRCache : public Arm64RegCache @@ -256,17 +262,19 @@ public: // Will dump an immediate to the host register as well ARM64Reg R(u32 preg); + void BindToRegister(u32 preg, bool do_load); + + BitSet32 GetCallerSavedUsed() override; + protected: // Get the order of the host registers void GetAllocationOrder(); - // Flushes the most stale register - void FlushMostStaleRegister(); - // Flushes a guest register by host provided void FlushByHost(ARM64Reg host_reg) override; - // Our guest FPRs - // Gekko has 32 paired registers(32x2) - OpArg m_guest_registers[32][2]; + void FlushRegister(u32 preg, bool maintain_state) override; + +private: + bool IsCalleeSaved(ARM64Reg reg); }; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index ea6ea6c46..01df60015 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -196,3 +196,90 @@ void JitArm64::twx(UGeckoInstruction inst) WriteExit(js.compilerPC + 4); } } + +void JitArm64::mfspr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + switch (iIndex) + { + case SPR_XER: + case SPR_WPAR: + case SPR_DEC: + case SPR_TL: + case SPR_TU: + FALLBACK_IF(true); + default: + gpr.BindToRegister(inst.RD, false); + ARM64Reg RD = gpr.R(inst.RD); + LDR(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(spr) + iIndex * 4); + break; + } +} + +void JitArm64::mftb(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + mfspr(inst); +} + +void JitArm64::mtspr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + + switch (iIndex) + { + case SPR_DMAU: + + case SPR_SPRG0: + case SPR_SPRG1: + case SPR_SPRG2: + case SPR_SPRG3: + + case SPR_SRR0: + case SPR_SRR1: + // These are safe to do the easy way, see the bottom of this function. + break; + + case SPR_LR: + case SPR_CTR: + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + // These are safe to do the easy way, see the bottom of this function. + break; + case SPR_XER: + { + FALLBACK_IF(true); + ARM64Reg RD = gpr.R(inst.RD); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg mask = gpr.GetReg(); + MOVI2R(mask, 0xFF7F); + AND(WA, RD, mask, ArithOption(mask, ST_LSL, 0)); + STRH(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_stringctrl)); + UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT); + STRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); + UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT + STRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_so_ov)); + gpr.Unlock(WA, mask); + } + break; + default: + FALLBACK_IF(true); + } + + // OK, this is easy. + ARM64Reg RD = gpr.R(inst.RD); + STR(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(spr) + iIndex * 4); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index 04ed7e7be..f1087a27c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -45,17 +45,17 @@ static GekkoOPTemplate primarytable[] = {3, &JitArm64::twx}, //"twi", OPTYPE_SYSTEM, FL_ENDBLOCK}}, {17, &JitArm64::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, - {7, &JitArm64::FallBackToInterpreter}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, + {7, &JitArm64::mulli}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, {8, &JitArm64::FallBackToInterpreter}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, {10, &JitArm64::cmpli}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, {11, &JitArm64::cmpi}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, - {12, &JitArm64::FallBackToInterpreter}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, - {13, &JitArm64::FallBackToInterpreter}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, + {12, &JitArm64::addic}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, + {13, &JitArm64::addic}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, {14, &JitArm64::arith_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, {15, &JitArm64::arith_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, {20, &JitArm64::FallBackToInterpreter}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}}, - {21, &JitArm64::FallBackToInterpreter}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {21, &JitArm64::rlwinmx}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {23, &JitArm64::FallBackToInterpreter}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}}, {24, &JitArm64::arith_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, @@ -84,15 +84,15 @@ static GekkoOPTemplate primarytable[] = {46, &JitArm64::FallBackToInterpreter}, //"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, {47, &JitArm64::FallBackToInterpreter}, //"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, - {48, &JitArm64::FallBackToInterpreter}, //"lfs", OPTYPE_LOADFP, FL_IN_A}}, - {49, &JitArm64::FallBackToInterpreter}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, - {50, &JitArm64::FallBackToInterpreter}, //"lfd", OPTYPE_LOADFP, FL_IN_A}}, - {51, &JitArm64::FallBackToInterpreter}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, + {48, &JitArm64::lfXX}, //"lfs", OPTYPE_LOADFP, FL_IN_A}}, + {49, &JitArm64::lfXX}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, + {50, &JitArm64::lfXX}, //"lfd", OPTYPE_LOADFP, FL_IN_A}}, + {51, &JitArm64::lfXX}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, - {52, &JitArm64::FallBackToInterpreter}, //"stfs", OPTYPE_STOREFP, FL_IN_A}}, - {53, &JitArm64::FallBackToInterpreter}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, - {54, &JitArm64::FallBackToInterpreter}, //"stfd", OPTYPE_STOREFP, FL_IN_A}}, - {55, &JitArm64::FallBackToInterpreter}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, + {52, &JitArm64::stfXX}, //"stfs", OPTYPE_STOREFP, FL_IN_A}}, + {53, &JitArm64::stfXX}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, + {54, &JitArm64::stfXX}, //"stfd", OPTYPE_STOREFP, FL_IN_A}}, + {55, &JitArm64::stfXX}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, {56, &JitArm64::FallBackToInterpreter}, //"psq_l", OPTYPE_PS, FL_IN_A}}, {57, &JitArm64::FallBackToInterpreter}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}}, @@ -114,39 +114,39 @@ static GekkoOPTemplate table4[] = { //SUBOP10 {0, &JitArm64::FallBackToInterpreter}, //"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}}, {32, &JitArm64::FallBackToInterpreter}, //"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}}, - {40, &JitArm64::FallBackToInterpreter}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}}, - {136, &JitArm64::FallBackToInterpreter}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}}, - {264, &JitArm64::FallBackToInterpreter}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}}, + {40, &JitArm64::ps_neg}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}}, + {136, &JitArm64::ps_nabs}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}}, + {264, &JitArm64::ps_abs}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}}, {64, &JitArm64::FallBackToInterpreter}, //"ps_cmpu1", OPTYPE_PS, FL_RC_BIT}}, - {72, &JitArm64::FallBackToInterpreter}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}}, + {72, &JitArm64::ps_mr}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}}, {96, &JitArm64::FallBackToInterpreter}, //"ps_cmpo1", OPTYPE_PS, FL_RC_BIT}}, - {528, &JitArm64::FallBackToInterpreter}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}}, - {560, &JitArm64::FallBackToInterpreter}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}}, - {592, &JitArm64::FallBackToInterpreter}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}}, - {624, &JitArm64::FallBackToInterpreter}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}}, + {528, &JitArm64::ps_merge00}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}}, + {560, &JitArm64::ps_merge01}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}}, + {592, &JitArm64::ps_merge10}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}}, + {624, &JitArm64::ps_merge11}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}}, {1014, &JitArm64::FallBackToInterpreter}, //"dcbz_l", OPTYPE_SYSTEM, 0}}, }; static GekkoOPTemplate table4_2[] = { - {10, &JitArm64::FallBackToInterpreter}, //"ps_sum0", OPTYPE_PS, 0}}, - {11, &JitArm64::FallBackToInterpreter}, //"ps_sum1", OPTYPE_PS, 0}}, - {12, &JitArm64::FallBackToInterpreter}, //"ps_muls0", OPTYPE_PS, 0}}, - {13, &JitArm64::FallBackToInterpreter}, //"ps_muls1", OPTYPE_PS, 0}}, - {14, &JitArm64::FallBackToInterpreter}, //"ps_madds0", OPTYPE_PS, 0}}, - {15, &JitArm64::FallBackToInterpreter}, //"ps_madds1", OPTYPE_PS, 0}}, - {18, &JitArm64::FallBackToInterpreter}, //"ps_div", OPTYPE_PS, 0, 16}}, - {20, &JitArm64::FallBackToInterpreter}, //"ps_sub", OPTYPE_PS, 0}}, - {21, &JitArm64::FallBackToInterpreter}, //"ps_add", OPTYPE_PS, 0}}, - {23, &JitArm64::FallBackToInterpreter}, //"ps_sel", OPTYPE_PS, 0}}, - {24, &JitArm64::FallBackToInterpreter}, //"ps_res", OPTYPE_PS, 0}}, - {25, &JitArm64::FallBackToInterpreter}, //"ps_mul", OPTYPE_PS, 0}}, + {10, &JitArm64::ps_sum0}, //"ps_sum0", OPTYPE_PS, 0}}, + {11, &JitArm64::ps_sum1}, //"ps_sum1", OPTYPE_PS, 0}}, + {12, &JitArm64::ps_muls0}, //"ps_muls0", OPTYPE_PS, 0}}, + {13, &JitArm64::ps_muls1}, //"ps_muls1", OPTYPE_PS, 0}}, + {14, &JitArm64::ps_madds0}, //"ps_madds0", OPTYPE_PS, 0}}, + {15, &JitArm64::ps_madds1}, //"ps_madds1", OPTYPE_PS, 0}}, + {18, &JitArm64::ps_div}, //"ps_div", OPTYPE_PS, 0, 16}}, + {20, &JitArm64::ps_sub}, //"ps_sub", OPTYPE_PS, 0}}, + {21, &JitArm64::ps_add}, //"ps_add", OPTYPE_PS, 0}}, + {23, &JitArm64::ps_sel}, //"ps_sel", OPTYPE_PS, 0}}, + {24, &JitArm64::ps_res}, //"ps_res", OPTYPE_PS, 0}}, + {25, &JitArm64::ps_mul}, //"ps_mul", OPTYPE_PS, 0}}, {26, &JitArm64::FallBackToInterpreter}, //"ps_rsqrte", OPTYPE_PS, 0, 1}}, - {28, &JitArm64::FallBackToInterpreter}, //"ps_msub", OPTYPE_PS, 0}}, - {29, &JitArm64::FallBackToInterpreter}, //"ps_madd", OPTYPE_PS, 0}}, - {30, &JitArm64::FallBackToInterpreter}, //"ps_nmsub", OPTYPE_PS, 0}}, - {31, &JitArm64::FallBackToInterpreter}, //"ps_nmadd", OPTYPE_PS, 0}}, + {28, &JitArm64::ps_msub}, //"ps_msub", OPTYPE_PS, 0}}, + {29, &JitArm64::ps_madd}, //"ps_madd", OPTYPE_PS, 0}}, + {30, &JitArm64::ps_nmsub}, //"ps_nmsub", OPTYPE_PS, 0}}, + {31, &JitArm64::ps_nmadd}, //"ps_nmadd", OPTYPE_PS, 0}}, }; @@ -196,7 +196,7 @@ static GekkoOPTemplate table31[] = {954, &JitArm64::extsXx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {536, &JitArm64::FallBackToInterpreter}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {792, &JitArm64::FallBackToInterpreter}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {824, &JitArm64::FallBackToInterpreter}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {824, &JitArm64::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {24, &JitArm64::FallBackToInterpreter}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {54, &JitArm64::FallBackToInterpreter}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, @@ -208,24 +208,24 @@ static GekkoOPTemplate table31[] = {1014, &JitArm64::FallBackToInterpreter}, //"dcbz", OPTYPE_DCACHE, 0, 4}}, //load word - {23, &JitArm64::FallBackToInterpreter}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {55, &JitArm64::FallBackToInterpreter}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {23, &JitArm64::lXX}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {55, &JitArm64::lXX}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, //load halfword - {279, &JitArm64::FallBackToInterpreter}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {311, &JitArm64::FallBackToInterpreter}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {279, &JitArm64::lXX}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {311, &JitArm64::lXX}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, //load halfword signextend - {343, &JitArm64::FallBackToInterpreter}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {375, &JitArm64::FallBackToInterpreter}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {343, &JitArm64::lXX}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {375, &JitArm64::lXX}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, //load byte - {87, &JitArm64::FallBackToInterpreter}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {119, &JitArm64::FallBackToInterpreter}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {87, &JitArm64::lXX}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {119, &JitArm64::lXX}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, //load byte reverse - {534, &JitArm64::FallBackToInterpreter}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {790, &JitArm64::FallBackToInterpreter}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {534, &JitArm64::lXX}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {790, &JitArm64::lXX}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, // Conditional load/store (Wii SMP) {150, &JitArm64::FallBackToInterpreter}, //"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}}, @@ -236,16 +236,16 @@ static GekkoOPTemplate table31[] = {597, &JitArm64::FallBackToInterpreter}, //"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}}, //store word - {151, &JitArm64::FallBackToInterpreter}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {183, &JitArm64::FallBackToInterpreter}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {151, &JitArm64::stX}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {183, &JitArm64::stX}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, //store halfword - {407, &JitArm64::FallBackToInterpreter}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {439, &JitArm64::FallBackToInterpreter}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {407, &JitArm64::stX}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {439, &JitArm64::stX}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, //store byte - {215, &JitArm64::FallBackToInterpreter}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {247, &JitArm64::FallBackToInterpreter}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {215, &JitArm64::stX}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {247, &JitArm64::stX}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, //store bytereverse {662, &JitArm64::FallBackToInterpreter}, //"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, @@ -255,15 +255,15 @@ static GekkoOPTemplate table31[] = {725, &JitArm64::FallBackToInterpreter}, //"stswi", OPTYPE_STORE, FL_EVIL}}, // fp load/store - {535, &JitArm64::FallBackToInterpreter}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, - {567, &JitArm64::FallBackToInterpreter}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, - {599, &JitArm64::FallBackToInterpreter}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, - {631, &JitArm64::FallBackToInterpreter}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, + {535, &JitArm64::lfXX}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, + {567, &JitArm64::lfXX}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, + {599, &JitArm64::lfXX}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, + {631, &JitArm64::lfXX}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, - {663, &JitArm64::FallBackToInterpreter}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, - {695, &JitArm64::FallBackToInterpreter}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, - {727, &JitArm64::FallBackToInterpreter}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, - {759, &JitArm64::FallBackToInterpreter}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, + {663, &JitArm64::stfXX}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, + {695, &JitArm64::stfXX}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, + {727, &JitArm64::stfXX}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, + {759, &JitArm64::stfXX}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, {983, &JitArm64::FallBackToInterpreter}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, {19, &JitArm64::FallBackToInterpreter}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}}, @@ -272,9 +272,9 @@ static GekkoOPTemplate table31[] = {146, &JitArm64::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}}, {210, &JitArm64::mtsr}, //"mtsr", OPTYPE_SYSTEM, 0}}, {242, &JitArm64::mtsrin}, //"mtsrin", OPTYPE_SYSTEM, 0}}, - {339, &JitArm64::FallBackToInterpreter}, //"mfspr", OPTYPE_SPR, FL_OUT_D}}, - {467, &JitArm64::FallBackToInterpreter}, //"mtspr", OPTYPE_SPR, 0, 2}}, - {371, &JitArm64::FallBackToInterpreter}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}}, + {339, &JitArm64::mfspr}, //"mfspr", OPTYPE_SPR, FL_OUT_D}}, + {467, &JitArm64::mtspr}, //"mtspr", OPTYPE_SPR, 0, 2}}, + {371, &JitArm64::mftb}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}}, {512, &JitArm64::FallBackToInterpreter}, //"mcrxr", OPTYPE_SYSTEM, 0}}, {595, &JitArm64::mfsr}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}}, {659, &JitArm64::mfsrin}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}}, @@ -294,25 +294,25 @@ static GekkoOPTemplate table31[] = static GekkoOPTemplate table31_2[] = { - {266, &JitArm64::FallBackToInterpreter}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {778, &JitArm64::FallBackToInterpreter}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {10, &JitArm64::FallBackToInterpreter}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {522, &JitArm64::FallBackToInterpreter}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {266, &JitArm64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {778, &JitArm64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {10, &JitArm64::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {522, &JitArm64::addcx}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {138, &JitArm64::FallBackToInterpreter}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {650, &JitArm64::FallBackToInterpreter}, //"addeox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {234, &JitArm64::FallBackToInterpreter}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {202, &JitArm64::FallBackToInterpreter}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, + {202, &JitArm64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {491, &JitArm64::FallBackToInterpreter}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {1003, &JitArm64::FallBackToInterpreter}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {459, &JitArm64::FallBackToInterpreter}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {971, &JitArm64::FallBackToInterpreter}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {75, &JitArm64::FallBackToInterpreter}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {11, &JitArm64::FallBackToInterpreter}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {235, &JitArm64::FallBackToInterpreter}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {747, &JitArm64::FallBackToInterpreter}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {235, &JitArm64::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {747, &JitArm64::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {104, &JitArm64::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {40, &JitArm64::FallBackToInterpreter}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {552, &JitArm64::FallBackToInterpreter}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {40, &JitArm64::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {552, &JitArm64::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {8, &JitArm64::FallBackToInterpreter}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {520, &JitArm64::FallBackToInterpreter}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {136, &JitArm64::FallBackToInterpreter}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, @@ -323,27 +323,27 @@ static GekkoOPTemplate table31_2[] = static GekkoOPTemplate table59[] = { {18, &JitArm64::FallBackToInterpreter}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}}, - {20, &JitArm64::FallBackToInterpreter}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {21, &JitArm64::FallBackToInterpreter}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {20, &JitArm64::fsubsx}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {21, &JitArm64::faddsx}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, // {22, &JitArm64::FallBackToInterpreter}, //"fsqrtsx", OPTYPE_FPU, FL_RC_BIT_F}}, {24, &JitArm64::FallBackToInterpreter}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitArm64::FallBackToInterpreter}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {28, &JitArm64::FallBackToInterpreter}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {29, &JitArm64::FallBackToInterpreter}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {30, &JitArm64::FallBackToInterpreter}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {31, &JitArm64::FallBackToInterpreter}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitArm64::fmulsx}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {28, &JitArm64::fmsubsx}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {29, &JitArm64::fmaddsx}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {30, &JitArm64::fnmsubsx}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {31, &JitArm64::fnmaddsx}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, }; static GekkoOPTemplate table63[] = { - {264, &JitArm64::FallBackToInterpreter}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {264, &JitArm64::fabsx}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}}, {32, &JitArm64::FallBackToInterpreter}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}}, {0, &JitArm64::FallBackToInterpreter}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}}, {14, &JitArm64::FallBackToInterpreter}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}}, {15, &JitArm64::FallBackToInterpreter}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}}, - {72, &JitArm64::FallBackToInterpreter}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}}, - {136, &JitArm64::FallBackToInterpreter}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {40, &JitArm64::FallBackToInterpreter}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}}, + {72, &JitArm64::fmrx}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}}, + {136, &JitArm64::fnabsx}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {40, &JitArm64::fnegx}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}}, {12, &JitArm64::FallBackToInterpreter}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}}, {64, &JitArm64::FallBackToInterpreter}, //"mcrfs", OPTYPE_SYSTEMFP, 0}}, @@ -357,16 +357,16 @@ static GekkoOPTemplate table63[] = static GekkoOPTemplate table63_2[] = { {18, &JitArm64::FallBackToInterpreter}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}}, - {20, &JitArm64::FallBackToInterpreter}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {21, &JitArm64::FallBackToInterpreter}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}}, + {20, &JitArm64::fsubx}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {21, &JitArm64::faddx}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}}, {22, &JitArm64::FallBackToInterpreter}, //"fsqrtx", OPTYPE_FPU, FL_RC_BIT_F}}, - {23, &JitArm64::FallBackToInterpreter}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitArm64::FallBackToInterpreter}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, + {23, &JitArm64::fselx}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitArm64::fmulx}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, {26, &JitArm64::FallBackToInterpreter}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}}, - {28, &JitArm64::FallBackToInterpreter}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {29, &JitArm64::FallBackToInterpreter}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, - {30, &JitArm64::FallBackToInterpreter}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {31, &JitArm64::FallBackToInterpreter}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, + {28, &JitArm64::fmsubx}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {29, &JitArm64::fmaddx}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, + {30, &JitArm64::fnmsubx}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {31, &JitArm64::fnmaddx}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, }; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp index 2b50a9c11..c7b399551 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp @@ -12,7 +12,7 @@ #define QUANTIZED_REGS_TO_SAVE \ (ABI_ALL_CALLER_SAVED & ~BitSet32 { \ RSCRATCH, RSCRATCH2, RSCRATCH_EXTRA, XMM0+16, XMM1+16 \ - }) + }) #define QUANTIZED_REGS_TO_SAVE_LOAD (QUANTIZED_REGS_TO_SAVE | BitSet32 { RSCRATCH2 }) @@ -196,9 +196,9 @@ const u8 GC_ALIGNED16(pbswapShuffle2x4[16]) = { 3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10 static const float GC_ALIGNED16(m_quantizeTableS[]) = { - (1ULL << 0), (1ULL << 0), (1ULL << 1), (1ULL << 1), (1ULL << 2), (1ULL << 2), (1ULL << 3), (1ULL << 3), - (1ULL << 4), (1ULL << 4), (1ULL << 5), (1ULL << 5), (1ULL << 6), (1ULL << 6), (1ULL << 7), (1ULL << 7), - (1ULL << 8), (1ULL << 8), (1ULL << 9), (1ULL << 9), (1ULL << 10), (1ULL << 10), (1ULL << 11), (1ULL << 11), + (1ULL << 0), (1ULL << 0), (1ULL << 1), (1ULL << 1), (1ULL << 2), (1ULL << 2), (1ULL << 3), (1ULL << 3), + (1ULL << 4), (1ULL << 4), (1ULL << 5), (1ULL << 5), (1ULL << 6), (1ULL << 6), (1ULL << 7), (1ULL << 7), + (1ULL << 8), (1ULL << 8), (1ULL << 9), (1ULL << 9), (1ULL << 10), (1ULL << 10), (1ULL << 11), (1ULL << 11), (1ULL << 12), (1ULL << 12), (1ULL << 13), (1ULL << 13), (1ULL << 14), (1ULL << 14), (1ULL << 15), (1ULL << 15), (1ULL << 16), (1ULL << 16), (1ULL << 17), (1ULL << 17), (1ULL << 18), (1ULL << 18), (1ULL << 19), (1ULL << 19), (1ULL << 20), (1ULL << 20), (1ULL << 21), (1ULL << 21), (1ULL << 22), (1ULL << 22), (1ULL << 23), (1ULL << 23), @@ -215,20 +215,20 @@ static const float GC_ALIGNED16(m_quantizeTableS[]) = 1.0 / (1ULL << 16), 1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), - 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), + 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), }; static const float GC_ALIGNED16(m_dequantizeTableS[]) = { - 1.0 / (1ULL << 0), 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), - 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), - 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), + 1.0 / (1ULL << 0), 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), + 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), + 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), @@ -245,12 +245,12 @@ static const float GC_ALIGNED16(m_dequantizeTableS[]) = (1ULL << 24), (1ULL << 24), (1ULL << 23), (1ULL << 23), (1ULL << 22), (1ULL << 22), (1ULL << 21), (1ULL << 21), (1ULL << 20), (1ULL << 20), (1ULL << 19), (1ULL << 19), (1ULL << 18), (1ULL << 18), (1ULL << 17), (1ULL << 17), (1ULL << 16), (1ULL << 16), (1ULL << 15), (1ULL << 15), (1ULL << 14), (1ULL << 14), (1ULL << 13), (1ULL << 13), - (1ULL << 12), (1ULL << 12), (1ULL << 11), (1ULL << 11), (1ULL << 10), (1ULL << 10), (1ULL << 9), (1ULL << 9), - (1ULL << 8), (1ULL << 8), (1ULL << 7), (1ULL << 7), (1ULL << 6), (1ULL << 6), (1ULL << 5), (1ULL << 5), - (1ULL << 4), (1ULL << 4), (1ULL << 3), (1ULL << 3), (1ULL << 2), (1ULL << 2), (1ULL << 1), (1ULL << 1), + (1ULL << 12), (1ULL << 12), (1ULL << 11), (1ULL << 11), (1ULL << 10), (1ULL << 10), (1ULL << 9), (1ULL << 9), + (1ULL << 8), (1ULL << 8), (1ULL << 7), (1ULL << 7), (1ULL << 6), (1ULL << 6), (1ULL << 5), (1ULL << 5), + (1ULL << 4), (1ULL << 4), (1ULL << 3), (1ULL << 3), (1ULL << 2), (1ULL << 2), (1ULL << 1), (1ULL << 1), }; -static const float GC_ALIGNED16(m_65535[4]) = { 65535.0f, 65535.0f, 65535.0f, 65535.0f }; +static const float GC_ALIGNED16(m_65535[4]) = {65535.0f, 65535.0f, 65535.0f, 65535.0f}; static const float GC_ALIGNED16(m_32767) = 32767.0f; static const float GC_ALIGNED16(m_m32768) = -32768.0f; static const float GC_ALIGNED16(m_255) = 255.0f; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 96dfdf751..6205f7d42 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -65,9 +65,7 @@ protected: struct JitState { u32 compilerPC; - u32 next_compilerPC; u32 blockStart; - UGeckoInstruction next_inst; // for easy peephole opt. int instructionNumber; int instructionsLeft; int downcountAmount; @@ -88,10 +86,9 @@ protected: bool firstFPInstructionFound; bool isLastInstruction; bool memcheck; - bool skipnext; + int skipInstructions; bool carryFlagSet; bool carryFlagInverted; - bool next_inst_bp; int fifoBytesThisBlock; @@ -99,7 +96,6 @@ protected: PPCAnalyst::BlockRegStats gpa; PPCAnalyst::BlockRegStats fpa; PPCAnalyst::CodeOp* op; - PPCAnalyst::CodeOp* next_op; u8* rewriteStart; JitBlock *curBlock; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 25ad70363..f4c84be65 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -23,315 +23,315 @@ using namespace Gen; -bool JitBaseBlockCache::IsFull() const -{ - return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; -} - -void JitBaseBlockCache::Init() -{ - if (m_initialized) + bool JitBaseBlockCache::IsFull() const { - PanicAlert("JitBaseBlockCache::Init() - iCache is already initialized"); - return; + return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; } - JitRegister::Init(); + void JitBaseBlockCache::Init() + { + if (m_initialized) + { + PanicAlert("JitBaseBlockCache::Init() - iCache is already initialized"); + return; + } - iCache.fill(JIT_ICACHE_INVALID_BYTE); - iCacheEx.fill(JIT_ICACHE_INVALID_BYTE); - iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE); - Clear(); + JitRegister::Init(); - m_initialized = true; -} + iCache.fill(JIT_ICACHE_INVALID_BYTE); + iCacheEx.fill(JIT_ICACHE_INVALID_BYTE); + iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE); + Clear(); -void JitBaseBlockCache::Shutdown() -{ - num_blocks = 0; - m_initialized = false; + m_initialized = true; + } - JitRegister::Shutdown(); -} + void JitBaseBlockCache::Shutdown() + { + num_blocks = 0; + m_initialized = false; -// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache -// is full and when saving and loading states. -void JitBaseBlockCache::Clear() -{ + JitRegister::Shutdown(); + } + + // This clears the JIT cache. It's called from JitCache.cpp when the JIT cache + // is full and when saving and loading states. + void JitBaseBlockCache::Clear() + { #if defined(_DEBUG) || defined(DEBUGFAST) - if (IsFull()) - Core::DisplayMessage("Clearing block cache.", 3000); - else - Core::DisplayMessage("Clearing code cache.", 3000); -#endif - jit->js.fifoWriteAddresses.clear(); - jit->js.pairedQuantizeAddresses.clear(); - for (int i = 0; i < num_blocks; i++) - { - DestroyBlock(i, false); - } - links_to.clear(); - block_map.clear(); - - valid_block.ClearAll(); - - num_blocks = 0; - blockCodePointers.fill(nullptr); -} - -void JitBaseBlockCache::Reset() -{ - Shutdown(); - Init(); -} - -JitBlock *JitBaseBlockCache::GetBlock(int no) -{ - return &blocks[no]; -} - -int JitBaseBlockCache::GetNumBlocks() const -{ - return num_blocks; -} - -bool JitBaseBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const -{ - // check if any endpoint is inside the other range - if ((s1 >= s2 && s1 <= e2) || - (e1 >= s2 && e1 <= e2) || - (s2 >= s1 && s2 <= e1) || - (e2 >= s1 && e2 <= e1)) - return true; - else - return false; -} - -int JitBaseBlockCache::AllocateBlock(u32 em_address) -{ - JitBlock &b = blocks[num_blocks]; - b.invalid = false; - b.originalAddress = em_address; - b.linkData.clear(); - num_blocks++; //commit the current block - return num_blocks - 1; -} - -void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr) -{ - blockCodePointers[block_num] = code_ptr; - JitBlock &b = blocks[block_num]; - u32* icp = GetICachePtr(b.originalAddress); - *icp = block_num; - - // Convert the logical address to a physical address for the block map - u32 pAddr = b.originalAddress & 0x1FFFFFFF; - - for (u32 block = pAddr / 32; block <= (pAddr + (b.originalSize - 1) * 4) / 32; ++block) - valid_block.Set(block); - - block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; - - if (block_link) - { - for (const auto& e : b.linkData) - { - links_to.insert(std::pair(e.exitAddress, block_num)); - } - - LinkBlock(block_num); - LinkBlockExits(block_num); - } - - JitRegister::Register(blockCodePointers[block_num], b.codeSize, - "JIT_PPC", b.originalAddress); -} - -const u8 **JitBaseBlockCache::GetCodePointers() -{ - return blockCodePointers.data(); -} - -u32* JitBaseBlockCache::GetICachePtr(u32 addr) -{ - if (addr & JIT_ICACHE_VMEM_BIT) - return (u32*)(&jit->GetBlockCache()->iCacheVMEM[addr & JIT_ICACHE_MASK]); - else if (addr & JIT_ICACHE_EXRAM_BIT) - return (u32*)(&jit->GetBlockCache()->iCacheEx[addr & JIT_ICACHEEX_MASK]); - else - return (u32*)(&jit->GetBlockCache()->iCache[addr & JIT_ICACHE_MASK]); -} - -int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr) -{ - u32 inst = *GetICachePtr(addr); - if (inst & 0xfc000000) // definitely not a JIT block - return -1; - - if ((int)inst >= num_blocks) - return -1; - - if (blocks[inst].originalAddress != addr) - return -1; - - return inst; -} - -CompiledCode JitBaseBlockCache::GetCompiledCodeFromBlock(int block_num) -{ - return (CompiledCode)blockCodePointers[block_num]; -} - -//Block linker -//Make sure to have as many blocks as possible compiled before calling this -//It's O(N), so it's fast :) -//Can be faster by doing a queue for blocks to link up, and only process those -//Should probably be done - -void JitBaseBlockCache::LinkBlockExits(int i) -{ - JitBlock &b = blocks[i]; - if (b.invalid) - { - // This block is dead. Don't relink it. - return; - } - for (auto& e : b.linkData) - { - if (!e.linkStatus) - { - int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress); - if (destinationBlock != -1) - { - WriteLinkBlock(e.exitPtrs, blocks[destinationBlock].checkedEntry); - e.linkStatus = true; - } - } - } -} - -void JitBaseBlockCache::LinkBlock(int i) -{ - LinkBlockExits(i); - JitBlock &b = blocks[i]; - // equal_range(b) returns pair representing the range - // of element with key b - auto ppp = links_to.equal_range(b.originalAddress); - - if (ppp.first == ppp.second) - return; - - for (auto iter = ppp.first; iter != ppp.second; ++iter) - { - // PanicAlert("Linking block %i to block %i", iter->second, i); - LinkBlockExits(iter->second); - } -} - -void JitBaseBlockCache::UnlinkBlock(int i) -{ - JitBlock &b = blocks[i]; - auto ppp = links_to.equal_range(b.originalAddress); - - if (ppp.first == ppp.second) - return; - - for (auto iter = ppp.first; iter != ppp.second; ++iter) - { - JitBlock &sourceBlock = blocks[iter->second]; - for (auto& e : sourceBlock.linkData) - { - if (e.exitAddress == b.originalAddress) - e.linkStatus = false; - } - } - links_to.erase(b.originalAddress); -} - -void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) -{ - if (block_num < 0 || block_num >= num_blocks) - { - PanicAlert("DestroyBlock: Invalid block number %d", block_num); - return; - } - JitBlock &b = blocks[block_num]; - if (b.invalid) - { - if (invalidate) - PanicAlert("Invalidating invalid block %d", block_num); - return; - } - b.invalid = true; - *GetICachePtr(b.originalAddress) = JIT_ICACHE_INVALID_WORD; - - UnlinkBlock(block_num); - - // Send anyone who tries to run this block back to the dispatcher. - // Not entirely ideal, but .. pretty good. - // Spurious entrances from previously linked blocks can only come through checkedEntry - WriteDestroyBlock(b.checkedEntry, b.originalAddress); -} - -void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) -{ - // Convert the logical address to a physical address for the block map - u32 pAddr = address & 0x1FFFFFFF; - - // Optimize the common case of length == 32 which is used by Interpreter::dcb* - bool destroy_block = true; - if (length == 32) - { - if (!valid_block.Test(pAddr / 32)) - destroy_block = false; + if (IsFull()) + Core::DisplayMessage("Clearing block cache.", 3000); else - valid_block.Clear(pAddr / 32); + Core::DisplayMessage("Clearing code cache.", 3000); +#endif + jit->js.fifoWriteAddresses.clear(); + jit->js.pairedQuantizeAddresses.clear(); + for (int i = 0; i < num_blocks; i++) + { + DestroyBlock(i, false); + } + links_to.clear(); + block_map.clear(); + + valid_block.ClearAll(); + + num_blocks = 0; + blockCodePointers.fill(nullptr); } - // destroy JIT blocks - // !! this works correctly under assumption that any two overlapping blocks end at the same address - if (destroy_block) + void JitBaseBlockCache::Reset() { - std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1; - while (it2 != block_map.end() && it2->first.second < pAddr + length) + Shutdown(); + Init(); + } + + JitBlock *JitBaseBlockCache::GetBlock(int no) + { + return &blocks[no]; + } + + int JitBaseBlockCache::GetNumBlocks() const + { + return num_blocks; + } + + bool JitBaseBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const + { + // check if any endpoint is inside the other range + if ((s1 >= s2 && s1 <= e2) || + (e1 >= s2 && e1 <= e2) || + (s2 >= s1 && s2 <= e1) || + (e2 >= s1 && e2 <= e1)) + return true; + else + return false; + } + + int JitBaseBlockCache::AllocateBlock(u32 em_address) + { + JitBlock &b = blocks[num_blocks]; + b.invalid = false; + b.originalAddress = em_address; + b.linkData.clear(); + num_blocks++; //commit the current block + return num_blocks - 1; + } + + void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr) + { + blockCodePointers[block_num] = code_ptr; + JitBlock &b = blocks[block_num]; + u32* icp = GetICachePtr(b.originalAddress); + *icp = block_num; + + // Convert the logical address to a physical address for the block map + u32 pAddr = b.originalAddress & 0x1FFFFFFF; + + for (u32 block = pAddr / 32; block <= (pAddr + (b.originalSize - 1) * 4) / 32; ++block) + valid_block.Set(block); + + block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; + + if (block_link) { - JitBlock &b = blocks[it2->second]; - *GetICachePtr(b.originalAddress) = JIT_ICACHE_INVALID_WORD; - DestroyBlock(it2->second, true); - ++it2; - } - if (it1 != it2) - { - block_map.erase(it1, it2); + for (const auto& e : b.linkData) + { + links_to.insert(std::pair(e.exitAddress, block_num)); + } + + LinkBlock(block_num); + LinkBlockExits(block_num); } - // If the code was actually modified, we need to clear the relevant entries from the - // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't - // be (this can clobber flags, and thus break any optimization that relies on flags - // being in the right place between instructions). - if (!forced) + JitRegister::Register(blockCodePointers[block_num], b.codeSize, + "JIT_PPC", b.originalAddress); + } + + const u8 **JitBaseBlockCache::GetCodePointers() + { + return blockCodePointers.data(); + } + + u32* JitBaseBlockCache::GetICachePtr(u32 addr) + { + if (addr & JIT_ICACHE_VMEM_BIT) + return (u32*)(&jit->GetBlockCache()->iCacheVMEM[addr & JIT_ICACHE_MASK]); + else if (addr & JIT_ICACHE_EXRAM_BIT) + return (u32*)(&jit->GetBlockCache()->iCacheEx[addr & JIT_ICACHEEX_MASK]); + else + return (u32*)(&jit->GetBlockCache()->iCache[addr & JIT_ICACHE_MASK]); + } + + int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr) + { + u32 inst = *GetICachePtr(addr); + if (inst & 0xfc000000) // definitely not a JIT block + return -1; + + if ((int)inst >= num_blocks) + return -1; + + if (blocks[inst].originalAddress != addr) + return -1; + + return inst; + } + + CompiledCode JitBaseBlockCache::GetCompiledCodeFromBlock(int block_num) + { + return (CompiledCode)blockCodePointers[block_num]; + } + + //Block linker + //Make sure to have as many blocks as possible compiled before calling this + //It's O(N), so it's fast :) + //Can be faster by doing a queue for blocks to link up, and only process those + //Should probably be done + + void JitBaseBlockCache::LinkBlockExits(int i) + { + JitBlock &b = blocks[i]; + if (b.invalid) { - for (u32 i = address; i < address + length; i += 4) + // This block is dead. Don't relink it. + return; + } + for (auto& e : b.linkData) + { + if (!e.linkStatus) { - jit->js.fifoWriteAddresses.erase(i); - jit->js.pairedQuantizeAddresses.erase(i); + int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress); + if (destinationBlock != -1) + { + WriteLinkBlock(e.exitPtrs, blocks[destinationBlock].checkedEntry); + e.linkStatus = true; + } } } } -} -void JitBlockCache::WriteLinkBlock(u8* location, const u8* address) -{ - XEmitter emit(location); - if (*location == 0xE8) - emit.CALL(address); - else - emit.JMP(address, true); -} + void JitBaseBlockCache::LinkBlock(int i) + { + LinkBlockExits(i); + JitBlock &b = blocks[i]; + // equal_range(b) returns pair representing the range + // of element with key b + auto ppp = links_to.equal_range(b.originalAddress); -void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address) -{ - XEmitter emit((u8 *)location); - emit.MOV(32, PPCSTATE(pc), Imm32(address)); - emit.JMP(jit->GetAsmRoutines()->dispatcher, true); -} + if (ppp.first == ppp.second) + return; + + for (auto iter = ppp.first; iter != ppp.second; ++iter) + { + // PanicAlert("Linking block %i to block %i", iter->second, i); + LinkBlockExits(iter->second); + } + } + + void JitBaseBlockCache::UnlinkBlock(int i) + { + JitBlock &b = blocks[i]; + auto ppp = links_to.equal_range(b.originalAddress); + + if (ppp.first == ppp.second) + return; + + for (auto iter = ppp.first; iter != ppp.second; ++iter) + { + JitBlock &sourceBlock = blocks[iter->second]; + for (auto& e : sourceBlock.linkData) + { + if (e.exitAddress == b.originalAddress) + e.linkStatus = false; + } + } + links_to.erase(b.originalAddress); + } + + void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) + { + if (block_num < 0 || block_num >= num_blocks) + { + PanicAlert("DestroyBlock: Invalid block number %d", block_num); + return; + } + JitBlock &b = blocks[block_num]; + if (b.invalid) + { + if (invalidate) + PanicAlert("Invalidating invalid block %d", block_num); + return; + } + b.invalid = true; + *GetICachePtr(b.originalAddress) = JIT_ICACHE_INVALID_WORD; + + UnlinkBlock(block_num); + + // Send anyone who tries to run this block back to the dispatcher. + // Not entirely ideal, but .. pretty good. + // Spurious entrances from previously linked blocks can only come through checkedEntry + WriteDestroyBlock(b.checkedEntry, b.originalAddress); + } + + void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) + { + // Convert the logical address to a physical address for the block map + u32 pAddr = address & 0x1FFFFFFF; + + // Optimize the common case of length == 32 which is used by Interpreter::dcb* + bool destroy_block = true; + if (length == 32) + { + if (!valid_block.Test(pAddr / 32)) + destroy_block = false; + else + valid_block.Clear(pAddr / 32); + } + + // destroy JIT blocks + // !! this works correctly under assumption that any two overlapping blocks end at the same address + if (destroy_block) + { + std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1; + while (it2 != block_map.end() && it2->first.second < pAddr + length) + { + JitBlock &b = blocks[it2->second]; + *GetICachePtr(b.originalAddress) = JIT_ICACHE_INVALID_WORD; + DestroyBlock(it2->second, true); + ++it2; + } + if (it1 != it2) + { + block_map.erase(it1, it2); + } + + // If the code was actually modified, we need to clear the relevant entries from the + // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't + // be (this can clobber flags, and thus break any optimization that relies on flags + // being in the right place between instructions). + if (!forced) + { + for (u32 i = address; i < address + length; i += 4) + { + jit->js.fifoWriteAddresses.erase(i); + jit->js.pairedQuantizeAddresses.erase(i); + } + } + } + } + + void JitBlockCache::WriteLinkBlock(u8* location, const u8* address) + { + XEmitter emit(location); + if (*location == 0xE8) + emit.CALL(address); + else + emit.JMP(address, true); + } + + void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address) + { + XEmitter emit((u8 *)location); + emit.MOV(32, PPCSTATE(pc), Imm32(address)); + emit.JMP(jit->GetAsmRoutines()->dispatcher, true); + } diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index b79158037..d3ad76673 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -41,233 +41,233 @@ bool bMMU = false; namespace JitInterface { -void DoState(PointerWrap &p) -{ - if (jit && p.GetMode() == PointerWrap::MODE_READ) - jit->GetBlockCache()->Clear(); -} -CPUCoreBase *InitJitCore(int core) -{ - bMMU = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU; - bFakeVMEM = !bMMU; + void DoState(PointerWrap &p) + { + if (jit && p.GetMode() == PointerWrap::MODE_READ) + jit->GetBlockCache()->Clear(); + } + CPUCoreBase *InitJitCore(int core) + { + bMMU = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU; + bFakeVMEM = !bMMU; - CPUCoreBase *ptr = nullptr; - switch (core) - { -#if _M_X86 - case 1: - { - ptr = new Jit64(); - break; - } - case 2: - { - ptr = new JitIL(); - break; - } -#endif -#if _M_ARM_32 - case 3: - { - ptr = new JitArm(); - break; - } -#endif -#if _M_ARM_64 - case 4: - { - ptr = new JitArm64(); - break; - } -#endif - default: - { - PanicAlert("Unrecognizable cpu_core: %d", core); - jit = nullptr; - return nullptr; - } - } - jit = static_cast(ptr); - jit->Init(); - return ptr; -} -void InitTables(int core) -{ - switch (core) - { -#if _M_X86 - case 1: - { - Jit64Tables::InitTables(); - break; - } - case 2: - { - JitILTables::InitTables(); - break; - } -#endif -#if _M_ARM_32 - case 3: - { - JitArmTables::InitTables(); - break; - } -#endif -#if _M_ARM_64 - case 4: - { - JitArm64Tables::InitTables(); - break; - } -#endif - default: - { - PanicAlert("Unrecognizable cpu_core: %d", core); - break; - } - } -} -CPUCoreBase *GetCore() -{ - return jit; -} - -void WriteProfileResults(const std::string& filename) -{ - // Can't really do this with no jit core available - if (!jit) - return; - - std::vector stats; - stats.reserve(jit->GetBlockCache()->GetNumBlocks()); - u64 cost_sum = 0; - u64 timecost_sum = 0; - u64 countsPerSec; - QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); - for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++) - { - const JitBlock *block = jit->GetBlockCache()->GetBlock(i); - // Rough heuristic. Mem instructions should cost more. - u64 cost = block->originalSize * (block->runCount / 4); - u64 timecost = block->ticCounter; - // Todo: tweak. - if (block->runCount >= 1) - stats.push_back(BlockStat(i, cost)); - cost_sum += cost; - timecost_sum += timecost; - } - - sort(stats.begin(), stats.end()); - File::IOFile f(filename, "w"); - if (!f) - { - PanicAlert("Failed to open %s", filename.c_str()); - return; - } - fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); - for (auto& stat : stats) - { - const JitBlock *block = jit->GetBlockCache()->GetBlock(stat.blockNum); - if (block) + CPUCoreBase *ptr = nullptr; + switch (core) { - std::string name = g_symbolDB.GetDescription(block->originalAddress); - double percent = 100.0 * (double)stat.cost / (double)cost_sum; - double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum; - fprintf(f.GetHandle(), "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n", - block->originalAddress, name.c_str(), stat.cost, - block->ticCounter, percent, timePercent, - (double)block->ticCounter*1000.0 / (double)countsPerSec, block->codeSize); + #if _M_X86 + case 1: + { + ptr = new Jit64(); + break; + } + case 2: + { + ptr = new JitIL(); + break; + } + #endif + #if _M_ARM_32 + case 3: + { + ptr = new JitArm(); + break; + } + #endif + #if _M_ARM_64 + case 4: + { + ptr = new JitArm64(); + break; + } + #endif + default: + { + PanicAlert("Unrecognizable cpu_core: %d", core); + jit = nullptr; + return nullptr; + } + } + jit = static_cast(ptr); + jit->Init(); + return ptr; + } + void InitTables(int core) + { + switch (core) + { + #if _M_X86 + case 1: + { + Jit64Tables::InitTables(); + break; + } + case 2: + { + JitILTables::InitTables(); + break; + } + #endif + #if _M_ARM_32 + case 3: + { + JitArmTables::InitTables(); + break; + } + #endif + #if _M_ARM_64 + case 4: + { + JitArm64Tables::InitTables(); + break; + } + #endif + default: + { + PanicAlert("Unrecognizable cpu_core: %d", core); + break; + } } } -} -bool HandleFault(uintptr_t access_address, SContext* ctx) -{ - return jit->HandleFault(access_address, ctx); -} - -void ClearCache() -{ - if (jit) - jit->ClearCache(); -} -void ClearSafe() -{ - // This clear is "safe" in the sense that it's okay to run from - // inside a JIT'ed block: it clears the instruction cache, but not - // the JIT'ed code. - // TODO: There's probably a better way to handle this situation. - if (jit) - jit->GetBlockCache()->Clear(); -} - -void InvalidateICache(u32 address, u32 size, bool forced) -{ - if (jit) - jit->GetBlockCache()->InvalidateICache(address, size, forced); -} - -u32 ReadOpcodeJIT(u32 _Address) -{ - if (bMMU && !bFakeVMEM && (_Address & Memory::ADDR_MASK_MEM1)) + CPUCoreBase *GetCore() { - _Address = Memory::TranslateAddress(_Address); - if (_Address == 0) + return jit; + } + + void WriteProfileResults(const std::string& filename) + { + // Can't really do this with no jit core available + if (!jit) + return; + + std::vector stats; + stats.reserve(jit->GetBlockCache()->GetNumBlocks()); + u64 cost_sum = 0; + u64 timecost_sum = 0; + u64 countsPerSec; + QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); + for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++) { - return 0; + const JitBlock *block = jit->GetBlockCache()->GetBlock(i); + // Rough heuristic. Mem instructions should cost more. + u64 cost = block->originalSize * (block->runCount / 4); + u64 timecost = block->ticCounter; + // Todo: tweak. + if (block->runCount >= 1) + stats.push_back(BlockStat(i, cost)); + cost_sum += cost; + timecost_sum += timecost; + } + + sort(stats.begin(), stats.end()); + File::IOFile f(filename, "w"); + if (!f) + { + PanicAlert("Failed to open %s", filename.c_str()); + return; + } + fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); + for (auto& stat : stats) + { + const JitBlock *block = jit->GetBlockCache()->GetBlock(stat.blockNum); + if (block) + { + std::string name = g_symbolDB.GetDescription(block->originalAddress); + double percent = 100.0 * (double)stat.cost / (double)cost_sum; + double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum; + fprintf(f.GetHandle(), "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n", + block->originalAddress, name.c_str(), stat.cost, + block->ticCounter, percent, timePercent, + (double)block->ticCounter*1000.0/(double)countsPerSec, block->codeSize); + } + } + } + bool HandleFault(uintptr_t access_address, SContext* ctx) + { + return jit->HandleFault(access_address, ctx); + } + + void ClearCache() + { + if (jit) + jit->ClearCache(); + } + void ClearSafe() + { + // This clear is "safe" in the sense that it's okay to run from + // inside a JIT'ed block: it clears the instruction cache, but not + // the JIT'ed code. + // TODO: There's probably a better way to handle this situation. + if (jit) + jit->GetBlockCache()->Clear(); + } + + void InvalidateICache(u32 address, u32 size, bool forced) + { + if (jit) + jit->GetBlockCache()->InvalidateICache(address, size, forced); + } + + u32 ReadOpcodeJIT(u32 _Address) + { + if (bMMU && !bFakeVMEM && (_Address & Memory::ADDR_MASK_MEM1)) + { + _Address = Memory::TranslateAddress(_Address); + if (_Address == 0) + { + return 0; + } + } + + u32 inst; + // Bypass the icache for the external interrupt exception handler + // -- this is stupid, should respect HID0 + if ( (_Address & 0x0FFFFF00) == 0x00000500 ) + inst = Memory::ReadUnchecked_U32(_Address); + else + inst = PowerPC::ppcState.iCache.ReadInstruction(_Address); + return inst; + } + + void CompileExceptionCheck(ExceptionType type) + { + if (!jit) + return; + + std::unordered_set* exception_addresses = nullptr; + + switch (type) + { + case ExceptionType::EXCEPTIONS_FIFO_WRITE: + exception_addresses = &jit->js.fifoWriteAddresses; + break; + case ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE: + exception_addresses = &jit->js.pairedQuantizeAddresses; + break; + } + + if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end())) + { + if (type == ExceptionType::EXCEPTIONS_FIFO_WRITE) + { + // Check in case the code has been replaced since: do we need to do this? + int optype = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type; + if (optype != OPTYPE_STORE && optype != OPTYPE_STOREFP && (optype != OPTYPE_STOREPS)) + return; + } + exception_addresses->insert(PC); + + // Invalidate the JIT block so that it gets recompiled with the external exception check included. + jit->GetBlockCache()->InvalidateICache(PC, 4, true); } } - u32 inst; - // Bypass the icache for the external interrupt exception handler - // -- this is stupid, should respect HID0 - if ((_Address & 0x0FFFFF00) == 0x00000500) - inst = Memory::ReadUnchecked_U32(_Address); - else - inst = PowerPC::ppcState.iCache.ReadInstruction(_Address); - return inst; -} - -void CompileExceptionCheck(ExceptionType type) -{ - if (!jit) - return; - - std::unordered_set* exception_addresses = nullptr; - - switch (type) + void Shutdown() { - case ExceptionType::EXCEPTIONS_FIFO_WRITE: - exception_addresses = &jit->js.fifoWriteAddresses; - break; - case ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE: - exception_addresses = &jit->js.pairedQuantizeAddresses; - break; - } - - if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end())) - { - if (type == ExceptionType::EXCEPTIONS_FIFO_WRITE) + if (jit) { - // Check in case the code has been replaced since: do we need to do this? - int optype = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type; - if (optype != OPTYPE_STORE && optype != OPTYPE_STOREFP && (optype != OPTYPE_STOREPS)) - return; + jit->Shutdown(); + delete jit; + jit = nullptr; } - exception_addresses->insert(PC); - - // Invalidate the JIT block so that it gets recompiled with the external exception check included. - jit->GetBlockCache()->InvalidateICache(PC, 4, true); } } - -void Shutdown() -{ - if (jit) - { - jit->Shutdown(); - delete jit; - jit = nullptr; - } -} -} diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index b8c001467..5233df6c0 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -31,252 +31,257 @@ namespace PPCAnalyst { - static const int CODEBUFFER_SIZE = 32000; - // 0 does not perform block merging - static const u32 FUNCTION_FOLLOWING_THRESHOLD = 16; +static const int CODEBUFFER_SIZE = 32000; +// 0 does not perform block merging +static const u32 FUNCTION_FOLLOWING_THRESHOLD = 16; - CodeBuffer::CodeBuffer(int size) - { - codebuffer = new PPCAnalyst::CodeOp[size]; - size_ = size; - } +CodeBuffer::CodeBuffer(int size) +{ + codebuffer = new PPCAnalyst::CodeOp[size]; + size_ = size; +} - CodeBuffer::~CodeBuffer() - { - delete[] codebuffer; - } +CodeBuffer::~CodeBuffer() +{ + delete[] codebuffer; +} - void AnalyzeFunction2(Symbol &func); - u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc); +void AnalyzeFunction2(Symbol &func); +u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc); #define INVALID_TARGET ((u32)-1) - u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc) +u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc) +{ + switch (instr.OPCD) { - switch (instr.OPCD) + case 18://branch instruction { - case 18://branch instruction - { - u32 target = SignExt26(instr.LI << 2); + u32 target = SignExt26(instr.LI<<2); if (!instr.AA) target += pc; return target; } - default: - return INVALID_TARGET; - } + default: + return INVALID_TARGET; } +} - //To find the size of each found function, scan - //forward until we hit blr. In the meantime, collect information - //about which functions this function calls. - //Also collect which internal branch goes the farthest - //If any one goes farther than the blr, assume that there is more than - //one blr, and keep scanning. +//To find the size of each found function, scan +//forward until we hit blr. In the meantime, collect information +//about which functions this function calls. +//Also collect which internal branch goes the farthest +//If any one goes farther than the blr, assume that there is more than +//one blr, and keep scanning. - bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size) +bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size) +{ + if (!func.name.size()) + func.name = StringFromFormat("zz_%07x_", startAddr & 0x0FFFFFF); + if (func.analyzed >= 1) + return true; // No error, just already did it. + + func.calls.clear(); + func.callers.clear(); + func.size = 0; + func.flags = FFLAG_LEAF; + u32 addr = startAddr; + + u32 farthestInternalBranchTarget = startAddr; + int numInternalBranches = 0; + while (true) { - if (!func.name.size()) - func.name = StringFromFormat("zz_%07x_", startAddr & 0x0FFFFFF); - if (func.analyzed >= 1) - return true; // No error, just already did it. + func.size += 4; + if (func.size >= CODEBUFFER_SIZE * 4) //weird + return false; - func.calls.clear(); - func.callers.clear(); - func.size = 0; - func.flags = FFLAG_LEAF; - u32 addr = startAddr; - - u32 farthestInternalBranchTarget = startAddr; - int numInternalBranches = 0; - while (true) + UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr); + if (max_size && func.size > max_size) { - func.size += 4; - if (func.size >= CODEBUFFER_SIZE * 4) //weird - return false; - - UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr); - if (max_size && func.size > max_size) - { - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) - func.flags |= FFLAG_STRAIGHT; - return true; - } - if (PPCTables::IsValidInstruction(instr)) - { - if (instr.hex == 0x4e800020) //4e800021 is blrl, not the end of a function - { - //BLR - if (farthestInternalBranchTarget > addr) - { - //bah, not this one, continue.. - } - else - { - //a final blr! - //We're done! Looks like we have a neat valid function. Perfect. - //Let's calc the checksum and get outta here - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) - func.flags |= FFLAG_STRAIGHT; - return true; - } - } - /* - else if ((instr.hex & 0xFC000000) == (0x4b000000 & 0xFC000000) && !instr.LK) - { - u32 target = addr + SignExt26(instr.LI << 2); - if (target < startAddr || (max_size && target > max_size+startAddr)) - { - //block ends by branching away. We're done! - func.size *= 4; // into bytes - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) func.flags |= FFLAG_STRAIGHT; - return true; - } - }*/ - else if (instr.hex == 0x4e800021 || instr.hex == 0x4e800420 || instr.hex == 0x4e800421) + return true; + } + if (PPCTables::IsValidInstruction(instr)) + { + if (instr.hex == 0x4e800020) //4e800021 is blrl, not the end of a function + { + //BLR + if (farthestInternalBranchTarget > addr) { - func.flags &= ~FFLAG_LEAF; - func.flags |= FFLAG_EVIL; - } - else if (instr.hex == 0x4c000064) - { - func.flags &= ~FFLAG_LEAF; - func.flags |= FFLAG_RFI; + //bah, not this one, continue.. } else { - if (instr.OPCD == 16) - { - u32 target = SignExt16(instr.BD << 2); - - if (!instr.AA) - target += addr; - - if (target > farthestInternalBranchTarget && !instr.LK) - { - farthestInternalBranchTarget = target; - } - numInternalBranches++; - } - else - { - u32 target = EvaluateBranchTarget(instr, addr); - if (target != INVALID_TARGET && instr.LK) - { - //we found a branch-n-link! - func.calls.push_back(SCall(target, addr)); - func.flags &= ~FFLAG_LEAF; - } - } + //a final blr! + //We're done! Looks like we have a neat valid function. Perfect. + //Let's calc the checksum and get outta here + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) + func.flags |= FFLAG_STRAIGHT; + return true; } } + /* + else if ((instr.hex & 0xFC000000) == (0x4b000000 & 0xFC000000) && !instr.LK) + { + u32 target = addr + SignExt26(instr.LI << 2); + if (target < startAddr || (max_size && target > max_size+startAddr)) + { + //block ends by branching away. We're done! + func.size *= 4; // into bytes + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) + func.flags |= FFLAG_STRAIGHT; + return true; + } + }*/ + else if (instr.hex == 0x4e800021 || instr.hex == 0x4e800420 || instr.hex == 0x4e800421) + { + func.flags &= ~FFLAG_LEAF; + func.flags |= FFLAG_EVIL; + } + else if (instr.hex == 0x4c000064) + { + func.flags &= ~FFLAG_LEAF; + func.flags |= FFLAG_RFI; + } else { - return false; - } - addr += 4; - } - } - - - // Second pass analysis, done after the first pass is done for all functions - // so we have more information to work with - static void AnalyzeFunction2(Symbol *func) - { - u32 flags = func->flags; - - bool nonleafcall = false; - for (const SCall& c : func->calls) - { - Symbol *called_func = g_symbolDB.GetSymbolFromAddr(c.function); - if (called_func && (called_func->flags & FFLAG_LEAF) == 0) - { - nonleafcall = true; - break; - } - } - - if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI)) - flags |= FFLAG_ONLYCALLSNICELEAFS; - - func->flags = flags; - } - - static bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b) - { - const GekkoOPInfo *a_info = a.opinfo; - const GekkoOPInfo *b_info = b.opinfo; - int a_flags = a_info->flags; - int b_flags = b_info->flags; - if (b_flags & (FL_SET_CRx | FL_ENDBLOCK | FL_TIMER | FL_EVIL | FL_SET_OE)) - return false; - if ((b_flags & (FL_RC_BIT | FL_RC_BIT_F)) && (b.inst.Rc)) - return false; - if ((a_flags & (FL_SET_CA | FL_READ_CA)) && (b_flags & (FL_SET_CA | FL_READ_CA))) - return false; - - switch (b.inst.OPCD) - { - case 16: - case 18: - //branches. Do not swap. - case 17: //sc - case 46: //lmw - case 19: //table19 - lots of tricky stuff - return false; - } - - // For now, only integer ops acceptable. Any instruction which can raise an - // interrupt is *not* a possible swap candidate: see [1] for an example of - // a crash caused by this error. - // - // [1] https://code.google.com/p/dolphin-emu/issues/detail?id=5864#c7 - if (b_info->type != OPTYPE_INTEGER) - return false; - - // Check that we have no register collisions. - // That is, check that none of b's outputs matches any of a's inputs, - // and that none of a's outputs matches any of b's inputs. - // The latter does not apply if a is a cmp, of course, but doesn't hurt to check. - // register collision: b outputs to one of a's inputs - if (b.regsOut & a.regsIn) - return false; - // register collision: a outputs to one of b's inputs - if (a.regsOut & b.regsIn) - return false; - // register collision: b outputs to one of a's outputs (overwriting it) - if (b.regsOut & a.regsOut) - return false; - - return true; - } - - // Most functions that are relevant to analyze should be - // called by another function. Therefore, let's scan the - // entire space for bl operations and find what functions - // get called. - static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB *func_db) - { - for (u32 addr = startAddr; addr < endAddr; addr += 4) - { - UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr); - - if (PPCTables::IsValidInstruction(instr)) - { - switch (instr.OPCD) + if (instr.OPCD == 16) { - case 18://branch instruction + u32 target = SignExt16(instr.BD << 2); + + if (!instr.AA) + target += addr; + + if (target > farthestInternalBranchTarget && !instr.LK) + { + farthestInternalBranchTarget = target; + } + numInternalBranches++; + } + else + { + u32 target = EvaluateBranchTarget(instr, addr); + if (target != INVALID_TARGET && instr.LK) + { + //we found a branch-n-link! + func.calls.push_back(SCall(target,addr)); + func.flags &= ~FFLAG_LEAF; + } + } + } + } + else + { + return false; + } + addr += 4; + } +} + + +// Second pass analysis, done after the first pass is done for all functions +// so we have more information to work with +static void AnalyzeFunction2(Symbol *func) +{ + u32 flags = func->flags; + + bool nonleafcall = false; + for (const SCall& c : func->calls) + { + Symbol *called_func = g_symbolDB.GetSymbolFromAddr(c.function); + if (called_func && (called_func->flags & FFLAG_LEAF) == 0) + { + nonleafcall = true; + break; + } + } + + if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI)) + flags |= FFLAG_ONLYCALLSNICELEAFS; + + func->flags = flags; +} + +static bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b) +{ + const GekkoOPInfo *a_info = a.opinfo; + const GekkoOPInfo *b_info = b.opinfo; + int a_flags = a_info->flags; + int b_flags = b_info->flags; + + // can't reorder around breakpoints + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging && + (PowerPC::breakpoints.IsAddressBreakPoint(a.address) || PowerPC::breakpoints.IsAddressBreakPoint(b.address))) + return false; + if (b_flags & (FL_SET_CRx | FL_ENDBLOCK | FL_TIMER | FL_EVIL | FL_SET_OE)) + return false; + if ((b_flags & (FL_RC_BIT | FL_RC_BIT_F)) && (b.inst.Rc)) + return false; + if ((a_flags & (FL_SET_CA | FL_READ_CA)) && (b_flags & (FL_SET_CA | FL_READ_CA))) + return false; + + switch (b.inst.OPCD) + { + case 16: + case 18: + //branches. Do not swap. + case 17: //sc + case 46: //lmw + case 19: //table19 - lots of tricky stuff + return false; + } + + // For now, only integer ops acceptable. Any instruction which can raise an + // interrupt is *not* a possible swap candidate: see [1] for an example of + // a crash caused by this error. + // + // [1] https://code.google.com/p/dolphin-emu/issues/detail?id=5864#c7 + if (b_info->type != OPTYPE_INTEGER) + return false; + + // Check that we have no register collisions. + // That is, check that none of b's outputs matches any of a's inputs, + // and that none of a's outputs matches any of b's inputs. + // The latter does not apply if a is a cmp, of course, but doesn't hurt to check. + // register collision: b outputs to one of a's inputs + if (b.regsOut & a.regsIn) + return false; + // register collision: a outputs to one of b's inputs + if (a.regsOut & b.regsIn) + return false; + // register collision: b outputs to one of a's outputs (overwriting it) + if (b.regsOut & a.regsOut) + return false; + + return true; +} + +// Most functions that are relevant to analyze should be +// called by another function. Therefore, let's scan the +// entire space for bl operations and find what functions +// get called. +static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB *func_db) +{ + for (u32 addr = startAddr; addr < endAddr; addr+=4) + { + UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr); + + if (PPCTables::IsValidInstruction(instr)) + { + switch (instr.OPCD) + { + case 18://branch instruction { if (instr.LK) //bl { @@ -290,639 +295,640 @@ namespace PPCAnalyst } } break; - default: - break; - } + default: + break; } } } +} - static void FindFunctionsAfterBLR(PPCSymbolDB *func_db) +static void FindFunctionsAfterBLR(PPCSymbolDB *func_db) +{ + std::vector funcAddrs; + + for (const auto& func : func_db->Symbols()) + funcAddrs.push_back(func.second.address + func.second.size); + + for (u32& location : funcAddrs) { - std::vector funcAddrs; - - for (const auto& func : func_db->Symbols()) - funcAddrs.push_back(func.second.address + func.second.size); - - for (u32& location : funcAddrs) - { - while (true) - { - if (PPCTables::IsValidInstruction(Memory::Read_Instruction(location))) - { - //check if this function is already mapped - Symbol *f = func_db->AddFunction(location); - if (!f) - break; - else - location += f->size; - } - else - break; - } - } - } - - void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db) - { - //Step 1: Find all functions - FindFunctionsFromBranches(startAddr, endAddr, func_db); - FindFunctionsAfterBLR(func_db); - - //Step 2: - func_db->FillInCallers(); - - int numLeafs = 0, numNice = 0, numUnNice = 0; - int numTimer = 0, numRFI = 0, numStraightLeaf = 0; - int leafSize = 0, niceSize = 0, unniceSize = 0; - for (auto& func : func_db->AccessSymbols()) - { - if (func.second.address == 4) - { - WARN_LOG(OSHLE, "Weird function"); - continue; - } - AnalyzeFunction2(&(func.second)); - Symbol &f = func.second; - if (f.name.substr(0, 3) == "zzz") - { - if (f.flags & FFLAG_LEAF) - f.name += "_leaf"; - if (f.flags & FFLAG_STRAIGHT) - f.name += "_straight"; - } - if (f.flags & FFLAG_LEAF) - { - numLeafs++; - leafSize += f.size; - } - else if (f.flags & FFLAG_ONLYCALLSNICELEAFS) - { - numNice++; - niceSize += f.size; - } - else - { - numUnNice++; - unniceSize += f.size; - } - - if (f.flags & FFLAG_TIMERINSTRUCTIONS) - numTimer++; - if (f.flags & FFLAG_RFI) - numRFI++; - if ((f.flags & FFLAG_STRAIGHT) && (f.flags & FFLAG_LEAF)) - numStraightLeaf++; - } - if (numLeafs == 0) - leafSize = 0; - else - leafSize /= numLeafs; - - if (numNice == 0) - niceSize = 0; - else - niceSize /= numNice; - - if (numUnNice == 0) - unniceSize = 0; - else - unniceSize /= numUnNice; - - INFO_LOG(OSHLE, "Functions analyzed. %i leafs, %i nice, %i unnice." - "%i timer, %i rfi. %i are branchless leafs.", numLeafs, - numNice, numUnNice, numTimer, numRFI, numStraightLeaf); - INFO_LOG(OSHLE, "Average size: %i (leaf), %i (nice), %i(unnice)", - leafSize, niceSize, unniceSize); - } - - static bool isCmp(const CodeOp& a) - { - return (a.inst.OPCD == 10 || a.inst.OPCD == 11) || (a.inst.OPCD == 31 && (a.inst.SUBOP10 == 0 || a.inst.SUBOP10 == 32)); - } - - static bool isCarryOp(const CodeOp& a) - { - return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && a.opinfo->type == OPTYPE_INTEGER; - } - - static bool isCror(const CodeOp& a) - { - return a.inst.OPCD == 19 && a.inst.SUBOP10 == 449; - } - - void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type) - { - // Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do - // multiple passes. while (true) { - // Instruction Reordering Pass - // Carry pass: bubble carry-using instructions as close to each other as possible, so we can avoid - // storing the carry flag. - // Compare pass: bubble compare instructions next to branches, so they can be merged. - bool swapped = false; - int increment = reverse ? -1 : 1; - int start = reverse ? instructions - 1 : 0; - int end = reverse ? 0 : instructions - 1; - for (int i = start; i != end; i += increment) + if (PPCTables::IsValidInstruction(Memory::Read_Instruction(location))) { - CodeOp &a = code[i]; - CodeOp &b = code[i + increment]; - // Reorder integer compares, rlwinm., and carry-affecting ops - // (if we add more merged branch instructions, add them here!) - if ((type == REORDER_CROR && isCror(a)) || (type == REORDER_CARRY && isCarryOp(a)) || (type == REORDER_CMP && (isCmp(a) || a.outputCR0))) - { - // once we're next to a carry instruction, don't move away! - if (type == REORDER_CARRY && i != start) - { - // if we read the CA flag, and the previous instruction sets it, don't move away. - if (!reverse && (a.opinfo->flags & FL_READ_CA) && (code[i - increment].opinfo->flags & FL_SET_CA)) - continue; - // if we set the CA flag, and the next instruction reads it, don't move away. - if (reverse && (a.opinfo->flags & FL_SET_CA) && (code[i - increment].opinfo->flags & FL_READ_CA)) - continue; - } + //check if this function is already mapped + Symbol *f = func_db->AddFunction(location); + if (!f) + break; + else + location += f->size; + } + else + break; + } + } +} - if (CanSwapAdjacentOps(a, b)) - { - // Alright, let's bubble it! - std::swap(a, b); - swapped = true; - } +void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db) +{ + //Step 1: Find all functions + FindFunctionsFromBranches(startAddr, endAddr, func_db); + FindFunctionsAfterBLR(func_db); + + //Step 2: + func_db->FillInCallers(); + + int numLeafs = 0, numNice = 0, numUnNice = 0; + int numTimer = 0, numRFI = 0, numStraightLeaf = 0; + int leafSize = 0, niceSize = 0, unniceSize = 0; + for (auto& func : func_db->AccessSymbols()) + { + if (func.second.address == 4) + { + WARN_LOG(OSHLE, "Weird function"); + continue; + } + AnalyzeFunction2(&(func.second)); + Symbol &f = func.second; + if (f.name.substr(0, 3) == "zzz") + { + if (f.flags & FFLAG_LEAF) + f.name += "_leaf"; + if (f.flags & FFLAG_STRAIGHT) + f.name += "_straight"; + } + if (f.flags & FFLAG_LEAF) + { + numLeafs++; + leafSize += f.size; + } + else if (f.flags & FFLAG_ONLYCALLSNICELEAFS) + { + numNice++; + niceSize += f.size; + } + else + { + numUnNice++; + unniceSize += f.size; + } + + if (f.flags & FFLAG_TIMERINSTRUCTIONS) + numTimer++; + if (f.flags & FFLAG_RFI) + numRFI++; + if ((f.flags & FFLAG_STRAIGHT) && (f.flags & FFLAG_LEAF)) + numStraightLeaf++; + } + if (numLeafs == 0) + leafSize = 0; + else + leafSize /= numLeafs; + + if (numNice == 0) + niceSize = 0; + else + niceSize /= numNice; + + if (numUnNice == 0) + unniceSize = 0; + else + unniceSize /= numUnNice; + + INFO_LOG(OSHLE, "Functions analyzed. %i leafs, %i nice, %i unnice." + "%i timer, %i rfi. %i are branchless leafs.", numLeafs, + numNice, numUnNice, numTimer, numRFI, numStraightLeaf); + INFO_LOG(OSHLE, "Average size: %i (leaf), %i (nice), %i(unnice)", + leafSize, niceSize, unniceSize); +} + +static bool isCmp(const CodeOp& a) +{ + return (a.inst.OPCD == 10 || a.inst.OPCD == 11) || (a.inst.OPCD == 31 && (a.inst.SUBOP10 == 0 || a.inst.SUBOP10 == 32)); +} + +static bool isCarryOp(const CodeOp& a) +{ + return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && a.opinfo->type == OPTYPE_INTEGER; +} + +static bool isCror(const CodeOp& a) +{ + return a.inst.OPCD == 19 && a.inst.SUBOP10 == 449; +} + +void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type) +{ + // Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do + // multiple passes. + while (true) + { + // Instruction Reordering Pass + // Carry pass: bubble carry-using instructions as close to each other as possible, so we can avoid + // storing the carry flag. + // Compare pass: bubble compare instructions next to branches, so they can be merged. + bool swapped = false; + int increment = reverse ? -1 : 1; + int start = reverse ? instructions - 1 : 0; + int end = reverse ? 0 : instructions - 1; + for (int i = start; i != end; i += increment) + { + CodeOp &a = code[i]; + CodeOp &b = code[i + increment]; + // Reorder integer compares, rlwinm., and carry-affecting ops + // (if we add more merged branch instructions, add them here!) + if ((type == REORDER_CROR && isCror(a)) || (type == REORDER_CARRY && isCarryOp(a)) || (type == REORDER_CMP && (isCmp(a) || a.outputCR0))) + { + // once we're next to a carry instruction, don't move away! + if (type == REORDER_CARRY && i != start) + { + // if we read the CA flag, and the previous instruction sets it, don't move away. + if (!reverse && (a.opinfo->flags & FL_READ_CA) && (code[i - increment].opinfo->flags & FL_SET_CA)) + continue; + // if we set the CA flag, and the next instruction reads it, don't move away. + if (reverse && (a.opinfo->flags & FL_SET_CA) && (code[i - increment].opinfo->flags & FL_READ_CA)) + continue; + } + + if (CanSwapAdjacentOps(a, b)) + { + // Alright, let's bubble it! + std::swap(a, b); + swapped = true; } } - if (!swapped) - return; } + if (!swapped) + return; } +} - void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp *code) - { - // Reorder cror instructions upwards (e.g. towards an fcmp). Technically we should be more - // picky about this, but cror seems to almost solely be used for this purpose in real code. - // Additionally, the other boolean ops seem to almost never be used. +void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp *code) +{ + // Reorder cror instructions upwards (e.g. towards an fcmp). Technically we should be more + // picky about this, but cror seems to almost solely be used for this purpose in real code. + // Additionally, the other boolean ops seem to almost never be used. + if (HasOption(OPTION_CROR_MERGE)) ReorderInstructionsCore(instructions, code, true, REORDER_CROR); - // For carry, bubble instructions *towards* each other; one direction often isn't enough - // to get pairs like addc/adde next to each other. - if (HasOption(OPTION_CARRY_MERGE)) + // For carry, bubble instructions *towards* each other; one direction often isn't enough + // to get pairs like addc/adde next to each other. + if (HasOption(OPTION_CARRY_MERGE)) + { + ReorderInstructionsCore(instructions, code, false, REORDER_CARRY); + ReorderInstructionsCore(instructions, code, true, REORDER_CARRY); + } + if (HasOption(OPTION_BRANCH_MERGE)) + ReorderInstructionsCore(instructions, code, false, REORDER_CMP); +} + +void PPCAnalyzer::SetInstructionStats(CodeBlock *block, CodeOp *code, GekkoOPInfo *opinfo, u32 index) +{ + code->wantsCR0 = false; + code->wantsCR1 = false; + + if (opinfo->flags & FL_USE_FPU) + block->m_fpa->any = true; + + if (opinfo->flags & FL_TIMER) + block->m_gpa->anyTimer = true; + + // Does the instruction output CR0? + if (opinfo->flags & FL_RC_BIT) + code->outputCR0 = code->inst.hex & 1; //todo fix + else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 0) + code->outputCR0 = true; + else + code->outputCR0 = (opinfo->flags & FL_SET_CR0) ? true : false; + + // Does the instruction output CR1? + if (opinfo->flags & FL_RC_BIT_F) + code->outputCR1 = code->inst.hex & 1; //todo fix + else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 1) + code->outputCR1 = true; + else + code->outputCR1 = (opinfo->flags & FL_SET_CR1) ? true : false; + + code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) ? true : false; + code->outputFPRF = (opinfo->flags & FL_SET_FPRF) ? true : false; + code->canEndBlock = (opinfo->flags & FL_ENDBLOCK) ? true : false; + + code->wantsCA = (opinfo->flags & FL_READ_CA) ? true : false; + code->outputCA = (opinfo->flags & FL_SET_CA) ? true : false; + + // We're going to try to avoid storing carry in XER if we can avoid it -- keep it in the x86 carry flag! + // If the instruction reads CA but doesn't write it, we still need to store CA in XER; we can't + // leave it in flags. + if (HasOption(OPTION_CARRY_MERGE)) + code->wantsCAInFlags = code->wantsCA && code->outputCA && opinfo->type == OPTYPE_INTEGER; + else + code->wantsCAInFlags = false; + + // mfspr/mtspr can affect/use XER, so be super careful here + // we need to note specifically that mfspr needs CA in XER, not in the x86 carry flag + if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 339) // mfspr + code->wantsCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; + if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 467) // mtspr + code->outputCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; + + code->regsIn = BitSet32(0); + code->regsOut = BitSet32(0); + if (opinfo->flags & FL_OUT_A) + { + code->regsOut[code->inst.RA] = true; + block->m_gpa->SetOutputRegister(code->inst.RA, index); + } + if (opinfo->flags & FL_OUT_D) + { + code->regsOut[code->inst.RD] = true; + block->m_gpa->SetOutputRegister(code->inst.RD, index); + } + if (opinfo->flags & FL_OUT_S) + { + code->regsOut[code->inst.RS] = true; + block->m_gpa->SetOutputRegister(code->inst.RS, index); + } + if ((opinfo->flags & FL_IN_A) || ((opinfo->flags & FL_IN_A0) && code->inst.RA != 0)) + { + code->regsIn[code->inst.RA] = true; + block->m_gpa->SetInputRegister(code->inst.RA, index); + } + if (opinfo->flags & FL_IN_B) + { + code->regsIn[code->inst.RB] = true; + block->m_gpa->SetInputRegister(code->inst.RB, index); + } + if (opinfo->flags & FL_IN_C) + { + code->regsIn[code->inst.RC] = true; + block->m_gpa->SetInputRegister(code->inst.RC, index); + } + if (opinfo->flags & FL_IN_S) + { + code->regsIn[code->inst.RS] = true; + block->m_gpa->SetInputRegister(code->inst.RS, index); + } + if (code->inst.OPCD == 46) // lmw + { + for (int iReg = code->inst.RD; iReg < 32; ++iReg) { - ReorderInstructionsCore(instructions, code, false, REORDER_CARRY); - ReorderInstructionsCore(instructions, code, true, REORDER_CARRY); + code->regsOut[iReg] = true; + block->m_gpa->SetOutputRegister(iReg, index); + } + } + else if (code->inst.OPCD == 47) //stmw + { + for (int iReg = code->inst.RS; iReg < 32; ++iReg) + { + code->regsIn[iReg] = true; + block->m_gpa->SetInputRegister(iReg, index); } - if (HasOption(OPTION_BRANCH_MERGE)) - ReorderInstructionsCore(instructions, code, false, REORDER_CMP); } - void PPCAnalyzer::SetInstructionStats(CodeBlock *block, CodeOp *code, GekkoOPInfo *opinfo, u32 index) + code->fregOut = -1; + if (opinfo->flags & FL_OUT_FLOAT_D) + code->fregOut = code->inst.FD; + else if (opinfo->flags & FL_OUT_FLOAT_S) + code->fregOut = code->inst.FS; + code->fregsIn = BitSet32(0); + if (opinfo->flags & FL_IN_FLOAT_A) + code->fregsIn[code->inst.FA] = true; + if (opinfo->flags & FL_IN_FLOAT_B) + code->fregsIn[code->inst.FB] = true; + if (opinfo->flags & FL_IN_FLOAT_C) + code->fregsIn[code->inst.FC] = true; + if (opinfo->flags & FL_IN_FLOAT_D) + code->fregsIn[code->inst.FD] = true; + if (opinfo->flags & FL_IN_FLOAT_S) + code->fregsIn[code->inst.FS] = true; + + switch (opinfo->type) { - code->wantsCR0 = false; - code->wantsCR1 = false; - - if (opinfo->flags & FL_USE_FPU) - block->m_fpa->any = true; - - if (opinfo->flags & FL_TIMER) - block->m_gpa->anyTimer = true; - - // Does the instruction output CR0? - if (opinfo->flags & FL_RC_BIT) - code->outputCR0 = code->inst.hex & 1; //todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 0) + case OPTYPE_INTEGER: + case OPTYPE_LOAD: + case OPTYPE_STORE: + case OPTYPE_LOADFP: + case OPTYPE_STOREFP: + break; + case OPTYPE_SINGLEFP: + case OPTYPE_DOUBLEFP: + break; + case OPTYPE_BRANCH: + if (code->inst.hex == 0x4e800020) + { + // For analysis purposes, we can assume that blr eats opinfo->flags. code->outputCR0 = true; - else - code->outputCR0 = (opinfo->flags & FL_SET_CR0) ? true : false; - - // Does the instruction output CR1? - if (opinfo->flags & FL_RC_BIT_F) - code->outputCR1 = code->inst.hex & 1; //todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 1) code->outputCR1 = true; - else - code->outputCR1 = (opinfo->flags & FL_SET_CR1) ? true : false; + } + break; + case OPTYPE_SYSTEM: + case OPTYPE_SYSTEMFP: + break; + } +} - code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) ? true : false; - code->outputFPRF = (opinfo->flags & FL_SET_FPRF) ? true : false; - code->canEndBlock = (opinfo->flags & FL_ENDBLOCK) ? true : false; +u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32 blockSize) +{ + // Clear block stats + memset(block->m_stats, 0, sizeof(BlockStats)); - code->wantsCA = (opinfo->flags & FL_READ_CA) ? true : false; - code->outputCA = (opinfo->flags & FL_SET_CA) ? true : false; + // Clear register stats + block->m_gpa->any = true; + block->m_fpa->any = false; - // We're going to try to avoid storing carry in XER if we can avoid it -- keep it in the x86 carry flag! - // If the instruction reads CA but doesn't write it, we still need to store CA in XER; we can't - // leave it in flags. - if (HasOption(OPTION_CARRY_MERGE)) - code->wantsCAInFlags = code->wantsCA && code->outputCA && opinfo->type == OPTYPE_INTEGER; - else - code->wantsCAInFlags = false; + block->m_gpa->Clear(); + block->m_fpa->Clear(); - // mfspr/mtspr can affect/use XER, so be super careful here - // we need to note specifically that mfspr needs CA in XER, not in the x86 carry flag - if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 339) // mfspr - code->wantsCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; - if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 467) // mtspr - code->outputCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; + // Set the blocks start address + block->m_address = address; - code->regsIn = BitSet32(0); - code->regsOut = BitSet32(0); - if (opinfo->flags & FL_OUT_A) - { - code->regsOut[code->inst.RA] = true; - block->m_gpa->SetOutputRegister(code->inst.RA, index); - } - if (opinfo->flags & FL_OUT_D) - { - code->regsOut[code->inst.RD] = true; - block->m_gpa->SetOutputRegister(code->inst.RD, index); - } - if (opinfo->flags & FL_OUT_S) - { - code->regsOut[code->inst.RS] = true; - block->m_gpa->SetOutputRegister(code->inst.RS, index); - } - if ((opinfo->flags & FL_IN_A) || ((opinfo->flags & FL_IN_A0) && code->inst.RA != 0)) - { - code->regsIn[code->inst.RA] = true; - block->m_gpa->SetInputRegister(code->inst.RA, index); - } - if (opinfo->flags & FL_IN_B) - { - code->regsIn[code->inst.RB] = true; - block->m_gpa->SetInputRegister(code->inst.RB, index); - } - if (opinfo->flags & FL_IN_C) - { - code->regsIn[code->inst.RC] = true; - block->m_gpa->SetInputRegister(code->inst.RC, index); - } - if (opinfo->flags & FL_IN_S) - { - code->regsIn[code->inst.RS] = true; - block->m_gpa->SetInputRegister(code->inst.RS, index); - } - if (code->inst.OPCD == 46) // lmw - { - for (int iReg = code->inst.RD; iReg < 32; ++iReg) - { - code->regsOut[iReg] = true; - block->m_gpa->SetOutputRegister(iReg, index); - } - } - else if (code->inst.OPCD == 47) //stmw - { - for (int iReg = code->inst.RS; iReg < 32; ++iReg) - { - code->regsIn[iReg] = true; - block->m_gpa->SetInputRegister(iReg, index); - } - } + // Reset our block state + block->m_broken = false; + block->m_memory_exception = false; + block->m_num_instructions = 0; + block->m_gqr_used = BitSet8(0); - code->fregOut = -1; - if (opinfo->flags & FL_OUT_FLOAT_D) - code->fregOut = code->inst.FD; - else if (opinfo->flags & FL_OUT_FLOAT_S) - code->fregOut = code->inst.FS; - code->fregsIn = BitSet32(0); - if (opinfo->flags & FL_IN_FLOAT_A) - code->fregsIn[code->inst.FA] = true; - if (opinfo->flags & FL_IN_FLOAT_B) - code->fregsIn[code->inst.FB] = true; - if (opinfo->flags & FL_IN_FLOAT_C) - code->fregsIn[code->inst.FC] = true; - if (opinfo->flags & FL_IN_FLOAT_D) - code->fregsIn[code->inst.FD] = true; - if (opinfo->flags & FL_IN_FLOAT_S) - code->fregsIn[code->inst.FS] = true; - - switch (opinfo->type) - { - case OPTYPE_INTEGER: - case OPTYPE_LOAD: - case OPTYPE_STORE: - case OPTYPE_LOADFP: - case OPTYPE_STOREFP: - break; - case OPTYPE_SINGLEFP: - case OPTYPE_DOUBLEFP: - break; - case OPTYPE_BRANCH: - if (code->inst.hex == 0x4e800020) - { - // For analysis purposes, we can assume that blr eats opinfo->flags. - code->outputCR0 = true; - code->outputCR1 = true; - } - break; - case OPTYPE_SYSTEM: - case OPTYPE_SYSTEMFP: - break; - } + if (address == 0) + { + // Memory exception occurred during instruction fetch + block->m_memory_exception = true; + return address; } - u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32 blockSize) + bool virtualAddr = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & JIT_ICACHE_VMEM_BIT); + if (virtualAddr) { - // Clear block stats - memset(block->m_stats, 0, sizeof(BlockStats)); - - // Clear register stats - block->m_gpa->any = true; - block->m_fpa->any = false; - - block->m_gpa->Clear(); - block->m_fpa->Clear(); - - // Set the blocks start address - block->m_address = address; - - // Reset our block state - block->m_broken = false; - block->m_memory_exception = false; - block->m_num_instructions = 0; - block->m_gqr_used = BitSet8(0); - - if (address == 0) + if (!Memory::TranslateAddress(address)) { // Memory exception occurred during instruction fetch block->m_memory_exception = true; return address; } + } - bool virtualAddr = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & JIT_ICACHE_VMEM_BIT); - if (virtualAddr) + CodeOp *code = buffer->codebuffer; + + bool found_exit = false; + u32 return_address = 0; + u32 numFollows = 0; + u32 num_inst = 0; + + for (u32 i = 0; i < blockSize; ++i) + { + UGeckoInstruction inst = JitInterface::ReadOpcodeJIT(address); + + if (inst.hex != 0) { - if (!Memory::TranslateAddress(address)) + // Slight hack: the JIT block cache currently assumes all blocks end at the same place, + // but broken blocks due to page faults break this assumption. Avoid this by just ending + // all virtual memory instruction blocks at page boundaries. + // FIXME: improve the JIT block cache so we don't need to do this. + if (virtualAddr && i > 0 && (address & 0xfff) == 0) { - // Memory exception occurred during instruction fetch - block->m_memory_exception = true; - return address; - } - } - - CodeOp *code = buffer->codebuffer; - - bool found_exit = false; - u32 return_address = 0; - u32 numFollows = 0; - u32 num_inst = 0; - - for (u32 i = 0; i < blockSize; ++i) - { - UGeckoInstruction inst = JitInterface::ReadOpcodeJIT(address); - - if (inst.hex != 0) - { - // Slight hack: the JIT block cache currently assumes all blocks end at the same place, - // but broken blocks due to page faults break this assumption. Avoid this by just ending - // all virtual memory instruction blocks at page boundaries. - // FIXME: improve the JIT block cache so we don't need to do this. - if (virtualAddr && i > 0 && (address & 0xfff) == 0) - { - break; - } - - num_inst++; - memset(&code[i], 0, sizeof(CodeOp)); - GekkoOPInfo *opinfo = GetOpInfo(inst); - if (!opinfo) - { - PanicAlert("Invalid PowerPC opcode: %x.", inst.hex); - Crash(); - } - - code[i].opinfo = opinfo; - code[i].address = address; - code[i].inst = inst; - code[i].branchTo = -1; - code[i].branchToIndex = -1; - code[i].skip = false; - block->m_stats->numCycles += opinfo->numCycles; - - SetInstructionStats(block, &code[i], opinfo, i); - - bool follow = false; - u32 destination = 0; - - bool conditional_continue = false; - - // Do we inline leaf functions? - if (HasOption(OPTION_LEAF_INLINE)) - { - if (inst.OPCD == 18 && blockSize > 1) - { - //Is bx - should we inline? yes! - if (inst.AA) - destination = SignExt26(inst.LI << 2); - else - destination = address + SignExt26(inst.LI << 2); - if (destination != block->m_address) - follow = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && - (inst.BO & (1 << 4)) && (inst.BO & (1 << 2)) && - return_address != 0) - { - // bclrx with unconditional branch = return - follow = true; - destination = return_address; - return_address = 0; - - if (inst.LK) - return_address = address + 4; - } - else if (inst.OPCD == 31 && inst.SUBOP10 == 467) - { - // mtspr - const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - if (index == SPR_LR) - { - // We give up to follow the return address - // because we have to check the register usage. - return_address = 0; - } - } - - // TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD. - // If it is small, the performance will be down. - // If it is big, the size of generated code will be big and - // cache clearning will happen many times. - // TODO: Investivate the reason why - // "0" is fastest in some games, MP2 for example. - if (numFollows > FUNCTION_FOLLOWING_THRESHOLD) - follow = false; - } - - if (HasOption(OPTION_CONDITIONAL_CONTINUE)) - { - if (inst.OPCD == 16 && - ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) - { - // bcx with conditional branch - conditional_continue = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && - ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) - { - // bclrx with conditional branch - conditional_continue = true; - } - else if (inst.OPCD == 3 || - (inst.OPCD == 31 && inst.SUBOP10 == 4)) - { - // tw/twi tests and raises an exception - conditional_continue = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 528 && - (inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0) - { - // Rare bcctrx with conditional branch - // Seen in NES games - conditional_continue = true; - } - } - - if (!follow) - { - address += 4; - if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) //right now we stop early - { - found_exit = true; - break; - } - } - // XXX: We don't support inlining yet. -#if 0 - else - { - numFollows++; - // We don't "code[i].skip = true" here - // because bx may store a certain value to the link register. - // Instead, we skip a part of bx in Jit**::bx(). - address = destination; - merged_addresses[size_of_merged_addresses++] = address; - } -#endif - } - else - { - // ISI exception or other critical memory exception occured (game over) - // We can continue on in MMU mode though, so don't spam this error in that case. - if (!virtualAddr) - ERROR_LOG(DYNA_REC, "Instruction hex was 0!"); break; } - } - block->m_num_instructions = num_inst; - - if (block->m_num_instructions > 1) - ReorderInstructions(block->m_num_instructions, code); - - if ((!found_exit && num_inst > 0) || blockSize == 1) - { - // We couldn't find an exit - block->m_broken = true; - } - - // Scan for flag dependencies; assume the next block (or any branch that can leave the block) - // wants flags, to be safe. - bool wantsCR0 = true, wantsCR1 = true, wantsFPRF = true, wantsCA = true; - BitSet32 fprInUse, gprInUse, gprInReg, fprInXmm; - for (int i = block->m_num_instructions - 1; i >= 0; i--) - { - bool opWantsCR0 = code[i].wantsCR0; - bool opWantsCR1 = code[i].wantsCR1; - bool opWantsFPRF = code[i].wantsFPRF; - bool opWantsCA = code[i].wantsCA; - code[i].wantsCR0 = wantsCR0 || code[i].canEndBlock; - code[i].wantsCR1 = wantsCR1 || code[i].canEndBlock; - code[i].wantsFPRF = wantsFPRF || code[i].canEndBlock; - code[i].wantsCA = wantsCA || code[i].canEndBlock; - wantsCR0 |= opWantsCR0 || code[i].canEndBlock; - wantsCR1 |= opWantsCR1 || code[i].canEndBlock; - wantsFPRF |= opWantsFPRF || code[i].canEndBlock; - wantsCA |= opWantsCA || code[i].canEndBlock; - wantsCR0 &= !code[i].outputCR0 || opWantsCR0; - wantsCR1 &= !code[i].outputCR1 || opWantsCR1; - wantsFPRF &= !code[i].outputFPRF || opWantsFPRF; - wantsCA &= !code[i].outputCA || opWantsCA; - code[i].gprInUse = gprInUse; - code[i].fprInUse = fprInUse; - code[i].gprInReg = gprInReg; - code[i].fprInXmm = fprInXmm; - // TODO: if there's no possible endblocks or exceptions in between, tell the regcache - // we can throw away a register if it's going to be overwritten later. - gprInUse |= code[i].regsIn; - gprInReg |= code[i].regsIn; - fprInUse |= code[i].fregsIn; - if (strncmp(code[i].opinfo->opname, "stfd", 4)) - fprInXmm |= code[i].fregsIn; - // For now, we need to count output registers as "used" though; otherwise the flush - // will result in a redundant store (e.g. store to regcache, then store again to - // the same location later). - gprInUse |= code[i].regsOut; - if (code[i].fregOut >= 0) - fprInUse[code[i].fregOut] = true; - } - - // Forward scan, for flags that need the other direction for calculation. - BitSet32 fprIsSingle, fprIsDuplicated, fprIsStoreSafe; - BitSet8 gqrUsed, gqrModified; - for (u32 i = 0; i < block->m_num_instructions; i++) - { - code[i].fprIsSingle = fprIsSingle; - code[i].fprIsDuplicated = fprIsDuplicated; - code[i].fprIsStoreSafe = fprIsStoreSafe; - if (code[i].fregOut >= 0) + num_inst++; + memset(&code[i], 0, sizeof(CodeOp)); + GekkoOPInfo *opinfo = GetOpInfo(inst); + if (!opinfo) { - fprIsSingle[code[i].fregOut] = false; - fprIsDuplicated[code[i].fregOut] = false; - fprIsStoreSafe[code[i].fregOut] = false; - // Single, duplicated, and doesn't need PPC_FP. - if (code[i].opinfo->type == OPTYPE_SINGLEFP) - { - fprIsSingle[code[i].fregOut] = true; - fprIsDuplicated[code[i].fregOut] = true; - fprIsStoreSafe[code[i].fregOut] = true; - } - // Single and duplicated, but might be a denormal (not safe to skip PPC_FP). - // TODO: if we go directly from a load to store, skip conversion entirely? - // TODO: if we go directly from a load to a float instruction, and the value isn't used - // for anything else, we can skip PPC_FP on a load too. - if (!strncmp(code[i].opinfo->opname, "lfs", 3)) - { - fprIsSingle[code[i].fregOut] = true; - fprIsDuplicated[code[i].fregOut] = true; - } - // Paired are still floats, but the top/bottom halves may differ. - if (code[i].opinfo->type == OPTYPE_PS || code[i].opinfo->type == OPTYPE_LOADPS) - { - fprIsSingle[code[i].fregOut] = true; - fprIsStoreSafe[code[i].fregOut] = true; - } - // Careful: changing the float mode in a block breaks this optimization, since - // a previous float op might have had had FTZ off while the later store has FTZ - // on. So, discard all information we have. - if (!strncmp(code[i].opinfo->opname, "mtfs", 4)) - fprIsStoreSafe = BitSet32(0); + PanicAlert("Invalid PowerPC opcode: %x.", inst.hex); + Crash(); } - if (code[i].opinfo->type == OPTYPE_STOREPS || code[i].opinfo->type == OPTYPE_LOADPS) + code[i].opinfo = opinfo; + code[i].address = address; + code[i].inst = inst; + code[i].branchTo = -1; + code[i].branchToIndex = -1; + code[i].skip = false; + block->m_stats->numCycles += opinfo->numCycles; + + SetInstructionStats(block, &code[i], opinfo, i); + + bool follow = false; + u32 destination = 0; + + bool conditional_continue = false; + + // Do we inline leaf functions? + if (HasOption(OPTION_LEAF_INLINE)) { - int gqr = code[i].inst.OPCD == 4 ? code[i].inst.Ix : code[i].inst.I; - gqrUsed[gqr] = true; + if (inst.OPCD == 18 && blockSize > 1) + { + //Is bx - should we inline? yes! + if (inst.AA) + destination = SignExt26(inst.LI << 2); + else + destination = address + SignExt26(inst.LI << 2); + if (destination != block->m_address) + follow = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && + (inst.BO & (1 << 4)) && (inst.BO & (1 << 2)) && + return_address != 0) + { + // bclrx with unconditional branch = return + follow = true; + destination = return_address; + return_address = 0; + + if (inst.LK) + return_address = address + 4; + } + else if (inst.OPCD == 31 && inst.SUBOP10 == 467) + { + // mtspr + const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + if (index == SPR_LR) + { + // We give up to follow the return address + // because we have to check the register usage. + return_address = 0; + } + } + + // TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD. + // If it is small, the performance will be down. + // If it is big, the size of generated code will be big and + // cache clearning will happen many times. + // TODO: Investivate the reason why + // "0" is fastest in some games, MP2 for example. + if (numFollows > FUNCTION_FOLLOWING_THRESHOLD) + follow = false; } - if (code[i].inst.OPCD == 31 && code[i].inst.SUBOP10 == 467) // mtspr + if (HasOption(OPTION_CONDITIONAL_CONTINUE)) { - int gqr = ((code[i].inst.SPRU << 5) | code[i].inst.SPRL) - SPR_GQR0; - if (gqr >= 0 && gqr <= 7) - gqrModified[gqr] = true; + if (inst.OPCD == 16 && + ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) + { + // bcx with conditional branch + conditional_continue = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && + ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) + { + // bclrx with conditional branch + conditional_continue = true; + } + else if (inst.OPCD == 3 || + (inst.OPCD == 31 && inst.SUBOP10 == 4)) + { + // tw/twi tests and raises an exception + conditional_continue = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 528 && + (inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0) + { + // Rare bcctrx with conditional branch + // Seen in NES games + conditional_continue = true; + } } + + if (!follow) + { + address += 4; + if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) //right now we stop early + { + found_exit = true; + break; + } + } + // XXX: We don't support inlining yet. +#if 0 + else + { + numFollows++; + // We don't "code[i].skip = true" here + // because bx may store a certain value to the link register. + // Instead, we skip a part of bx in Jit**::bx(). + address = destination; + merged_addresses[size_of_merged_addresses++] = address; + } +#endif + } + else + { + // ISI exception or other critical memory exception occured (game over) + // We can continue on in MMU mode though, so don't spam this error in that case. + if (!virtualAddr) + ERROR_LOG(DYNA_REC, "Instruction hex was 0!"); + break; } - block->m_gqr_used = gqrUsed; - block->m_gqr_modified = gqrModified; - return address; } + block->m_num_instructions = num_inst; + + if (block->m_num_instructions > 1) + ReorderInstructions(block->m_num_instructions, code); + + if ((!found_exit && num_inst > 0) || blockSize == 1) + { + // We couldn't find an exit + block->m_broken = true; + } + + // Scan for flag dependencies; assume the next block (or any branch that can leave the block) + // wants flags, to be safe. + bool wantsCR0 = true, wantsCR1 = true, wantsFPRF = true, wantsCA = true; + BitSet32 fprInUse, gprInUse, gprInReg, fprInXmm; + for (int i = block->m_num_instructions - 1; i >= 0; i--) + { + bool opWantsCR0 = code[i].wantsCR0; + bool opWantsCR1 = code[i].wantsCR1; + bool opWantsFPRF = code[i].wantsFPRF; + bool opWantsCA = code[i].wantsCA; + code[i].wantsCR0 = wantsCR0 || code[i].canEndBlock; + code[i].wantsCR1 = wantsCR1 || code[i].canEndBlock; + code[i].wantsFPRF = wantsFPRF || code[i].canEndBlock; + code[i].wantsCA = wantsCA || code[i].canEndBlock; + wantsCR0 |= opWantsCR0 || code[i].canEndBlock; + wantsCR1 |= opWantsCR1 || code[i].canEndBlock; + wantsFPRF |= opWantsFPRF || code[i].canEndBlock; + wantsCA |= opWantsCA || code[i].canEndBlock; + wantsCR0 &= !code[i].outputCR0 || opWantsCR0; + wantsCR1 &= !code[i].outputCR1 || opWantsCR1; + wantsFPRF &= !code[i].outputFPRF || opWantsFPRF; + wantsCA &= !code[i].outputCA || opWantsCA; + code[i].gprInUse = gprInUse; + code[i].fprInUse = fprInUse; + code[i].gprInReg = gprInReg; + code[i].fprInXmm = fprInXmm; + // TODO: if there's no possible endblocks or exceptions in between, tell the regcache + // we can throw away a register if it's going to be overwritten later. + gprInUse |= code[i].regsIn; + gprInReg |= code[i].regsIn; + fprInUse |= code[i].fregsIn; + if (strncmp(code[i].opinfo->opname, "stfd", 4)) + fprInXmm |= code[i].fregsIn; + // For now, we need to count output registers as "used" though; otherwise the flush + // will result in a redundant store (e.g. store to regcache, then store again to + // the same location later). + gprInUse |= code[i].regsOut; + if (code[i].fregOut >= 0) + fprInUse[code[i].fregOut] = true; + } + + // Forward scan, for flags that need the other direction for calculation. + BitSet32 fprIsSingle, fprIsDuplicated, fprIsStoreSafe; + BitSet8 gqrUsed, gqrModified; + for (u32 i = 0; i < block->m_num_instructions; i++) + { + code[i].fprIsSingle = fprIsSingle; + code[i].fprIsDuplicated = fprIsDuplicated; + code[i].fprIsStoreSafe = fprIsStoreSafe; + if (code[i].fregOut >= 0) + { + fprIsSingle[code[i].fregOut] = false; + fprIsDuplicated[code[i].fregOut] = false; + fprIsStoreSafe[code[i].fregOut] = false; + // Single, duplicated, and doesn't need PPC_FP. + if (code[i].opinfo->type == OPTYPE_SINGLEFP) + { + fprIsSingle[code[i].fregOut] = true; + fprIsDuplicated[code[i].fregOut] = true; + fprIsStoreSafe[code[i].fregOut] = true; + } + // Single and duplicated, but might be a denormal (not safe to skip PPC_FP). + // TODO: if we go directly from a load to store, skip conversion entirely? + // TODO: if we go directly from a load to a float instruction, and the value isn't used + // for anything else, we can skip PPC_FP on a load too. + if (!strncmp(code[i].opinfo->opname, "lfs", 3)) + { + fprIsSingle[code[i].fregOut] = true; + fprIsDuplicated[code[i].fregOut] = true; + } + // Paired are still floats, but the top/bottom halves may differ. + if (code[i].opinfo->type == OPTYPE_PS || code[i].opinfo->type == OPTYPE_LOADPS) + { + fprIsSingle[code[i].fregOut] = true; + fprIsStoreSafe[code[i].fregOut] = true; + } + // Careful: changing the float mode in a block breaks this optimization, since + // a previous float op might have had had FTZ off while the later store has FTZ + // on. So, discard all information we have. + if (!strncmp(code[i].opinfo->opname, "mtfs", 4)) + fprIsStoreSafe = BitSet32(0); + } + + if (code[i].opinfo->type == OPTYPE_STOREPS || code[i].opinfo->type == OPTYPE_LOADPS) + { + int gqr = code[i].inst.OPCD == 4 ? code[i].inst.Ix : code[i].inst.I; + gqrUsed[gqr] = true; + } + + if (code[i].inst.OPCD == 31 && code[i].inst.SUBOP10 == 467) // mtspr + { + int gqr = ((code[i].inst.SPRU << 5) | code[i].inst.SPRL) - SPR_GQR0; + if (gqr >= 0 && gqr <= 7) + gqrModified[gqr] = true; + } + } + block->m_gqr_used = gqrUsed; + block->m_gqr_modified = gqrModified; + return address; +} + } // namespace diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h index 8b2f3245a..6fc074beb 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/PowerPC/PPCAnalyst.h @@ -79,11 +79,11 @@ struct BlockRegStats bool any; bool anyTimer; - int GetTotalNumAccesses(int reg) { return numReads[reg] + numWrites[reg]; } + int GetTotalNumAccesses(int reg) {return numReads[reg] + numWrites[reg];} int GetUseRange(int reg) { return std::max(lastRead[reg], lastWrite[reg]) - - std::min(firstRead[reg], firstWrite[reg]); + std::min(firstRead[reg], firstWrite[reg]); } bool IsUsed(int reg) @@ -214,6 +214,9 @@ public: // Reorder carry instructions next to their associated branches and pass // carry flags in the x86 flags between them, instead of in XER. OPTION_CARRY_MERGE = (1 << 5), + + // Reorder cror instructions next to their associated fcmp. + OPTION_CROR_MERGE = (1 << 6), }; diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index f9b1fa10e..381d1bdbd 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -206,8 +206,7 @@ u32 CFileSystemGCWii::Read32(u64 _Offset) const std::string CFileSystemGCWii::GetStringFromOffset(u64 _Offset) const { - std::string data; - data.resize(255); + std::string data(255, 0x00); m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_Wii); data.erase(std::find(data.begin(), data.end(), 0x00), data.end()); @@ -263,40 +262,41 @@ bool CFileSystemGCWii::DetectFileSystem() void CFileSystemGCWii::InitFileSystem() { m_Initialized = true; + u32 const shift = GetOffsetShift(); // read the whole FST - u64 FSTOffset = (u64)Read32(0x424) << GetOffsetShift(); + u64 FSTOffset = static_cast(Read32(0x424)) << shift; // u32 FSTSize = Read32(0x428); // u32 FSTMaxSize = Read32(0x42C); // read all fileinfos - SFileInfo Root; - Root.m_NameOffset = Read32(FSTOffset + 0x0); - Root.m_Offset = (u64)Read32(FSTOffset + 0x4) << GetOffsetShift(); - Root.m_FileSize = Read32(FSTOffset + 0x8); - - if (Root.IsDirectory()) + SFileInfo Root { - if (m_FileInfoVector.size()) - PanicAlert("Wtf?"); - u64 NameTableOffset = FSTOffset; + Read32(FSTOffset + 0x0), + static_cast(FSTOffset + 0x4) << shift, + Read32(FSTOffset + 0x8) + }; - m_FileInfoVector.reserve((unsigned int)Root.m_FileSize); - for (u32 i = 0; i < Root.m_FileSize; i++) - { - SFileInfo sfi; - u64 Offset = FSTOffset + (i * 0xC); - sfi.m_NameOffset = Read32(Offset + 0x0); - sfi.m_Offset = (u64)Read32(Offset + 0x4) << GetOffsetShift(); - sfi.m_FileSize = Read32(Offset + 0x8); + if (!Root.IsDirectory()) + return; - m_FileInfoVector.push_back(sfi); - NameTableOffset += 0xC; - } + if (m_FileInfoVector.size()) + PanicAlert("Wtf?"); + u64 NameTableOffset = FSTOffset; - BuildFilenames(1, m_FileInfoVector.size(), "", NameTableOffset); + m_FileInfoVector.reserve((size_t)Root.m_FileSize); + for (u32 i = 0; i < Root.m_FileSize; i++) + { + u64 const read_offset = FSTOffset + (i * 0xC); + u64 const name_offset = Read32(read_offset + 0x0); + u64 const offset = static_cast(Read32(read_offset + 0x4)) << shift; + u64 const size = Read32(read_offset + 0x8); + m_FileInfoVector.emplace_back(name_offset, offset, size); + NameTableOffset += 0xC; } + + BuildFilenames(1, m_FileInfoVector.size(), "", NameTableOffset); } size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const std::string& _szDirectory, u64 _NameTableOffset) @@ -307,19 +307,22 @@ size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _ { SFileInfo& rFileInfo = m_FileInfoVector[CurrentIndex]; u64 const uOffset = _NameTableOffset + (rFileInfo.m_NameOffset & 0xFFFFFF); + std::string const offset_str { GetStringFromOffset(uOffset) }; + bool const is_dir = rFileInfo.IsDirectory(); + rFileInfo.m_FullPath.reserve(_szDirectory.size() + offset_str.size()); - rFileInfo.m_FullPath = _szDirectory + GetStringFromOffset(uOffset); + rFileInfo.m_FullPath.append(_szDirectory.data(), _szDirectory.size()) + .append(offset_str.data(), offset_str.size()) + .append("/", size_t(is_dir)); - // check next index - if (rFileInfo.IsDirectory()) - { - rFileInfo.m_FullPath += '/'; - CurrentIndex = BuildFilenames(CurrentIndex + 1, (size_t) rFileInfo.m_FileSize, rFileInfo.m_FullPath, _NameTableOffset); - } - else + if (!is_dir) { ++CurrentIndex; + continue; } + + // check next index + CurrentIndex = BuildFilenames(CurrentIndex + 1, (size_t) rFileInfo.m_FileSize, rFileInfo.m_FullPath, _NameTableOffset); } return CurrentIndex; diff --git a/Source/Core/DiscIO/Filesystem.h b/Source/Core/DiscIO/Filesystem.h index 914560926..78f179d6d 100644 --- a/Source/Core/DiscIO/Filesystem.h +++ b/Source/Core/DiscIO/Filesystem.h @@ -19,21 +19,21 @@ class IVolume; // file info of an FST entry struct SFileInfo { - u64 m_NameOffset; - u64 m_Offset; - u64 m_FileSize; + u64 m_NameOffset = 0u; + u64 m_Offset = 0u; + u64 m_FileSize = 0u; std::string m_FullPath; bool IsDirectory() const { return (m_NameOffset & 0xFF000000) != 0; } - SFileInfo() : m_NameOffset(0), m_Offset(0), m_FileSize(0) - { - } + SFileInfo(u64 name_offset, u64 offset, u64 filesize) : + m_NameOffset(name_offset), + m_Offset(offset), + m_FileSize(filesize) + { } - SFileInfo(const SFileInfo& rhs) : m_NameOffset(rhs.m_NameOffset), - m_Offset(rhs.m_Offset), m_FileSize(rhs.m_FileSize), m_FullPath(rhs.m_FullPath) - { - } + SFileInfo (SFileInfo const&) = default; + SFileInfo () = default; }; class IFileSystem diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 097da655b..a9818c676 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -42,7 +42,7 @@ public: virtual bool ChangePartition(u64 offset) { return false; } - // Increment CACHE_REVISION if values are changed (ISOFile.cpp) + // Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) enum ECountry { COUNTRY_EUROPE = 0, diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index 2cd3a1f77..235bb22b4 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -9,6 +9,7 @@ #include "Common/Logging/Log.h" #include "DiscIO/Volume.h" +// Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) namespace DiscIO { IVolume::ECountry CountrySwitch(u8 CountryCode) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index cc26ff814..10a3e51f0 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -24,7 +24,7 @@ namespace DiscIO { CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, - const std::string& _rApploader, const std::string& _rDOL) + const std::string& _rApploader, const std::string& _rDOL) : m_totalNameSize(0) , m_dataStartAddress(-1) , m_diskHeader(DISKHEADERINFO_ADDRESS) @@ -194,7 +194,7 @@ void CVolumeDirectory::SetName(const std::string& name) { size_t length = name.length(); if (length > MAX_NAME_LENGTH) - length = MAX_NAME_LENGTH; + length = MAX_NAME_LENGTH; memcpy(&m_diskHeader[0x20], name.c_str(), length); m_diskHeader[length + 0x20] = 0; @@ -357,7 +357,7 @@ void CVolumeDirectory::BuildFST() } void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, const u8* _Src, - u64& _Address, u64& _Length, u8*& _pBuffer) const + u64& _Address, u64& _Length, u8*& _pBuffer) const { if (_Length == 0) return; @@ -403,7 +403,7 @@ void CVolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buff (*buffer)[offset++] = (data >> 24); (*buffer)[offset++] = (data >> 16) & 0xff; (*buffer)[offset++] = (data >> 8) & 0xff; - (*buffer)[offset] = (data)& 0xff; + (*buffer)[offset] = (data) & 0xff; } void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u32 length) @@ -412,7 +412,7 @@ void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, m_FSTData[entryOffset++] = (nameOffset >> 16) & 0xff; m_FSTData[entryOffset++] = (nameOffset >> 8) & 0xff; - m_FSTData[entryOffset++] = (nameOffset)& 0xff; + m_FSTData[entryOffset++] = (nameOffset) & 0xff; Write32((u32)(dataOffset >> m_addressShift), entryOffset, &m_FSTData); entryOffset += 4; diff --git a/Source/Core/DolphinQt/GameList/GameFile.cpp b/Source/Core/DolphinQt/GameList/GameFile.cpp index f5f4dd989..cd56d39b8 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt/GameList/GameFile.cpp @@ -152,7 +152,7 @@ bool GameFile::LoadFromCache() if (!file.open(QFile::ReadOnly)) return false; - // If you modify the code below, you MUST bump the CACHE_REVISION! (ISOFile.cpp) + // Increment CACHE_REVISION if the code below is modified (GameFile.cpp) QDataStream stream(&file); stream.setVersion(DATASTREAM_REVISION); @@ -195,7 +195,7 @@ void GameFile::SaveToCache() if (!file.open(QFile::WriteOnly)) return; - // If you modify the code below, you MUST bump the CACHE_REVISION! (ISOFile.cpp) + // Increment CACHE_REVISION if the code below is modified (GameFile.cpp) QDataStream stream(&file); stream.setVersion(DATASTREAM_REVISION); stream << CACHE_REVISION; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 9ae30b25f..75d7729ea 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -21,6 +21,8 @@ #include "DolphinQt/Utils/Resources.h" #include "DolphinQt/Utils/Utils.h" +#include "VideoCommon/VideoConfig.h" + // The "g_main_window" object as defined in MainWindow.h DMainWindow* g_main_window = nullptr; @@ -92,39 +94,34 @@ void DMainWindow::StartGame(const QString filename) m_render_widget->setWindowTitle(tr("Dolphin")); // TODO m_render_widget->setWindowIcon(windowIcon()); - // TODO: When rendering to main, this won't resize the parent window.. - if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) { - connect(m_render_widget.get(), SIGNAL(Closed()), this, SLOT(OnStop())); - m_render_widget->move(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowXPos, - SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowYPos); - m_render_widget->resize(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowWidth, // TODO: Make sure these are client sizes! - SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight); - m_render_widget->show(); + m_render_widget->setWindowFlags(m_render_widget->windowFlags() | Qt::BypassWindowManagerHint); + g_Config.bFullscreen = !g_Config.bBorderlessFullscreen; + m_render_widget->showFullScreen(); } else { m_ui->centralWidget->addWidget(m_render_widget.get()); m_ui->centralWidget->setCurrentWidget(m_render_widget.get()); + + // TODO: When rendering to main, this won't resize the parent window... + m_render_widget->resize(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowWidth, + SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight); } if (!BootManager::BootCore(filename.toStdString())) { QMessageBox::critical(this, tr("Fatal error"), tr("Failed to init Core"), QMessageBox::Ok); - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) - m_ui->centralWidget->removeWidget(m_render_widget.get()); - else + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) m_render_widget->close(); + else + m_ui->centralWidget->removeWidget(m_render_widget.get()); m_render_widget.reset(); } else { // TODO: Disable screensaver! - - // TODO: Fullscreen - //DoFullscreen(SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen); - - m_render_widget->focusWidget(); emit CoreStateChanged(Core::CORE_RUN); } } @@ -181,48 +178,53 @@ void DMainWindow::OnPlay() } } -void DMainWindow::OnStop() +bool DMainWindow::OnStop() { - if (Core::GetState() != Core::CORE_UNINITIALIZED && !m_isStopping) + if (Core::GetState() == Core::CORE_UNINITIALIZED || m_isStopping) + return true; // We're already stopped/stopping + + // Ask for confirmation in case the user accidentally clicked Stop / Escape + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop) { - m_isStopping = true; - // Ask for confirmation in case the user accidentally clicked Stop / Escape - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop) + // Pause emulation + Core::SetState(Core::CORE_PAUSE); + emit CoreStateChanged(Core::CORE_PAUSE); + + QMessageBox::StandardButton ret = QMessageBox::question(m_render_widget.get(), tr("Please confirm..."), + tr("Do you want to stop the current emulation?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (ret == QMessageBox::No) { - int ret = QMessageBox::question(m_render_widget.get(), tr("Please confirm..."), - tr("Do you want to stop the current emulation?"), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - - if (ret == QMessageBox::No) - return; + DoStartPause(); + return false; } - - // TODO: Movie stuff - // TODO: Show the author/description dialog here - - // TODO: Show busy cursor - BootManager::Stop(); - // TODO: Hide busy cursor again - - // TODO: Allow screensaver again - // TODO: Restore original window title - - // TODO: Return from fullscreen if necessary (DoFullscreen in the wx code) - - // TODO: - // If batch mode was specified on the command-line, exit now. - //if (m_bBatchMode) - // Close(true); - - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) - m_ui->centralWidget->removeWidget(m_render_widget.get()); - else - m_render_widget->close(); - m_render_widget.reset(); - - emit CoreStateChanged(Core::CORE_UNINITIALIZED); } + + m_isStopping = true; + + // TODO: Movie stuff + // TODO: Show the author/description dialog here + + BootManager::Stop(); + + // TODO: Allow screensaver again + // TODO: Restore original window title + + // TODO: + // If batch mode was specified on the command-line, exit now. + //if (m_bBatchMode) + // Close(true); + + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) + m_render_widget->close(); + else + m_ui->centralWidget->removeWidget(m_render_widget.get()); + m_render_widget.reset(); + + emit CoreStateChanged(Core::CORE_UNINITIALIZED); m_isStopping = false; + return true; } void DMainWindow::OnGameListStyleChanged() diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index cee7743ad..a0671443f 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -33,6 +33,10 @@ public: signals: void CoreStateChanged(Core::EState state); +public slots: + // Main toolbar (also used by DRenderWidget) + bool OnStop(); + private slots: // Emulation void StartGame(const QString filename); @@ -41,7 +45,6 @@ private slots: // Main toolbar void OnOpen(); void OnPlay(); - void OnStop(); // View menu void OnGameListStyleChanged(); diff --git a/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp b/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp index 4fbcd3cd2..4a9023956 100644 --- a/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp +++ b/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp @@ -2,8 +2,10 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include #include +#include "DolphinQt/MainWindow.h" #include "DolphinQt/VideoInterface/RenderWidget.h" DRenderWidget::DRenderWidget(QWidget* parent_widget) @@ -16,9 +18,10 @@ DRenderWidget::DRenderWidget(QWidget* parent_widget) void DRenderWidget::closeEvent(QCloseEvent* e) { - // TODO: update render window positions in config - - // TODO: Do this differently... - emit Closed(); + if (!g_main_window->OnStop()) + { + e->ignore(); + return; + } QWidget::closeEvent(e); } diff --git a/Source/Core/DolphinWX/ConfigMain.cpp b/Source/Core/DolphinWX/ConfigMain.cpp index 322a5c694..b490673fa 100644 --- a/Source/Core/DolphinWX/ConfigMain.cpp +++ b/Source/Core/DolphinWX/ConfigMain.cpp @@ -610,7 +610,7 @@ void CConfigMain::CreateGUIControls() DSPEngine = new wxRadioBox(AudioPage, ID_DSPENGINE, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize, arrayStringFor_DSPEngine, 0, wxRA_SPECIFY_ROWS); DPL2Decoder = new wxCheckBox(AudioPage, ID_DPL2DECODER, _("Dolby Pro Logic II decoder")); TimeStretching = new wxCheckBox(AudioPage, ID_TIMESTRETCHING, _("Time Stretching")); - VolumeSlider = new wxSlider(AudioPage, ID_VOLUME, 0, 1, 100, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL|wxSL_INVERSE); + VolumeSlider = new wxSlider(AudioPage, ID_VOLUME, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL|wxSL_INVERSE); VolumeText = new wxStaticText(AudioPage, wxID_ANY, ""); BackendSelection = new wxChoice(AudioPage, ID_BACKEND, wxDefaultPosition, wxDefaultSize, wxArrayBackends, 0, wxDefaultValidator, wxEmptyString); Latency = new wxSpinCtrl(AudioPage, ID_LATENCY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 30); @@ -801,14 +801,14 @@ void CConfigMain::CreateGUIControls() EnableOC = new wxCheckBox(AdvancedPage, ID_ENABLEOVERCLOCK, _("Enable CPU Clock Override")); OCSlider = new wxSlider(AdvancedPage, ID_OVERCLOCK, 100, 0, 150, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL); wxStaticText* OCDescription = new wxStaticText(AdvancedPage, wxID_ANY, - ("Higher values can make variable-framerate games\n" - "run at a higher framerate, at the expense of CPU.\n" - "Lower values can make variable-framerate games\n" - "run at a lower framerate, saving CPU.\n\n" - "WARNING: Changing this from the default (100%)\n" - "can and will break games and cause glitches.\n" - "Do so at your own risk. Please do not report\n" - "bugs that occur with a non-default clock.\n")); + _("Higher values can make variable-framerate games\n" + "run at a higher framerate, at the expense of CPU.\n" + "Lower values can make variable-framerate games\n" + "run at a lower framerate, saving CPU.\n\n" + "WARNING: Changing this from the default (100%)\n" + "can and will break games and cause glitches.\n" + "Do so at your own risk. Please do not report\n" + "bugs that occur with a non-default clock.\n")); OCText = new wxStaticText(AdvancedPage, wxID_ANY, ""); bOverclockEnable->Add(EnableOC); bOverclock->Add(OCSlider, 1, wxALL, 5); diff --git a/Source/Core/DolphinWX/ConfigMain.h b/Source/Core/DolphinWX/ConfigMain.h index ca89cd42d..f2ecca2c3 100644 --- a/Source/Core/DolphinWX/ConfigMain.h +++ b/Source/Core/DolphinWX/ConfigMain.h @@ -144,13 +144,13 @@ private: wxCheckBox* SkipIdle; wxCheckBox* EnableCheats; wxChoice* Framelimit; - wxSlider* OCSlider; - wxStaticText* OCText; - wxCheckBox* EnableOC; // Advanced wxRadioBox* CPUEngine; wxCheckBox* _NTSCJ; + wxSlider* OCSlider; + wxStaticText* OCText; + wxCheckBox* EnableOC; wxBoxSizer* sDisplayPage; // Display settings @@ -268,7 +268,7 @@ private: void AddRemoveISOPaths(wxCommandEvent& event); void DefaultISOChanged(wxFileDirPickerEvent& event); void DVDRootChanged(wxFileDirPickerEvent& event); - void ApploaderPathChanged(wxFileDirPickerEvent& WXUNUSED(event)); + void ApploaderPathChanged(wxFileDirPickerEvent& WXUNUSED (event)); void NANDRootChanged(wxFileDirPickerEvent& event); private: diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index cb9c23737..62ca00949 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -77,7 +77,6 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() wxStaticText* pad_labels[4]; wxChoice* pad_type_choices[4]; - wxButton* config_buttons[4]; for (int i = 0; i < 4; i++) { @@ -86,8 +85,8 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() // Create an ID for the config button. const wxWindowID button_id = wxWindow::NewControlId(); m_gc_port_config_ids.insert(std::make_pair(button_id, i)); - config_buttons[i] = new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); - config_buttons[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this); + gamecube_configure_bt[i] = new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); + gamecube_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this); // Create a control ID for the choice boxes on the fly. const wxWindowID choice_id = wxWindow::NewControlId(); @@ -122,19 +121,21 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() break; case SIDEVICE_GC_GBA: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]); + gamecube_configure_bt[i]->Disable(); break; case SIDEVICE_AM_BASEBOARD: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]); break; default: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]); + gamecube_configure_bt[i]->Disable(); break; } // Add to the sizer gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL); gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL); - gamecube_flex_sizer->Add(config_buttons[i], 1, wxEXPAND); + gamecube_flex_sizer->Add(gamecube_configure_bt[i], 1, wxEXPAND); } gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5); @@ -488,19 +489,40 @@ void ControllerConfigDiag::OnGameCubePortChanged(wxCommandEvent& event) SIDevices tempType; if (device_name == m_gc_pad_type_strs[1]) + { tempType = SIDEVICE_GC_CONTROLLER; + gamecube_configure_bt[device_num]->Enable(); + } else if (device_name == m_gc_pad_type_strs[2]) + { tempType = SIDEVICE_GC_STEERING; + gamecube_configure_bt[device_num]->Enable(); + } else if (device_name == m_gc_pad_type_strs[3]) + { tempType = SIDEVICE_DANCEMAT; + gamecube_configure_bt[device_num]->Enable(); + } else if (device_name == m_gc_pad_type_strs[4]) + { tempType = SIDEVICE_GC_TARUKONGA; + gamecube_configure_bt[device_num]->Enable(); + } else if (device_name == m_gc_pad_type_strs[5]) + { tempType = SIDEVICE_GC_GBA; + gamecube_configure_bt[device_num]->Disable(); + } else if (device_name == m_gc_pad_type_strs[6]) + { tempType = SIDEVICE_AM_BASEBOARD; + gamecube_configure_bt[device_num]->Enable(); + } else + { tempType = SIDEVICE_NONE; + gamecube_configure_bt[device_num]->Disable(); + } SConfig::GetInstance().m_SIDevice[device_num] = tempType; diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 6fe5122b0..73f424a11 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -89,5 +89,6 @@ private: unsigned int m_orig_wiimote_sources[MAX_BBMOTES]; wxButton* wiimote_configure_bt[MAX_WIIMOTES]; + wxButton* gamecube_configure_bt[4]; std::map m_wiimote_index_from_conf_bt_id; }; diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp index a5f1110ed..df2c7cd24 100644 --- a/Source/Core/DolphinWX/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -431,6 +433,25 @@ void CISOProperties::CreateGUIControls(bool IsWad) // Wii Console EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Wii", "Widescreen")); + // Stereoscopy + wxBoxSizer* const sDepthPercentage = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const DepthPercentageText = new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage: ")); + DepthPercentage = new wxSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200); + DepthPercentage->SetToolTip(_("This value is multiplied with the depth set in the graphics configuration.")); + sDepthPercentage->Add(DepthPercentageText); + sDepthPercentage->Add(DepthPercentage); + + wxBoxSizer* const sConvergenceMinimum = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const ConvergenceMinimumText = new wxStaticText(m_GameConfig, wxID_ANY, _("Convergence Minimum: ")); + ConvergenceMinimum = new wxSpinCtrl(m_GameConfig, ID_CONVERGENCEMINIMUM); + ConvergenceMinimum->SetRange(0, INT32_MAX); + ConvergenceMinimum->SetToolTip(_("This value is added to the convergence value set in the graphics configuration.")); + sConvergenceMinimum->Add(ConvergenceMinimumText); + sConvergenceMinimum->Add(ConvergenceMinimum); + + MonoDepth = new wxCheckBox(m_GameConfig, ID_MONODEPTH, _("Monoscopic Shadows"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Video_Stereoscopy", "StereoEFBMonoDepth")); + MonoDepth->SetToolTip(_("Use a single depth buffer for both eyes. Needed for a few games.")); + wxBoxSizer* const sEmuState = new wxBoxSizer(wxHORIZONTAL); wxStaticText* const EmuStateText = new wxStaticText(m_GameConfig, wxID_ANY, _("Emulation State: ")); arrayStringFor_EmuState.Add(_("Not Set")); @@ -466,10 +487,17 @@ void CISOProperties::CreateGUIControls(bool IsWad) } sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5); + wxStaticBoxSizer* const sbStereoOverrides = + new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy")); + sbStereoOverrides->Add(sDepthPercentage); + sbStereoOverrides->Add(sConvergenceMinimum); + sbStereoOverrides->Add(MonoDepth); + wxStaticBoxSizer * const sbGameConfig = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings")); sbGameConfig->Add(OverrideText, 0, wxEXPAND|wxALL, 5); sbGameConfig->Add(sbCoreOverrides, 0, wxEXPAND); sbGameConfig->Add(sbWiiOverrides, 0, wxEXPAND); + sbGameConfig->Add(sbStereoOverrides, 0, wxEXPAND); sConfigPage->Add(sbGameConfig, 0, wxEXPAND|wxALL, 5); sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL); sEmuState->Add(EmuState, 0, wxEXPAND); @@ -1042,6 +1070,7 @@ void CISOProperties::LoadGameConfig() SetCheckboxValueFromGameini("Core", "BlockMerging", BlockMerging); SetCheckboxValueFromGameini("Core", "DSPHLE", DSPHLE); SetCheckboxValueFromGameini("Wii", "Widescreen", EnableWideScreen); + SetCheckboxValueFromGameini("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); IniFile::Section* default_video = GameIniDefault.GetOrCreateSection("Video"); @@ -1089,6 +1118,14 @@ void CISOProperties::LoadGameConfig() else if (sTemp == "fake-completion") GPUDeterminism->SetSelection(3); + IniFile::Section* default_stereoscopy = GameIniDefault.GetOrCreateSection("Video_Stereoscopy"); + default_stereoscopy->Get("StereoDepthPercentage", &iTemp, 100); + GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iTemp); + DepthPercentage->SetValue(iTemp); + default_stereoscopy->Get("StereoConvergenceMinimum", &iTemp, 0); + GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoConvergenceMinimum", &iTemp); + ConvergenceMinimum->SetValue(iTemp); + PatchList_Load(); ActionReplayList_Load(); m_geckocode_panel->LoadCodes(GameIniDefault, GameIniLocal, OpenISO->GetUniqueID()); @@ -1130,6 +1167,7 @@ bool CISOProperties::SaveGameConfig() SaveGameIniValueFrom3StateCheckbox("Core", "BlockMerging", BlockMerging); SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", DSPHLE); SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", EnableWideScreen); + SaveGameIniValueFrom3StateCheckbox("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); #define SAVE_IF_NOT_DEFAULT(section, key, val, def) do { \ if (GameIniDefault.Exists((section), (key))) { \ @@ -1166,6 +1204,10 @@ bool CISOProperties::SaveGameConfig() SAVE_IF_NOT_DEFAULT("Core", "GPUDeterminismMode", tmp, "Not Set"); + int depth = DepthPercentage->GetValue() > 0 ? DepthPercentage->GetValue() : 100; + SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoDepthPercentage", depth, 100); + SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoConvergenceMinimum", ConvergenceMinimum->GetValue(), 0); + PatchList_Save(); ActionReplayList_Save(); Gecko::SaveCodes(GameIniLocal, m_geckocode_panel->GetCodes()); diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h index 31c2680f0..e31d0ca0b 100644 --- a/Source/Core/DolphinWX/ISOProperties.h +++ b/Source/Core/DolphinWX/ISOProperties.h @@ -26,6 +26,8 @@ class wxButton; class wxCheckBox; class wxCheckListBox; class wxChoice; +class wxSlider; +class wxSpinCtrl; class wxStaticBitmap; class wxTextCtrl; class wxTreeCtrl; @@ -75,6 +77,11 @@ private: // Wii wxCheckBox* EnableWideScreen; + // Stereoscopy + wxSlider* DepthPercentage; + wxSpinCtrl* ConvergenceMinimum; + wxCheckBox* MonoDepth; + wxArrayString arrayStringFor_EmuState; wxChoice* EmuState; wxTextCtrl* EmuIssues; @@ -150,6 +157,9 @@ private: ID_ADDCHEAT, ID_REMOVECHEAT, ID_GPUDETERMINISM, + ID_DEPTHPERCENTAGE, + ID_CONVERGENCEMINIMUM, + ID_MONODEPTH, ID_NAME, ID_GAMEID, diff --git a/Source/Core/DolphinWX/X11Utils.cpp b/Source/Core/DolphinWX/X11Utils.cpp index 06680bcad..c571735eb 100644 --- a/Source/Core/DolphinWX/X11Utils.cpp +++ b/Source/Core/DolphinWX/X11Utils.cpp @@ -37,7 +37,7 @@ bool ToggleFullscreen(Display *dpy, Window win) // Send the event if (!XSendEvent(dpy, DefaultRootWindow(dpy), False, - SubstructureRedirectMask | SubstructureNotifyMask, &event)) + SubstructureRedirectMask | SubstructureNotifyMask, &event)) { ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode."); return false; @@ -56,12 +56,12 @@ void InhibitScreensaver(Display *dpy, Window win, bool suspend) (char *)"xdg-screensaver", (char *)(suspend ? "suspend" : "resume"), id, - nullptr }; + nullptr}; pid_t pid; if (!posix_spawnp(&pid, "xdg-screensaver", nullptr, nullptr, argv, environ)) { int status; - while (waitpid(pid, &status, 0) == -1); + while (waitpid (pid, &status, 0) == -1); DEBUG_LOG(VIDEO, "Started xdg-screensaver (PID = %d)", (int)pid); } @@ -79,7 +79,7 @@ XRRConfiguration::XRRConfiguration(Display *_dpy, Window _win) int XRRMajorVersion, XRRMinorVersion; if (!XRRQueryVersion(dpy, &XRRMajorVersion, &XRRMinorVersion) || - (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3))) + (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3))) { WARN_LOG(VIDEO, "XRRExtension not supported."); bValid = false; @@ -135,7 +135,7 @@ void XRRConfiguration::Update() char *output_name = nullptr; char auxFlag = '\0'; if (SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution.find(':') == - std::string::npos) + std::string::npos) { fullWidth = fb_width; fullHeight = fb_height; @@ -143,7 +143,7 @@ void XRRConfiguration::Update() else { sscanf(SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution.c_str(), - "%m[^:]: %ux%u%c", &output_name, &fullWidth, &fullHeight, &auxFlag); + "%m[^:]: %ux%u%c", &output_name, &fullWidth, &fullHeight, &auxFlag); } bool want_interlaced = ('i' == auxFlag); @@ -173,8 +173,8 @@ void XRRConfiguration::Update() if (output_info->modes[j] == screenResources->modes[k].id) { if (fullWidth == screenResources->modes[k].width && - fullHeight == screenResources->modes[k].height && - want_interlaced == !!(screenResources->modes[k].modeFlags & RR_Interlace)) + fullHeight == screenResources->modes[k].height && + want_interlaced == !!(screenResources->modes[k].modeFlags & RR_Interlace)) { fullMode = screenResources->modes[k].id; if (crtcInfo->x + (int)screenResources->modes[k].width > fs_fb_width) @@ -213,7 +213,7 @@ void XRRConfiguration::Update() else { ERROR_LOG(VIDEO, "Failed to obtain fullscreen size.\n" - "Using current desktop resolution for fullscreen."); + "Using current desktop resolution for fullscreen."); } } @@ -228,16 +228,16 @@ void XRRConfiguration::ToggleDisplayMode(bool bFullscreen) if (bFullscreen) { XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, - crtcInfo->x, crtcInfo->y, fullMode, crtcInfo->rotation, - crtcInfo->outputs, crtcInfo->noutput); + crtcInfo->x, crtcInfo->y, fullMode, crtcInfo->rotation, + crtcInfo->outputs, crtcInfo->noutput); XRRSetScreenSize(dpy, win, fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm); bIsFullscreen = true; } else { XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, - crtcInfo->x, crtcInfo->y, crtcInfo->mode, crtcInfo->rotation, - crtcInfo->outputs, crtcInfo->noutput); + crtcInfo->x, crtcInfo->y, crtcInfo->mode, crtcInfo->rotation, + crtcInfo->outputs, crtcInfo->noutput); XRRSetScreenSize(dpy, win, fb_width, fb_height, fb_width_mm, fb_height_mm); bIsFullscreen = false; } @@ -267,7 +267,7 @@ void XRRConfiguration::AddResolutions(std::vector& resos) bool interlaced = !!(screenResources->modes[k].modeFlags & RR_Interlace); const std::string strRes = std::string(output_info->name) + ": " + - std::string(screenResources->modes[k].name) + (interlaced ? "i" : ""); + std::string(screenResources->modes[k].name) + (interlaced? "i" : ""); // Only add unique resolutions if (std::find(resos.begin(), resos.end(), strRes) == resos.end()) { diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp index 4402b286c..76f553ff5 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp @@ -18,6 +18,11 @@ namespace ciface namespace SDL { +// 10ms = 100Hz which homebrew docs very roughly imply is within WiiMote normal +// range, used for periodic haptic effects though often ignored by devices +static const u16 RUMBLE_PERIOD = 10; +static const u16 RUMBLE_LENGTH_MAX = 500; // ms: enough to span multiple frames at low FPS, but still finite + static std::string GetJoystickName(int index) { #if SDL_VERSION_ATLEAST(2, 0, 0) @@ -27,13 +32,13 @@ static std::string GetJoystickName(int index) #endif } -void Init( std::vector& devices ) +void Init(std::vector& devices) { // this is used to number the joysticks // multiple joysticks with the same name shall get unique ids starting at 0 std::map name_counts; - if (SDL_Init( SDL_INIT_FLAGS ) >= 0) + if (SDL_Init(SDL_INIT_FLAGS) >= 0) { // joysticks for (int i = 0; i < SDL_NumJoysticks(); ++i) @@ -44,7 +49,7 @@ void Init( std::vector& devices ) Joystick* js = new Joystick(dev, i, name_counts[GetJoystickName(i)]++); // only add if it has some inputs/outputs if (js->Inputs().size() || js->Outputs().size()) - devices.push_back( js ); + devices.push_back(js); else delete js; } @@ -68,10 +73,10 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsi std::transform(lcasename.begin(), lcasename.end(), lcasename.begin(), tolower); if ((std::string::npos != lcasename.find("xbox 360")) && - (10 == SDL_JoystickNumButtons(joystick)) && - (5 == SDL_JoystickNumAxes(joystick)) && - (1 == SDL_JoystickNumHats(joystick)) && - (0 == SDL_JoystickNumBalls(joystick))) + (10 == SDL_JoystickNumButtons(joystick)) && + (5 == SDL_JoystickNumAxes(joystick)) && + (1 == SDL_JoystickNumHats(joystick)) && + (0 == SDL_JoystickNumBalls(joystick))) { // this device won't be used return; @@ -79,9 +84,9 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsi #endif if (SDL_JoystickNumButtons(joystick) > 255 || - SDL_JoystickNumAxes(joystick) > 255 || - SDL_JoystickNumHats(joystick) > 255 || - SDL_JoystickNumBalls(joystick) > 255) + SDL_JoystickNumAxes(joystick) > 255 || + SDL_JoystickNumHats(joystick) > 255 || + SDL_JoystickNumBalls(joystick) > 255) { // This device is invalid, don't use it // Some crazy devices(HP webcam 2100) end up as HID devices @@ -111,13 +116,13 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsi #ifdef USE_SDL_HAPTIC // try to get supported ff effects - m_haptic = SDL_HapticOpenFromJoystick( m_joystick ); + m_haptic = SDL_HapticOpenFromJoystick(m_joystick); if (m_haptic) { //SDL_HapticSetGain( m_haptic, 1000 ); //SDL_HapticSetAutocenter( m_haptic, 0 ); - const unsigned int supported_effects = SDL_HapticQuery( m_haptic ); + const unsigned int supported_effects = SDL_HapticQuery(m_haptic); // constant effect if (supported_effects & SDL_HAPTIC_CONSTANT) @@ -126,6 +131,18 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsi // ramp effect if (supported_effects & SDL_HAPTIC_RAMP) AddOutput(new RampEffect(m_haptic)); + + // sine effect + if (supported_effects & SDL_HAPTIC_SINE) + AddOutput(new SineEffect(m_haptic)); + + // triangle effect + if (supported_effects & SDL_HAPTIC_TRIANGLE) + AddOutput(new TriangleEffect(m_haptic)); + + // left-right effect + if (supported_effects & SDL_HAPTIC_LEFTRIGHT) + AddOutput(new LeftRightEffect(m_haptic)); } #endif @@ -178,36 +195,81 @@ std::string Joystick::RampEffect::GetName() const return "Ramp"; } -void Joystick::ConstantEffect::SetState(ControlState state) +std::string Joystick::SineEffect::GetName() const { + return "Sine"; +} + +std::string Joystick::TriangleEffect::GetName() const +{ + return "Triangle"; +} + +std::string Joystick::LeftRightEffect::GetName() const +{ + return "LeftRight"; +} + +void Joystick::HapticEffect::SetState(ControlState state) +{ + memset(&m_effect, 0, sizeof(m_effect)); if (state) { - m_effect.type = SDL_HAPTIC_CONSTANT; - m_effect.constant.length = SDL_HAPTIC_INFINITY; + SetSDLHapticEffect(state); } else { + // this module uses type==0 to indicate 'off' m_effect.type = 0; } - - m_effect.constant.level = (Sint16)(state * 0x7FFF); Update(); } -void Joystick::RampEffect::SetState(ControlState state) +void Joystick::ConstantEffect::SetSDLHapticEffect(ControlState state) { - if (state) - { - m_effect.type = SDL_HAPTIC_RAMP; - m_effect.ramp.length = SDL_HAPTIC_INFINITY; - } - else - { - m_effect.type = 0; - } + m_effect.type = SDL_HAPTIC_CONSTANT; + m_effect.constant.length = RUMBLE_LENGTH_MAX; + m_effect.constant.level = (Sint16)(state * 0x7FFF); +} +void Joystick::RampEffect::SetSDLHapticEffect(ControlState state) +{ + m_effect.type = SDL_HAPTIC_RAMP; + m_effect.ramp.length = RUMBLE_LENGTH_MAX; m_effect.ramp.start = (Sint16)(state * 0x7FFF); - Update(); +} + +void Joystick::SineEffect::SetSDLHapticEffect(ControlState state) +{ + m_effect.type = SDL_HAPTIC_SINE; + m_effect.periodic.period = RUMBLE_PERIOD; + m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); + m_effect.periodic.offset = 0; + m_effect.periodic.phase = 18000; + m_effect.periodic.length = RUMBLE_LENGTH_MAX; + m_effect.periodic.delay = 0; + m_effect.periodic.attack_length = 0; +} + +void Joystick::TriangleEffect::SetSDLHapticEffect(ControlState state) +{ + m_effect.type = SDL_HAPTIC_TRIANGLE; + m_effect.periodic.period = RUMBLE_PERIOD; + m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); + m_effect.periodic.offset = 0; + m_effect.periodic.phase = 18000; + m_effect.periodic.length = RUMBLE_LENGTH_MAX; + m_effect.periodic.delay = 0; + m_effect.periodic.attack_length = 0; +} + +void Joystick::LeftRightEffect::SetSDLHapticEffect(ControlState state) +{ + m_effect.type = SDL_HAPTIC_LEFTRIGHT; + m_effect.leftright.length = RUMBLE_LENGTH_MAX; + // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller + m_effect.leftright.large_magnitude = (Uint16)(state * 0x4000); + m_effect.leftright.small_magnitude = (Uint16)(state * 0xFFFF); } #endif diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h index dc449e9ab..36724f8eb 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h @@ -12,14 +12,14 @@ #if SDL_VERSION_ATLEAST(1, 3, 0) - #define USE_SDL_HAPTIC +#define USE_SDL_HAPTIC #endif #ifdef USE_SDL_HAPTIC - #include - #define SDL_INIT_FLAGS SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC +#include +#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC #else - #define SDL_INIT_FLAGS SDL_INIT_JOYSTICK +#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK #endif namespace ciface @@ -27,7 +27,7 @@ namespace ciface namespace SDL { -void Init( std::vector& devices ); +void Init(std::vector& devices); class Joystick : public Core::Device { @@ -40,8 +40,8 @@ private: Button(u8 index, SDL_Joystick* js) : m_js(js), m_index(index) {} ControlState GetState() const override; private: - SDL_Joystick* const m_js; - const u8 m_index; + SDL_Joystick* const m_js; + const u8 m_index; }; class Axis : public Core::Device::Input @@ -77,10 +77,13 @@ private: protected: void Update(); + virtual void SetSDLHapticEffect(ControlState state) = 0; SDL_HapticEffect m_effect; SDL_Haptic* m_haptic; int m_id; + private: + virtual void SetState(ControlState state) override final; }; class ConstantEffect : public HapticEffect @@ -88,7 +91,8 @@ private: public: ConstantEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} std::string GetName() const override; - void SetState(ControlState state) override; + private: + void SetSDLHapticEffect(ControlState state) override; }; class RampEffect : public HapticEffect @@ -96,7 +100,35 @@ private: public: RampEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} std::string GetName() const override; - void SetState(ControlState state) override; + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class SineEffect : public HapticEffect + { + public: + SineEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class TriangleEffect : public HapticEffect + { + public: + TriangleEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class LeftRightEffect : public HapticEffect + { + public: + LeftRightEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + private: + void SetSDLHapticEffect(ControlState state) override; }; #endif diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index 3bdcdc6b6..c9b312c25 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -477,7 +477,7 @@ void SetCpStatusRegister() { // Here always there is one fifo attached to the GPU m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || (fifo.CPReadPointer == fifo.CPWritePointer); + m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer); m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || !fifo.bFF_GPReadEnable; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index 87a7f1751..b2064d63e 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -125,6 +125,11 @@ void VideoBackendHardware::Video_EndField() { if (s_BackendInitialized) { + // Wait until the GPU thread has swapped. Prevents FIFO overflows. + while (g_ActiveConfig.bUseXFB && SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread && s_swapRequested.IsSet()) + { + Common::YieldCPU(); + } s_swapRequested.Set(); } } diff --git a/docs/gc-font-tool.cpp b/docs/gc-font-tool.cpp new file mode 100644 index 000000000..9f4a2e8e0 --- /dev/null +++ b/docs/gc-font-tool.cpp @@ -0,0 +1,1377 @@ +// GameCube font tool +// Copyright 2015 Dolphin Emulator Project +// Copyright 2015 James Cowgill +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Compile with: +// g++ -O2 -std=c++11 $(freetype-config --cflags --libs) gc-font-tool.cpp + +// Yay0 +// =============== +// Yay0 is the binary compression format used in game cube font files. +// It is heavily based on LZ77 (used by DEFLATE). +// HEADER +// 0 Yay0 magic number +// 4 Size of data uncompressed +// 8 Offset to "link" table +// C Offset to "chunks" table +// +// MASK TABLE +// The mask table immediately follows the header (so there is no offset to it) +// Each byte is a bitmask specifying the type of data to read next. If the bit +// is 1, one byte should be read from the chunks table. If the bit is 0, a link +// from the links table should be read. +// +// CHUNKS TABLE +// This table contains binary data copied into the output stream by the mask +// table, and counters for large links. Each time bytes are read from this +// table, the chunks offset is incremented (bytes are only ever used once). +// +// LINK TABLE +// The link table contains references to blocks of previously decompressed data. +// Each link is 2 bytes long in the format: +// CCOO OOOO +// Where (C+2) is the count of bytes in the link and (O+1) is the offset +// backwards in the already decompressed data to read from. If C == 0, the +// number of bytes in the link is read from the chunks table and 18 is added +// to it. +// +// Font Format +// =============== +// 00 Font type (0 = Windows-1252, 2 = Windows-31J) +// 02 First character +// 04 Last character +// 06 Invalid character +// 08 Ascent +// 0A Decent +// 0C Width of widest character +// 0E Leading space +// 10 Cell width +// 12 Cell height +// 14 Texture size +// 18 Texture format +// 1A Texture columns +// 1C Texture rows +// 1E Texture width +// 20 Texture height +// 22 Offset to character widths table +// 24 Offset to tile data +// 28 Tile data size +// 2A Greyscale colour for 0 values +// 2B Greyscale colour for 1 values +// 2C Greyscale colour for 2 values +// 2D Greyscale colour for 3 values +// This program ignores these values and justs assumes it uses the linear +// 4-bit colours: 00, 55, AA, FF (FIXME?) +// +// Font data is encoded in 2 bit greyscale and in 8x8 blocks. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H + +using std::size_t; +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; + +// Font parameters +const int FNT_CELL_SIZE = 24; +const int FNT_RENDER_SIZE = FNT_CELL_SIZE * 5 / 6; +const int FNT_CELLS_PER_ROW = 21; +const int FNT_PIXMAP_WIDTH = 512; // Must be >= CELL_SIZE * CELLS_PER_ROW + +// The two types of font which can be generated +enum class font_type +{ + ansi, + sjis, +}; + +#define SEQUENCE_4(x) (x), (x)+1, (x)+2, (x)+3 +#define SEQUENCE_8(x) SEQUENCE_4(x), SEQUENCE_4((x)+4) +#define SEQUENCE_16(x) SEQUENCE_8(x), SEQUENCE_8((x)+8) +#define SEQUENCE_32(x) SEQUENCE_16(x), SEQUENCE_16((x)+16) +#define SEQUENCE_64(x) SEQUENCE_32(x), SEQUENCE_32((x)+32) + +// List of unicode codepoints appearing in the ANSI font +const uint16_t ansi_font_table[] = +{ + SEQUENCE_32(0x20), + SEQUENCE_64(0x40), + + 0x20AC, 0, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0, 0x017D, 0, + 0, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0, 0x017E, 0x0178, + SEQUENCE_32(0xA0), + SEQUENCE_64(0xC0), +}; + +// List of unicode codepoints appearing in the SJIS font +const uint16_t sjis_font_table[] = +{ + // Starts at SJIS 0x8740. Any holes are skipped over. + 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, + 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E, + 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, + 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C, + 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, + 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, + 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, + 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7, + 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, + 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04, + 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, + 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7, 0x25C6, 0x25A1, + 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, 0x2192, + 0x2190, 0x2191, 0x2193, 0x3013, 0x2208, 0x220B, 0x2286, 0x2287, + 0x2282, 0x2283, 0x222A, 0x2229, 0x2227, 0x2228, 0xFFE2, 0x21D2, + 0x21D4, 0x2200, 0x2203, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, + 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, + 0x222B, 0x222C, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, + 0x2021, 0x00B6, 0x25EF, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, + 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF21, 0xFF22, 0xFF23, + 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, + 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, + 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF41, + 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, + 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, + 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, + 0xFF5A, 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, + 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, + 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, + 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, + 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, + 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, + 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, + 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, + 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, + 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, + 0x3090, 0x3091, 0x3092, 0x3093, 0x30A1, 0x30A2, 0x30A3, 0x30A4, + 0x30A5, 0x30A6, 0x30A7, 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC, + 0x30AD, 0x30AE, 0x30AF, 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, + 0x30B5, 0x30B6, 0x30B7, 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, + 0x30BD, 0x30BE, 0x30BF, 0x30C0, 0x30C1, 0x30C2, 0x30C3, 0x30C4, + 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, + 0x30CD, 0x30CE, 0x30CF, 0x30D0, 0x30D1, 0x30D2, 0x30D3, 0x30D4, + 0x30D5, 0x30D6, 0x30D7, 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC, + 0x30DD, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, + 0x30E5, 0x30E6, 0x30E7, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, + 0x30ED, 0x30EE, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, + 0x30F5, 0x30F6, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, + 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, + 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, + 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, + 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, + 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, + 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, + 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, + 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, + 0x0435, 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, + 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, + 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, + 0x044C, 0x044D, 0x044E, 0x044F, 0x2500, 0x2502, 0x250C, 0x2510, + 0x2518, 0x2514, 0x251C, 0x252C, 0x2524, 0x2534, 0x253C, 0x2501, + 0x2503, 0x250F, 0x2513, 0x251B, 0x2517, 0x2523, 0x2533, 0x252B, + 0x253B, 0x254B, 0x2520, 0x252F, 0x2528, 0x2537, 0x253F, 0x251D, + 0x2530, 0x2525, 0x2538, 0x2542, + + // ASCII Section + SEQUENCE_32(0x20), + SEQUENCE_32(0x40), + SEQUENCE_16(0x60), + SEQUENCE_8(0x70), + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E, + + // Katakana Section + 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, + SEQUENCE_8(0xFF68), + SEQUENCE_16(0xFF70), + SEQUENCE_32(0xFF80), + 0x30F0, 0x30F1, 0x30EE, 0xFF76, 0xFF79, 0xFF73, 0x30AB, 0x30AE, + 0x30B0, 0x30B2, 0x30B4, 0x3056, 0x3058, 0x305A, 0x305C, 0x305E, + 0x30C0, 0x30C2, 0x30C5, 0x30C7, 0x30C9, 0x30D0, 0x30D1, 0x30D3, + 0x30D4, 0x30D6, 0x30D7, 0x30D9, 0x30DA, 0x30DC, 0x30DD, + + 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, + 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, + 0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162, 0x2163, + 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x3349, 0x3314, + 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336, 0x3351, 0x3357, + 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B, 0x339C, 0x339D, + 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0x337B, 0x301D, 0x301E, + 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6, 0x32A7, 0x32A8, + 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C, 0x2252, 0x2261, + 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220, 0x221F, 0x22BF, + 0x2235, 0x2229, 0x222A, 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, + 0x611B, 0x6328, 0x59F6, 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, + 0x63E1, 0x6E25, 0x65ED, 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, + 0x65A1, 0x6271, 0x5B9B, 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, + 0x9B8E, 0x6216, 0x7C9F, 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, + 0x6848, 0x95C7, 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, + 0x5049, 0x56F2, 0x5937, 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, + 0x6170, 0x6613, 0x6905, 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, + 0x7DEF, 0x80C3, 0x840E, 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, + 0x4E95, 0x4EA5, 0x57DF, 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, + 0x6EA2, 0x9038, 0x7A32, 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, + 0x54BD, 0x54E1, 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, + 0x852D, 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, + 0x70CF, 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, + 0x7893, 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, + 0x59E5, 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, + 0x96F2, 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, + 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, + 0x9834, 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, + 0x99C5, 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, + 0x5712, 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, + 0x6CBF, 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, + 0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, + 0x6C5A, 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC, 0x62BC, + 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, 0x9D2C, + 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, 0x61B6, + 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, 0x6E29, + 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, 0x4FA1, + 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, 0x5BE1, + 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, 0x73C2, + 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, 0x8377, + 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, 0x904E, + 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, 0x81E5, + 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, 0x4F1A, + 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, 0x6094, + 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539, 0x9B41, 0x6666, 0x68B0, + 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, 0x82A5, 0x87F9, 0x958B, + 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916, 0x54B3, 0x5BB3, 0x5D16, + 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, 0x8857, 0x8A72, 0x93A7, + 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, 0x67FF, 0x86CE, 0x920E, + 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, 0x64B9, 0x683C, 0x6838, + 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A, 0x89D2, 0x8D6B, 0x8F03, + 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, 0x5CB3, 0x697D, 0x984D, + 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F, 0x68B6, 0x9C0D, 0x6F5F, + 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, 0x6E07, 0x6ED1, 0x845B, + 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6, 0x691B, 0x6A3A, 0x9784, + 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, 0x938C, 0x565B, 0x9D28, + 0x6822, 0x8305, 0x8431, 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, + 0x4F83, 0x51A0, 0x5BD2, 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, + 0x582A, 0x59E6, 0x5B8C, 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, + 0x611F, 0x6163, 0x61BE, 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, + 0x6B3E, 0x6B53, 0x6C57, 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, + 0x76E3, 0x770B, 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, + 0x809D, 0x8266, 0x839E, 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, + 0x9593, 0x9591, 0x95A2, 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, + 0x542B, 0x5CB8, 0x5DCC, 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, + 0x8D0B, 0x96C1, 0x9811, 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, + 0x559C, 0x5668, 0x57FA, 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, + 0x5E7E, 0x5FCC, 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, + 0x68C4, 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, + 0x5B63, 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, + 0x8ECC, 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, + 0x5993, 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, + 0x7947, 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, + 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, + 0x9ECD, 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, + 0x4EC7, 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, + 0x673D, 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, + 0x7B08, 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, + 0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, + 0x92F8, 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC, 0x4F9B, + 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, 0x5321, + 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, 0x602F, + 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, 0x72ED, + 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, 0x97FF, + 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, 0x5C40, + 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, 0x5747, + 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, 0x79BD, + 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, 0x8FD1, + 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, 0x72D7, + 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, 0x5177, + 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, 0x9685, + 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48, 0x6398, 0x7A9F, 0x6C93, + 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, 0x7C82, 0x6817, 0x7E70, + 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB, 0x8A13, 0x7FA4, 0x8ECD, + 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, 0x50BE, 0x5211, 0x5144, + 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, 0x5F62, 0x5F84, 0x6075, + 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, 0x656C, 0x666F, 0x6842, + 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, 0x7D99, 0x7E4B, 0x7F6B, + 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, 0x8B66, 0x8EFD, 0x981A, + 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287, 0x621F, 0x6483, 0x6FC0, + 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, 0x6F54, 0x7A74, 0x7D50, + 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039, 0x5026, 0x5065, 0x517C, + 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, 0x5ACC, 0x5EFA, 0x61B2, + 0x61F8, 0x62F3, 0x6372, 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, + 0x7814, 0x786F, 0x7D79, 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, + 0x8ED2, 0x9063, 0x9375, 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, + 0x539F, 0x53B3, 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, + 0x7D43, 0x8237, 0x8A00, 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, + 0x547C, 0x56FA, 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, + 0x6545, 0x67AF, 0x6E56, 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, + 0x83F0, 0x864E, 0x8A87, 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, + 0x4E94, 0x4E92, 0x4F0D, 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, + 0x5FA1, 0x609F, 0x68A7, 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, + 0x8B77, 0x9190, 0x4E5E, 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, + 0x5016, 0x5149, 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, + 0x5411, 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, + 0x5B8F, 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, + 0x5F18, 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, + 0x6643, 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, + 0x6D69, 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, + 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, + 0x8154, 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, + 0x8CFC, 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, + 0x9805, 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, + 0x58D5, 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, + 0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, + 0x8170, 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC, 0x6B64, + 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, 0x61C7, + 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, 0x826E, + 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, 0x5DEE, + 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, 0x5750, + 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, 0x585E, + 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, 0x6E08, + 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, 0x7D30, + 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, 0x7F6A, + 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, 0x54B2, + 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, 0x643E, + 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, 0x685C, + 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237, 0x5BDF, 0x62F6, 0x64AE, + 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, 0x7690, 0x9BD6, 0x634C, + 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09, 0x5098, 0x53C2, 0x5C71, + 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, 0x73CA, 0x7523, 0x7B97, + 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, 0x9910, 0x65AC, 0x66AB, + 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, 0x523A, 0x53F8, 0x53F2, + 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9, 0x59FF, 0x5B50, 0x5C4D, + 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, 0x652F, 0x5B5C, 0x65AF, + 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B, 0x6C0F, 0x7345, 0x7949, + 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, 0x8102, 0x81F3, 0x8996, + 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE, 0x8CC7, 0x8CDC, 0x96CC, + 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, 0x5150, 0x5B57, 0x5BFA, + 0x6148, 0x6301, 0x6642, 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, + 0x75D4, 0x78C1, 0x793A, 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, + 0x6C50, 0x9E7F, 0x5F0F, 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, + 0x96EB, 0x4E03, 0x53F1, 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, + 0x6E7F, 0x6F06, 0x75BE, 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, + 0x67F4, 0x829D, 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, + 0x6368, 0x8D66, 0x659C, 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, + 0x8ECA, 0x906E, 0x86C7, 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, + 0x707C, 0x7235, 0x914C, 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, + 0x60F9, 0x4E3B, 0x53D6, 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, + 0x73E0, 0x7A2E, 0x816B, 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, + 0x546A, 0x5BFF, 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, + 0x5468, 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, + 0x79C0, 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, + 0x8846, 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, + 0x96C6, 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, + 0x67D4, 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, + 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, + 0x51FA, 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, + 0x821C, 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, + 0x6E96, 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, + 0x51E6, 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, + 0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, + 0x5E8F, 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F, 0x52DD, + 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, 0x5968, + 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, 0x5E84, + 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, 0x6377, + 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, 0x6A35, + 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, 0x75C7, + 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, 0x7CA7, + 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, 0x8A1F, + 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, 0x937E, + 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, 0x5197, + 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, 0x64FE, + 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, 0x8B72, + 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE, 0x62ED, 0x690D, 0x6B96, + 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, 0x98DF, 0x8755, 0x8FB1, + 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507, 0x5A20, 0x5BDD, 0x5BE9, + 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, 0x68EE, 0x699B, 0x6D78, + 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, 0x79E6, 0x7D33, 0x81E3, + 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, 0x8F9B, 0x9032, 0x91DD, + 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875, 0x58EC, 0x5C0B, 0x751A, + 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, 0x976D, 0x7B25, 0x8ACF, + 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017, 0x5439, 0x5782, 0x5E25, + 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, 0x7FE0, 0x8870, 0x9042, + 0x9154, 0x9310, 0x9318, 0x968F, 0x745E, 0x9AC4, 0x5D07, 0x5D69, + 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, 0x6749, 0x6919, 0x83C5, + 0x9817, 0x96C0, 0x88FE, 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, + 0x755D, 0x662F, 0x51C4, 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, + 0x6210, 0x653F, 0x6574, 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, + 0x6E05, 0x7272, 0x751F, 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, + 0x897F, 0x8AA0, 0x8A93, 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, + 0x6589, 0x7A0E, 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, + 0x6614, 0x6790, 0x77F3, 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, + 0x8D64, 0x8DE1, 0x8E5F, 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, + 0x6298, 0x8A2D, 0x7A83, 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, + 0x8749, 0x4ED9, 0x5148, 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, + 0x5DDD, 0x6226, 0x6247, 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, + 0x6D17, 0x67D3, 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, + 0x7DDA, 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, + 0x8CCE, 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, + 0x524D, 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, + 0x7CCE, 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, + 0x72D9, 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, + 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, + 0x53CC, 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, + 0x5C64, 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, + 0x64CD, 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, + 0x4E89, 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, + 0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, + 0x906D, 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E, 0x81D3, + 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, 0x606F, + 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, 0x8CCA, + 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, 0x5B6B, + 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, 0x6C70, + 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, 0x8235, + 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, 0x8010, + 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, 0x6CF0, + 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, 0x902E, + 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, 0x918D, + 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, 0x6258, + 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, 0x6FC1, + 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA, 0x53E9, 0x4F46, 0x9054, + 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, 0x8FBF, 0x68DA, 0x8C37, + 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39, 0x5358, 0x5606, 0x5766, + 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, 0x6E5B, 0x70AD, 0x77ED, + 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, 0x86CB, 0x8A95, 0x935B, + 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, 0x6A80, 0x6BB5, 0x7537, + 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B, 0x6065, 0x667A, 0x6C60, + 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, 0x9045, 0x99B3, 0x7BC9, + 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010, 0x79E9, 0x7A92, 0x8336, + 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, 0x5FE0, 0x62BD, 0x663C, + 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B, 0x914E, 0x92F3, 0x99D0, + 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, 0x8CAF, 0x4E01, 0x5146, + 0x51CB, 0x558B, 0x5BF5, 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, + 0x5F6B, 0x5FB4, 0x61F2, 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, + 0x753A, 0x773A, 0x8074, 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, + 0x8D85, 0x8DF3, 0x929A, 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, + 0x76F4, 0x6715, 0x6C88, 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, + 0x589C, 0x690E, 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, + 0x6802, 0x63B4, 0x69FB, 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, + 0x7DB4, 0x9354, 0x693F, 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, + 0x722A, 0x540A, 0x91E3, 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, + 0x5243, 0x8C9E, 0x5448, 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, + 0x5EF7, 0x5F1F, 0x608C, 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, + 0x7887, 0x798E, 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, + 0x9013, 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, + 0x6575, 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, + 0x5FB9, 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, + 0x5C55, 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, + 0x70B9, 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, + 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, + 0x767B, 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, + 0x52AA, 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, + 0x51CD, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, + 0x5D8B, 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, + 0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, + 0x7977, 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230, 0x8463, + 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, 0x900F, + 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, 0x540C, + 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, 0x80F4, + 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, 0x5FB3, + 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, 0x8AAD, + 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, 0x82EB, + 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, 0x6C8C, + 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, 0x90A3, + 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, 0x934B, + 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, 0x96E3, + 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, 0x8089, + 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165, 0x5982, 0x5C3F, 0x97EE, + 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, 0x79B0, 0x7962, 0x5BE7, + 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5, 0x637B, 0x649A, 0x71C3, + 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, 0x56A2, 0x60A9, 0x6FC3, + 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, 0x8997, 0x86A4, 0x5DF4, + 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, 0x6D3E, 0x7436, 0x7834, + 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3, 0x5EC3, 0x62DD, 0x6392, + 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, 0x80BA, 0x8F29, 0x914D, + 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973, 0x7164, 0x72FD, 0x8CB7, + 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, 0x79E4, 0x77E7, 0x8429, + 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF, 0x6CCA, 0x767D, 0x7B94, + 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, 0x6F20, 0x7206, 0x7E1B, + 0x83AB, 0x99C1, 0x9EA6, 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, + 0x7B48, 0x6AE8, 0x5E61, 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, + 0x6E8C, 0x767A, 0x9197, 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, + 0x95A5, 0x9CE9, 0x567A, 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, + 0x534A, 0x53CD, 0x53DB, 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, + 0x6C4E, 0x7248, 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, + 0x8CA9, 0x7BC4, 0x91C6, 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, + 0x756A, 0x76E4, 0x78D0, 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, + 0x5983, 0x5E87, 0x5F7C, 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, + 0x6BD4, 0x6CCC, 0x75B2, 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, + 0x80A5, 0x88AB, 0x8AB9, 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, + 0x7C38, 0x5099, 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, + 0x7F8E, 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, + 0x819D, 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, + 0x6867, 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, + 0x6A19, 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, + 0x5EDF, 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, + 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, + 0x8CD3, 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, + 0x5A66, 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, + 0x65A7, 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, + 0x8B5C, 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, + 0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, + 0x847A, 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D, 0x798F, + 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, 0x4ECF, + 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, 0x626E, + 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, 0x805E, + 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, 0x67C4, + 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, 0x58C1, + 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, 0x5909, + 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, 0x52C9, + 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, 0x6355, + 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, 0x6155, + 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, 0x5305, + 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, 0x5E96, + 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B, 0x6CD5, 0x6CE1, 0x70F9, + 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, 0x84EC, 0x8702, 0x8912, + 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD, 0x9CF3, 0x9D6C, 0x4E4F, + 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, 0x5E3D, 0x5FD8, 0x5FD9, + 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, 0x5192, 0x7D21, 0x80AA, + 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, 0x9632, 0x5420, 0x982C, + 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2, 0x6734, 0x7267, 0x7766, + 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, 0x5800, 0x5E4C, 0x5954, + 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469, 0x78E8, 0x9B54, 0x9EBB, + 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, 0x54E9, 0x69D9, 0x5E55, + 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52, 0x685D, 0x4EA6, 0x4FE3, + 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF, + 0x4E07, 0x6162, 0x6E80, 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, + 0x5DF3, 0x7B95, 0x5CAC, 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, + 0x8108, 0x5999, 0x7C8D, 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, + 0x725F, 0x77DB, 0x9727, 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, + 0x540D, 0x547D, 0x660E, 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, + 0x725D, 0x6EC5, 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, + 0x6478, 0x6A21, 0x8302, 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, + 0x7DB2, 0x8017, 0x8499, 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, + 0x52FF, 0x9905, 0x5C24, 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, + 0x7D0B, 0x9580, 0x5301, 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, + 0x91CE, 0x5F25, 0x77E2, 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, + 0x8E8D, 0x9756, 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, + 0x7652, 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, + 0x5BA5, 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, + 0x6D8C, 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, + 0x9091, 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, + 0x8A89, 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, + 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, + 0x7194, 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, + 0x8B21, 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, + 0x6C83, 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, + 0x6765, 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, + 0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, + 0x5229, 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483, 0x75E2, + 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, 0x7ACB, + 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, 0x7559, + 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, 0x65C5, + 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, 0x6599, + 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, 0x826F, + 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, 0x502B, + 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, 0x96A3, + 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, 0x4EE4, + 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, 0x793C, + 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, 0x66A6, + 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, 0x6190, + 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F, 0x84EE, 0x9023, 0x932C, + 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, 0x8DEF, 0x9732, 0x52B4, + 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C, 0x6994, 0x6D6A, 0x6F0F, + 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, 0x874B, 0x90CE, 0x516D, + 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, 0x502D, 0x548C, 0x8A71, + 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, 0x9DF2, 0x4E99, 0x4E98, + 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900, 0x6E7E, 0x7897, 0x8155, + + // Padding to ensure size is 4-byte aligned + 0, 0, 0, +}; + +// Font conversion error +class font_error : public std::runtime_error +{ +public: + explicit font_error(const char* msg) : std::runtime_error(msg) {} +}; + +// Error decompressing a yay0 file +class yay0_error : public std::runtime_error +{ +public: + explicit yay0_error(const char* msg) : std::runtime_error(msg) {} +}; + +// Class which writes bits to the mask vector +class mask_vector_writer +{ +public: + void push_back(bool bit) + { + // Increase array size if needed + if (_next_offset < 0) + { + _data.push_back(0); + _next_offset = 7; + } + + // Insert bit + _data.back() |= (bit << _next_offset); + _next_offset--; + } + + const std::vector& data() const + { + return _data; + } + +private: + std::vector _data; + int8_t _next_offset = -1; +}; + +// Class which reads bits from the mask vector +class mask_vector_reader +{ +public: + mask_vector_reader(const std::vector& input, size_t offset) + :_input(input), _offset(offset) + { + } + + bool pop_front() + { + // Read next byte if needed + if (_next_bit == 8) + { + _next_bit = 0; + _offset++; + } + + bool value = (_input.at(_offset) << _next_bit) & 0x80; + _next_bit++; + return value; + } + +private: + const std::vector& _input; + size_t _offset; + uint8_t _next_bit = 0; +}; + +// Simple image container containing height and width +template +class image_generic +{ +public: + std::vector data; + unsigned width; + + image_generic() = default; + image_generic(const std::vector& idata, unsigned iwidth) + :data(idata), width(iwidth) + { + } + + unsigned height() const + { + return height_scale * data.size() / width; + } +}; + +typedef image_generic<1> image8; +typedef image_generic<4> image2; + +// Wraps a freetype library object + destroys it when done +class ft_library_wrapper +{ +public: + ft_library_wrapper() + { + if (FT_Init_FreeType(&_library) != 0) + throw font_error("error initializing freetype"); + } + + ft_library_wrapper(const ft_library_wrapper&) = delete; + ft_library_wrapper operator=(const ft_library_wrapper&) = delete; + + ~ft_library_wrapper() + { + FT_Done_FreeType(_library); + } + + operator FT_Library() + { + return _library; + } + +private: + FT_Library _library; +}; + +// Reads a 16 bit big endian value from a vector +static uint16_t read_be16(const std::vector& input, size_t offset) +{ + return input.at(offset) << 8 | + input.at(offset + 1); +} + +// Reads a 32 bit big endian value from a vector +static uint32_t read_be32(const std::vector& input, size_t offset) +{ + return read_be16(input, offset) << 16 | + read_be16(input, offset + 2); +} + +// Writes a 16 bit big endian value to a vector +static void write_be16(std::vector& output, uint16_t value) +{ + output.push_back(static_cast(value >> 8)); + output.push_back(static_cast(value)); +} + +// Writes a 32 bit big endian value to a vector +static void write_be32(std::vector& output, uint32_t value) +{ + write_be16(output, static_cast(value >> 16)); + write_be16(output, static_cast(value)); +} + +// Writes a 16 bit little endian value to a vector +static void write_le16(std::vector& output, uint16_t value) +{ + output.push_back(static_cast(value)); + output.push_back(static_cast(value >> 8)); +} + +// Writes a 16 bit little endian value to a vector +static void write_le32(std::vector& output, uint32_t value) +{ + write_le16(output, static_cast(value)); + write_le16(output, static_cast(value >> 16)); +} + +// Clamps an integer between two values +static int clamp(int value, int min, int max) +{ + if (value < min) + value = min; + else if (value > max) + value = max; + + return value; +} + +// Compresses a file using the Yay0 format +static std::vector yay0_compress(const std::vector& input) +{ + const uint16_t MAX_LINK_LEN = 255 + 18; + + size_t input_pos = 0; + mask_vector_writer masks; + std::vector links; + std::vector chunks; + + // Start the main loop to generate a single link or chunk + while (input_pos < input.size()) + { + uint16_t link_count = 0; + uint16_t link_offset; + + // Search the previous 4K for the largest series of bytes to use as a link + for (uint16_t offset = 1; offset <= 0x1000 && offset <= input_pos; offset++) + { + uint16_t count = 0; + bool max_count_reached = false; + + while (input[input_pos - offset + count] == input[input_pos + count]) + { + count++; + + // Limit the number of characters + if (count > MAX_LINK_LEN || input_pos + count >= input.size()) + { + max_count_reached = true; + break; + } + } + + // Handle max link lengths + if (max_count_reached) + { + link_count = count - 1; + link_offset = offset; + break; + } + + // Update best link + if (count > link_count) + { + link_count = count; + link_offset = offset; + } + } + + // Write link or chunk to relevant list + if (link_count >= 3) + { + uint16_t link_count_header = 0; + + if (link_count >= 18) + chunks.push_back(link_count - 18); + else + link_count_header = link_count - 2; + + write_be16(links, link_count_header << 12 | (link_offset - 1)); + masks.push_back(false); + input_pos += link_count; + } + else + { + chunks.push_back(input[input_pos]); + masks.push_back(true); + input_pos++; + } + } + + // Return final array + std::vector result = { 'Y', 'a', 'y', '0' }; + write_be32(result, input.size()); + write_be32(result, 16 + masks.data().size()); + write_be32(result, 16 + masks.data().size() + links.size()); + + result.insert(result.end(), masks.data().begin(), masks.data().end()); + result.insert(result.end(), links.begin(), links.end()); + result.insert(result.end(), chunks.begin(), chunks.end()); + return result; +} + +// Decompresses a file using the Yay0 format +static std::vector yay0_decompress(const std::vector& input) +{ + std::vector result; + + try + { + // Validate header + if (input.at(0) != 'Y' || input.at(1) != 'a' || + input.at(2) != 'y' || input.at(3) != '0') + { + throw yay0_error("yay0: not a yay0 file"); + } + + // Extract header information + uint32_t final_size = read_be32(input, 4); + uint32_t links_offset = read_be32(input, 8); + uint32_t chunks_offset = read_be32(input, 12); + mask_vector_reader masks(input, 16); + + result.reserve(final_size); + + while (result.size() < final_size) + { + // Link or a chunk? + if (masks.pop_front()) + { + // Write chunk to output + result.push_back(input.at(chunks_offset)); + chunks_offset++; + } + else + { + // Examine link contents + uint16_t link = read_be16(input, links_offset); + links_offset += 2; + + int count = (link >> 12) + 2; + if (count == 2) + { + // Read count from chunks list + count = input.at(chunks_offset) + 18; + chunks_offset++; + } + + // Replay the link + unsigned offset = ((link & 0xFFF) + 1); + if (offset > result.size()) + throw yay0_error("yay0: invalid yay0 file"); + + for (int i = 0; i < count; i++) + result.push_back(result.at(result.size() - offset)); + } + } + + return result; + } + catch (std::out_of_range) + { + // Invalid offset somewhere + throw yay0_error("yay0: invalid yay0 file"); + } +} + +// Encodes an 8 bit greyscale bitmap as an i2 font image +static image2 i2encode(const image8& image) +{ + image2 out; + + const std::vector& data = image.data; + unsigned width = image.width; + + // Blocks are 8x8 pixels + // Each row is 2 bytes wide, 16 bytes per block + unsigned width_blocks = width / 8; + unsigned height_blocks = data.size() / (width_blocks * 64); + + out.data.resize(height_blocks * width_blocks * 16); + out.width = width_blocks * 8; + + // Process each row of blocks, and then each block in the row + for (unsigned block_row = 0; block_row < height_blocks; block_row++) + { + for (unsigned block = 0; block < width_blocks; block++) + { + for (unsigned row = 0; row < 8; row++) + { + // Move pixel data to the right place and shrink 8-bit data to 2-bit + unsigned src_row_offset = (block_row * width_blocks * 64) + + (block * 8) + (row * width_blocks * 8); + unsigned dst_row_offset = (block_row * width_blocks * 16) + + (block * 16) + (row * 2); + + out.data[dst_row_offset ] = + (data[src_row_offset ] & 0xC0) | + (data[src_row_offset + 1] >> 2 & 0x30) | + (data[src_row_offset + 2] >> 4 & 0x0C) | + (data[src_row_offset + 3] >> 6 ); + out.data[dst_row_offset + 1] = + (data[src_row_offset + 4] & 0xC0) | + (data[src_row_offset + 5] >> 2 & 0x30) | + (data[src_row_offset + 6] >> 4 & 0x0C) | + (data[src_row_offset + 7] >> 6 ); + } + } + } + + return out; +} + +// Decodes an i2 image into a normal 8-bit greyscale bitmap +static image8 i2decode(const image2& image) +{ + image8 out; + + const std::vector& data = image.data; + unsigned width = image.width; + + // Blocks are 8x8 pixels + // Each row is 2 bytes wide, 16 bytes per block + unsigned width_blocks = (width + 7) / 8; + unsigned height_blocks = data.size() / (width_blocks * 16); + + out.data.resize(height_blocks * width_blocks * 64); + out.width = width_blocks * 8; + + // Process each row of blocks, and then each block in the row + for (unsigned block_row = 0; block_row < height_blocks; block_row++) + { + for (unsigned block = 0; block < width_blocks; block++) + { + for (unsigned row = 0; row < 8; row++) + { + // Move pixel data to the right place and expand 2-bit data to 8-bit + unsigned src_row_offset = (block_row * width_blocks * 16) + + (block * 16) + (row * 2); + unsigned dst_row_offset = (block_row * width_blocks * 64) + + (block * 8) + (row * width_blocks * 8); + + uint8_t src1 = data[src_row_offset]; + uint8_t src2 = data[src_row_offset + 1]; + + out.data[dst_row_offset ] = (src1 >> 6 ) * 0x55; + out.data[dst_row_offset + 1] = (src1 >> 4 & 0x03) * 0x55; + out.data[dst_row_offset + 2] = (src1 >> 2 & 0x03) * 0x55; + out.data[dst_row_offset + 3] = (src1 & 0x03) * 0x55; + + out.data[dst_row_offset + 4] = (src2 >> 6 ) * 0x55; + out.data[dst_row_offset + 5] = (src2 >> 4 & 0x03) * 0x55; + out.data[dst_row_offset + 6] = (src2 >> 2 & 0x03) * 0x55; + out.data[dst_row_offset + 7] = (src2 & 0x03) * 0x55; + } + } + } + + return out; +} + +// Adds an error to the given pixel while clamping it +static void dither_add_clamp(uint8_t& pixel, int error) +{ + if (pixel + error < 0) + pixel = 0; + else if (pixel + error > 255) + pixel = 255; + else + pixel += error; +} + +// Dithers the given image (in-place) using the Floyd–Steinberg dithering algorithm +static void dither_4colour(image8& image) +{ + const unsigned height = image.height(); + + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < image.width; x++) + { + uint8_t old_pixel = image.data[y * image.width + x]; + uint8_t new_pixel = old_pixel & 0xC0; + int error = old_pixel - new_pixel; + + // Store new pixel value + distribute error to surrounding pixels + image.data[y * image.width + x] = new_pixel; + + if (x + 1 < image.width) + dither_add_clamp(image.data[y * image.width + x + 1], error * 7 / 16); + + if (y + 1 < height) + { + dither_add_clamp(image.data[(y + 1) * image.width + x], error * 5 / 16); + if (x > 0) + dither_add_clamp(image.data[(y + 1) * image.width + x - 1], error * 3 / 16); + if (x + 1 < image.width) + dither_add_clamp(image.data[(y + 1) * image.width + x + 1], error / 16); + } + } + } +} + +// Creates the bmp header from an image +static std::vector generate_bmp_header(const image8& img) +{ + const unsigned HEADER_SIZE = 14 + 40 + (4 * 256); + std::vector result; + + // BMP Header + result.push_back('B'); + result.push_back('M'); + write_le32(result, HEADER_SIZE + img.data.size()); + write_le32(result, 0); + write_le32(result, HEADER_SIZE); + + // DIB Header + write_le32(result, 40); // Size of header + write_le32(result, img.width); // Image width + write_le32(result, ~img.height() + 1); // Image height (stored negative) + write_le16(result, 1); // Image planes + write_le16(result, 8); // Bits per pixel + write_le32(result, 0); // Compression type + write_le32(result, 0); // Size of image in bytes + write_le32(result, 0); // X Pixels per metre + write_le32(result, 0); // Y Pixels per metre + write_le32(result, 0); // Colour table size + write_le32(result, 0); // Colour table required + + // Colour table (RGBA) + for (unsigned i = 0; i < 256; i++) + write_be32(result, 0x01010100 * i); + + return result; +} + +// Converts a Yay0 font to a bitmap +static std::vector fnt_to_bmp(const std::vector& input) +{ + std::vector uncompressed_fnt = yay0_decompress(input); + + // Descramble image + uint32_t start = read_be32(uncompressed_fnt, 0x24); + image2 i2data; + i2data.width = read_be16(uncompressed_fnt, 0x1E); + i2data.data.assign(uncompressed_fnt.begin() + start, uncompressed_fnt.end()); + + image8 dest = i2decode(i2data); + + // Write bitmap out + std::vector bitmap = generate_bmp_header(dest); + bitmap.insert(bitmap.end(), dest.data.begin(), dest.data.end()); + + return bitmap; +} + +// Generates a gamecube font file +static std::vector generate_fnt( + font_type type, + const std::vector& widths, + const image2& pixmap) +{ + std::vector out; + + write_be16(out, type == font_type::ansi ? 0 : 2); + write_be16(out, type == font_type::ansi ? 0x0020 : 0x8140); + write_be16(out, type == font_type::ansi ? 0x00FF : 0x9872); + write_be16(out, 0x20); + write_be16(out, FNT_CELL_SIZE); + write_be16(out, 0x00); + write_be16(out, FNT_CELL_SIZE); + write_be16(out, FNT_CELL_SIZE * 7 / 6); + write_be16(out, FNT_CELL_SIZE); + write_be16(out, FNT_CELL_SIZE); + write_be32(out, FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH / 2); + write_be16(out, 0x00); + write_be16(out, FNT_CELLS_PER_ROW); + write_be16(out, FNT_CELLS_PER_ROW); + write_be16(out, FNT_PIXMAP_WIDTH); + write_be16(out, FNT_PIXMAP_WIDTH); + write_be16(out, 0x30); + write_be32(out, 0x30 + widths.size()); + write_be32(out, 2 * pixmap.data.size()); + write_be32(out, 0x0055AAFF); + + out.insert(out.end(), widths.begin(), widths.end()); + out.insert(out.end(), pixmap.data.begin(), pixmap.data.end()); + return out; +} + +// Generates the font data arrays from a freetype font +// font_buf = input font data +// font_table = list of unicode codepoints appearing in the font +// font_table_size = number of characters in font_table +// out_widths = output vector to store advance widths of each character +// out_pixmap = output vector to store pixmap (unscrambled) +static void freetype_to_fnt_data( + const std::vector& font_buf, + const uint16_t* font_table, + unsigned font_table_size, + std::vector& out_widths, + image8& out_pixmap) +{ + // Initialize freetype + ft_library_wrapper library; + + // Initialize fontface + FT_Face face; + if (FT_New_Memory_Face(library, font_buf.data(), font_buf.size(), 0, &face) != 0) + throw font_error("error reading font data"); + + // Set size to render glyphs at + if (FT_Set_Pixel_Sizes(face, 0, FNT_RENDER_SIZE) != 0) + throw font_error("error selecting font size (is the font scalable?)"); + + // Get descender size in pixels (negative value) + const int descender = face->size->metrics.descender >> 6; + + // Resize output vectors + const unsigned cpr_squared = FNT_CELLS_PER_ROW * FNT_CELLS_PER_ROW; + const unsigned pages = (font_table_size + cpr_squared - 1) / cpr_squared; + + out_widths.clear(); + out_widths.resize(font_table_size); + out_pixmap.data.clear(); + out_pixmap.data.resize(FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH * pages); + out_pixmap.width = FNT_PIXMAP_WIDTH; + + // Render each glyph in the list + for (unsigned i = 0; i < font_table_size; i++) + { + unsigned glyph_index = FT_Get_Char_Index(face, font_table[i]); + + // Skip undefined characters + if (glyph_index == 0) + continue; + + // Load glyph data + if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER) != 0) + throw font_error("error loading glyph"); + + // Record width + out_widths[i] = clamp(face->glyph->metrics.horiAdvance >> 6, 0, FNT_CELL_SIZE); + + // Calculate cell offset within final image + const unsigned cell_page = i / cpr_squared; + const unsigned cell_y = (i % cpr_squared) / FNT_CELLS_PER_ROW; + const unsigned cell_x = (i % cpr_squared) % FNT_CELLS_PER_ROW; + const int cell_offset = + cell_page * FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH + + cell_y * FNT_PIXMAP_WIDTH * FNT_CELL_SIZE + + cell_x * FNT_CELL_SIZE; + + // Copy glyph image + const FT_Bitmap* bitmap = &face->glyph->bitmap; + const int xStart = face->glyph->bitmap_left; + const int yStart = FNT_CELL_SIZE + descender - face->glyph->bitmap_top; + const int xMax = xStart + bitmap->width; + const int yMax = yStart + bitmap->rows; + + for (int y = yStart; y < yMax; y++) + { + for (int x = xStart; x < xMax; x++) + { + // Clip pixels outsize the cell + if (y < 0 || x < 0 || x >= FNT_CELL_SIZE || y >= FNT_CELL_SIZE) + continue; + + // Copy pixel + int srcOff = (y - yStart) * bitmap->width + (x - xStart); + int dstOff = cell_offset + y * FNT_PIXMAP_WIDTH + x; + out_pixmap.data[dstOff] = bitmap->buffer[srcOff]; + } + } + } +} + +// Converts a freetype font to a gamecube compressed font +static std::vector freetype_to_fnt(const std::vector& font_buf, font_type type, bool dither) +{ + // Get font table from font type + const uint16_t* font_table; + unsigned font_table_size; + + if (type == font_type::ansi) + { + font_table = ansi_font_table; + font_table_size = sizeof(ansi_font_table) / 2; + } + else + { + font_table = sjis_font_table; + font_table_size = sizeof(sjis_font_table) / 2; + } + + // Generate pixmap + std::vector widths; + image8 pixmap; + freetype_to_fnt_data(font_buf, font_table, font_table_size, widths, pixmap); + + // Dither image + if (dither) + dither_4colour(pixmap); + + // Scramble pixmap, generate fnt header and compress + return yay0_compress(generate_fnt(type, widths, i2encode(pixmap))); +} + +static void usage() +{ + std::cerr << "GameCube font tool" << std::endl; + std::cerr << std::endl; + std::cerr << "gc-font-tool " << std::endl; + std::cerr << " c = compress using yay0" << std::endl; + std::cerr << " d = decompress a yay0 file" << std::endl; + std::cerr << " a = generate an ansi gamecube font file from a true type font" << std::endl; + std::cerr << " s = generate a sjis gamecube font file from a true type font" << std::endl; + std::cerr << " b = like a, but do not dither the final image" << std::endl; + std::cerr << " t = like s, but do not dither the final image" << std::endl; + std::cerr << " v = generate a bitmap showing the contents of a gamecube font file" << std::endl; + std::cerr << " input and output may be files or - for stdin/stdout" << std::endl; +} + +// Reads an entire file into a vector +static std::vector read_file(const std::string& filename) +{ + std::ifstream in_file; + std::istream* input; + + // Open stream + if (filename == "-") + { + std::cin.exceptions(std::ios::failbit); + input = &std::cin; + } + else + { + in_file.exceptions(std::ios::failbit); + in_file.open(filename, std::ios::in | std::ios::binary); + input = &in_file; + } + + return std::vector(std::istreambuf_iterator(*input), + std::istreambuf_iterator()); +} + +// Writes a byte vector to a file +static void write_file(const std::string& filename, const std::vector data) +{ + std::ofstream out_file; + std::ostream* output; + + // Open stream + if (filename == "-") + { + std::cout.exceptions(std::ios::failbit); + output = &std::cout; + } + else + { + out_file.exceptions(std::ios::failbit); + out_file.open(filename, std::ios::out | std::ios::binary); + output = &out_file; + } + + std::copy(data.begin(), data.end(), + std::ostreambuf_iterator(*output)); +} + +int main(int argc, char* argv[]) +{ + // Get arguments + if (argc != 4) + { + usage(); + return 1; + } + + try + { + // Read input file + std::vector input = read_file(argv[2]); + + // Do operation + const std::string mode = argv[1]; + char mode_char = 0; + + if (mode.length() == 2 && mode[0] == '-') + mode_char = mode[1]; + else if (mode.length() == 1) + mode_char = mode[0]; + + std::vector result; + switch (mode_char) + { + case 'c': result = yay0_compress(input); break; + case 'd': result = yay0_decompress(input); break; + case 'a': result = freetype_to_fnt(input, font_type::ansi, true); break; + case 's': result = freetype_to_fnt(input, font_type::sjis, true); break; + case 'b': result = freetype_to_fnt(input, font_type::ansi, false); break; + case 't': result = freetype_to_fnt(input, font_type::sjis, false); break; + case 'v': result = fnt_to_bmp(input); break; + default: + usage(); + return 1; + } + + // Write output file + write_file(argv[3], result); + return 0; + } + catch (const std::ios_base::failure& e) + { + std::cerr << "gc-font-tool: io error: " << std::strerror(errno) << std::endl; + return 1; + } + catch (const std::runtime_error& e) + { + std::cerr << "gc-font-tool: " << e.what() << std::endl; + return 1; + } +}