Support Apple Silicon (macOS ARM Universal Binary) (#253)

* Add audio arm64 cpp into Xcode project

* Build universal binary for SDL2 also

* Add vixl aarch64 dependency + build arm64 in cmake

* hardcode pagesize for M1 CPU

* Use `MAP_JIT` and toggle between RX and RW

* add pthread.h for cmake

* Disable audio dynarec temporary

* Enable aica arm dynarec

* Supports `br` with condition

* Dynamic linker flag for libSDL2.a since Homebrew path is different on arm (for xcodeproj)

* Fallback path for Intel

* de-dup for arm64, allow cross compilation on both Intel and Apple Silicon Mac

* Rename WriteProtect() to JITWriteProtect(), Move JITWriteProtect from arm7_rec to arm7_rec_arm64

* Remove CodeCache memset

* Remove keyboard_device.cpp from xcodeproj

* Use hard tab

* Update libchdr to support compiling on M1 (thanks @scribam)
This commit is contained in:
vkedwardli 2021-07-23 13:34:12 -07:00 committed by GitHub
parent 147bd8341d
commit 3c483c61e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 139 additions and 28 deletions

View File

@ -21,6 +21,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake")
if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum macOS deployment version")
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
endif()
project(flycast)
@ -813,7 +814,7 @@ if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3dx9)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)" AND NOT APPLE)
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/vixl)
target_sources(${PROJECT_NAME} PRIVATE
core/rec-ARM/rec_arm.cpp
@ -847,7 +848,9 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
core/deps/vixl/pool-manager-impl.h
core/deps/vixl/utils-vixl.cc
core/deps/vixl/utils-vixl.h)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
set(KNOWN_ARCHITECTURE_DETECTED ON)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*)" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/vixl)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/vixl/aarch64/abi-aarch64.h
@ -892,7 +895,9 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
core/deps/vixl/utils-vixl.cc
core/deps/vixl/utils-vixl.h)
target_sources(${PROJECT_NAME} PRIVATE core/rec-ARM64/rec_arm64.cpp core/rec-ARM64/arm64_regalloc.h)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*")
set(KNOWN_ARCHITECTURE_DETECTED ON)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*" OR CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
add_subdirectory(core/deps/xbyak)
target_link_libraries(${PROJECT_NAME} PRIVATE xbyak::xbyak)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
@ -908,7 +913,9 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD6
core/rec-x64/rec_x64.cpp
core/rec-x64/x64_regalloc.h)
endif()
else()
set(KNOWN_ARCHITECTURE_DETECTED ON)
endif()
if(NOT KNOWN_ARCHITECTURE_DETECTED)
message(FATAL_ERROR "Unknown target processor: ${CMAKE_SYSTEM_PROCESSOR}")
endif()

@ -1 +1 @@
Subproject commit 00319cf31f034e4d468a49a60265c7c5b8305b70
Subproject commit d3ffd20ca71686877372dea7f9eed359dbf65ba2

View File

@ -107,9 +107,17 @@ class Arm7Compiler : public MacroAssembler
void call(void *loc)
{
ptrdiff_t offset = reinterpret_cast<uintptr_t>(loc) - GetBuffer()->GetStartAddress<uintptr_t>();
Label function_label;
BindToOffset(&function_label, offset);
Bl(&function_label);
if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024)
{
Mov(x4, reinterpret_cast<uintptr_t>(loc));
Blr(x4);
}
else
{
Label function_label;
BindToOffset(&function_label, offset);
Bl(&function_label);
}
}
Operand getOperand(const ArmOp::Operand& arg, const Register& scratch_reg)
@ -543,6 +551,7 @@ public:
void compile(const std::vector<ArmOp>& block_ops, u32 cycles)
{
JITWriteProtect(false);
Ldr(w1, arm_reg_operand(CYCL_CNT));
Sub(w1, w1, cycles);
Str(w1, arm_reg_operand(CYCL_CNT));
@ -622,6 +631,7 @@ public:
#endif
delete regalloc;
regalloc = nullptr;
JITWriteProtect(true);
}
void generateMainLoop()
@ -632,6 +642,7 @@ public:
verify(arm_compilecode != nullptr);
return;
}
JITWriteProtect(false);
Label arm_dispatch_label;
Label arm_dofiq;
Label arm_exit;
@ -686,6 +697,7 @@ public:
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>(),
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
recompiler::advance(GetBuffer()->GetSizeInBytes());
JITWriteProtect(true);
}
};

View File

@ -423,7 +423,6 @@ static void recSh4_Init()
// Ensure the pointer returned is non-null
verify(CodeCache != NULL);
memset(CodeCache, 0xFF, CODE_SIZE + TEMP_CODE_SIZE);
TempCodeCache = CodeCache + CODE_SIZE;
ngen_init();
bm_ResetCache();

View File

@ -249,11 +249,21 @@ bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code
{
// Well it failed, use another approach, unmap the memory area and remap it back.
// Seems it works well on Darwin according to reicast code :P
#ifndef __ARM_MAC__
munmap(code_area, size);
void *ret_ptr = mmap(code_area, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
// Ensure it's the area we requested
if (ret_ptr != code_area)
return false; // Couldn't remap it? Perhaps RWX is disabled? This should never happen in any supported Unix platform.
#else
// MAP_JIT and toggleable write protection is required on Apple Silicon
// Cannot use MAP_FIXED with MAP_JIT
void *ret_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1, 0);
if ( ret_ptr == MAP_FAILED )
return false;
*code_area_rwx = ret_ptr;
return true;
#endif
}
// Pointer location should be same:

View File

@ -278,6 +278,7 @@ public:
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
{
//printf("REC-ARM64 compiling %08x\n", block->addr);
JITWriteProtect(false);
this->block = block;
CheckBlock(force_checks, block);
@ -959,6 +960,7 @@ public:
RelinkBlock(block);
Finalize();
JITWriteProtect(true);
}
void ngen_CC_Start(shil_opcode* op)
@ -1518,11 +1520,18 @@ private:
void GenCallRuntime(R (*function)(P...))
{
ptrdiff_t offset = reinterpret_cast<uintptr_t>(function) - reinterpret_cast<uintptr_t>(CC_RW2RX(GetBuffer()->GetStartAddress<void*>()));
verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024);
verify((offset & 3) == 0);
Label function_label;
BindToOffset(&function_label, offset);
Bl(&function_label);
if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024)
{
Mov(x4, reinterpret_cast<uintptr_t>(function));
Blr(x4);
}
else
{
Label function_label;
BindToOffset(&function_label, offset);
Bl(&function_label);
}
}
void GenCall(DynaCode *function)
@ -1539,14 +1548,34 @@ private:
void GenBranchRuntime(R (*target)(P...), Condition cond = al)
{
ptrdiff_t offset = reinterpret_cast<uintptr_t>(target) - reinterpret_cast<uintptr_t>(CC_RW2RX(GetBuffer()->GetStartAddress<void*>()));
verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024);
verify((offset & 3) == 0);
Label target_label;
BindToOffset(&target_label, offset);
if (cond == al)
B(&target_label);
if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024)
{
if (cond == al)
{
Mov(x4, reinterpret_cast<uintptr_t>(target));
Br(x4);
}
else
{
Label skip_target;
Condition inverse_cond = (Condition)((u32)cond ^ 1);
B(&skip_target, inverse_cond);
Mov(x4, reinterpret_cast<uintptr_t>(target));
Br(x4);
Bind(&skip_target);
}
}
else
B(&target_label, cond);
{
Label target_label;
BindToOffset(&target_label, offset);
if (cond == al)
B(&target_label);
else
B(&target_label, cond);
}
}
void GenBranch(DynaCode *code, Condition cond = al)
@ -2116,8 +2145,8 @@ private:
std::vector<const VRegister*> call_fregs;
Arm64RegAlloc regalloc;
RuntimeBlockInfo* block = NULL;
const int read_memory_rewrite_size = 3; // ubfx, add, ldr
const int write_memory_rewrite_size = 3; // ubfx, add, str
const int read_memory_rewrite_size = 5; // ubfx, add, ldr
const int write_memory_rewrite_size = 5; // ubfx, add, str
};
static Arm64Assembler* compiler;
@ -2188,6 +2217,7 @@ static const u32 op_sizes[] = {
};
bool ngen_Rewrite(host_context_t &context, void *faultAddress)
{
JITWriteProtect(false);
//LOGI("ngen_Rewrite pc %zx\n", context.pc);
u32 *code_ptr = (u32 *)CC_RX2RW(context.pc);
u32 armv8_op = *code_ptr;
@ -2219,6 +2249,7 @@ bool ngen_Rewrite(host_context_t &context, void *faultAddress)
assembler->Finalize(true);
delete assembler;
context.pc = (unat)CC_RW2RX(code_rewrite);
JITWriteProtect(true);
return true;
}
@ -2227,12 +2258,14 @@ static void generate_mainloop()
{
if (mainloop != nullptr)
return;
JITWriteProtect(false);
compiler = new Arm64Assembler();
compiler->GenMainloop();
delete compiler;
compiler = nullptr;
JITWriteProtect(true);
}
RuntimeBlockInfo* ngen_AllocateBlock()
@ -2250,11 +2283,13 @@ u32 DynaRBI::Relink()
{
#ifndef NO_BLOCK_LINKING
//printf("DynaRBI::Relink %08x\n", this->addr);
JITWriteProtect(false);
Arm64Assembler *compiler = new Arm64Assembler((u8 *)this->code + this->relink_offset);
u32 code_size = compiler->RelinkBlock(this);
compiler->Finalize(true);
delete compiler;
JITWriteProtect(true);
return code_size;
#else

View File

@ -12,7 +12,11 @@
#undef PAGE_MASK
#define PAGE_MASK (PAGE_SIZE-1)
#else
#if defined(__APPLE__) && defined(__aarch64__)
#define PAGE_SIZE 16384
#else
#define PAGE_SIZE 4096
#endif
#define PAGE_MASK (PAGE_SIZE-1)
#endif

View File

@ -139,6 +139,14 @@ enum HollyInterruptID
int darw_printf(const char* Text,...);
#endif
#if defined(__APPLE__) && defined(__MACH__) && HOST_CPU == CPU_ARM64
#define __ARM_MAC__
#include "pthread.h"
static void JITWriteProtect(bool enabled) { if (__builtin_available(macOS 11.0, *)) pthread_jit_write_protect_np(enabled); }
#else
__forceinline static void JITWriteProtect(bool enabled) {}
#endif
//includes from c++rt
#include <vector>
#include <string>

View File

@ -7,5 +7,4 @@
REI_APP_NAME = Flycast
PRODUCT_NAME = Flycast
CFLAGS =
LIBSDL = /usr/local/lib/libSDL2.a

View File

@ -306,7 +306,6 @@
AEE6278822131BB500EC7E89 /* mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6278522131BB500EC7E89 /* mapping.cpp */; };
AEE6278E2224762000EC7E89 /* imgui_impl_opengl3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6278B2224762000EC7E89 /* imgui_impl_opengl3.cpp */; };
AEE6279422247C0A00EC7E89 /* gui_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279222247C0A00EC7E89 /* gui_util.cpp */; };
AEE6279622247C2B00EC7E89 /* keyboard_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */; };
AEF25646227C442F00348550 /* fastmmu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF25644227C442F00348550 /* fastmmu.cpp */; };
AEF2564822886A2E00348550 /* posix_vmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF2564722886A2E00348550 /* posix_vmem.cpp */; };
AEF256502294060400348550 /* ZipArchive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF2564A2294060300348550 /* ZipArchive.cpp */; };
@ -943,7 +942,6 @@
AEE6278D2224762000EC7E89 /* imgui_impl_opengl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_opengl3.h; sourceTree = "<group>"; };
AEE6279222247C0A00EC7E89 /* gui_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gui_util.cpp; sourceTree = "<group>"; };
AEE6279322247C0A00EC7E89 /* gui_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gui_util.h; sourceTree = "<group>"; };
AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keyboard_device.cpp; sourceTree = "<group>"; };
AEF25644227C442F00348550 /* fastmmu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fastmmu.cpp; sourceTree = "<group>"; };
AEF25645227C442F00348550 /* wince.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wince.h; sourceTree = "<group>"; };
AEF2564722886A2E00348550 /* posix_vmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = posix_vmem.cpp; sourceTree = "<group>"; };
@ -1530,6 +1528,7 @@
84B7BDCF1B72720100F9733F /* dsp.h */,
AE8C27332111A31100D4D8F4 /* dsp_interp.cpp */,
AE7BCB512406EDB0007285F8 /* dsp_x64.cpp */,
F2D7C89E265B304F002812E2 /* dsp_arm64.cpp */,
84B7BDD01B72720100F9733F /* sgc_if.cpp */,
84B7BDD11B72720100F9733F /* sgc_if.h */,
);
@ -1540,6 +1539,7 @@
isa = PBXGroup;
children = (
AE7BCB562415515B007285F8 /* arm7_rec_x64.cpp */,
F2D7C8A2265B3082002812E2 /* arm7_rec_arm64.cpp */,
AE7BCB572415515B007285F8 /* arm7_rec.cpp */,
AE7BCB552415515B007285F8 /* arm7_rec.h */,
84B7BDD31B72720100F9733F /* arm-new.h */,
@ -2747,6 +2747,7 @@
84B7BF2A1B72720200F9733F /* arm7.cpp in Sources */,
AE90679D235DF80400CE473C /* osd.cpp in Sources */,
AE82C67D25B64AE200C79BC2 /* zip_get_name.c in Sources */,
F2D7C8A3265B3082002812E2 /* arm7_rec_arm64.cpp in Sources */,
84B7BF551B72720200F9733F /* sh4_mem.cpp in Sources */,
AE82C69F25B64AE200C79BC2 /* zip_open.c in Sources */,
AE649C2C218C553A00EF4A81 /* Lzma86Enc.c in Sources */,
@ -2914,6 +2915,7 @@
84B7BF771B72720200F9733F /* reios_elf.cpp in Sources */,
AE9125CC25E3BBDC00ED4594 /* option.cpp in Sources */,
84B7BF5C1B72720200F9733F /* common.cpp in Sources */,
F2D7C89F265B304F002812E2 /* dsp_arm64.cpp in Sources */,
AE82C6BE25B64AE200C79BC2 /* zip_source_crc.c in Sources */,
84B7BF681B72720200F9733F /* audiobackend_directsound.cpp in Sources */,
AE2A2D5C21D68470004B308D /* awcartridge.cpp in Sources */,
@ -3165,7 +3167,7 @@
);
INFOPLIST_FILE = "emulator-osx/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = /usr/local/lib/libSDL2.a;
OTHER_LDFLAGS = "$(LIBSDL)";
OTHER_LIBTOOLFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.flyinghead.Flycast;
PRODUCT_NAME = "$(REI_APP_NAME)";
@ -3217,7 +3219,7 @@
);
INFOPLIST_FILE = "emulator-osx/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = /usr/local/lib/libSDL2.a;
OTHER_LDFLAGS = "$(LIBSDL)";
OTHER_LIBTOOLFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.flyinghead.Flycast;
PRODUCT_NAME = "$(REI_APP_NAME)";

View File

@ -1,10 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "if [[ `uname -m` == &apos;arm64&apos; ]]; then&#10; sdl2path=&apos;/opt/homebrew/lib/libSDL2.a&apos;&#10;else&#10; sdl2path=&apos;/usr/local/lib/libSDL2.a&apos;&#10;fi&#10;sed -i &apos;&apos; &quot;s|LIBSDL.*|LIBSDL = $sdl2path|&quot; $SRCROOT/emulator-osx/DreamcastConfig.xcconfig&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "84A388B21B1CDD3E000166C0"
BuildableName = "Flycast.app"
BlueprintName = "reicast-osx"
ReferencedContainer = "container:reicast-osx.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View File

@ -5,6 +5,7 @@ class Sdl2 < Formula
sha256 "d8215b571a581be1332d2106f8036fcb03d12a70bae01e20f424976d275432bc"
license "Zlib"
revision 1
env :std
livecheck do
url "https://www.libsdl.org/download-2.0.php"
@ -31,6 +32,20 @@ class Sdl2 < Formula
end
def install
# Delete default flags for cross compiling
ENV.delete('CFLAGS')
ENV.delete('CXXFLAGS')
ENV.delete('CPPFLAGS')
ENV.delete('LDFLAGS')
ENV.delete('CMAKE_PREFIX_PATH')
ENV.delete('CMAKE_FRAMEWORK_PATH')
ENV.delete('CPATH')
sdkpath = %x[xcode-select -p]
sdkpath = sdkpath.chomp + "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
ENV['SDKROOT'] = sdkpath
ENV['CPP'] = "/usr/bin/cpp"
ENV['CXXCPP'] = "/usr/bin/cpp"
# we have to do this because most build scripts assume that all SDL modules
# are installed to the same prefix. Consequently SDL stuff cannot be
# keg-only but I doubt that will be needed.
@ -41,6 +56,8 @@ class Sdl2 < Formula
args = %W[--prefix=#{prefix} --without-x --enable-hidapi]
args << "CFLAGS=-mmacosx-version-min=10.9"
args << "CXXFLAGS=-mmacosx-version-min=10.9"
args << "CC=gcc -isysroot #{sdkpath} -arch arm64 -arch x86_64"
args << "CXX=g++ -isysroot #{sdkpath} -arch arm64 -arch x86_64"
system "./configure", *args
system "make", "install"
end