Merge remote-tracking branch 'origin/upstream-master'
This commit is contained in:
commit
d38e094ba0
|
@ -48,6 +48,9 @@ reicast-ios.xccheckout
|
|||
shell/linux/.map
|
||||
shell/linux/nosym-reicast.elf
|
||||
shell/linux/reicast.elf
|
||||
shell/linux/reicast_naomi.elf
|
||||
shell/linux/reicast_awave.elf
|
||||
shell/linux/dispframe.elf
|
||||
|
||||
# Visual Studio
|
||||
generated
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
|
||||
|
||||
set(TNAME reicast)
|
||||
|
||||
project(${TNAME})
|
||||
|
||||
enable_language(ASM)
|
||||
enable_language(ASM_MASM)
|
||||
|
||||
set(DEBUG_CMAKE ON)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
|
||||
set(reicast_root_path "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(reicast_core_path "${reicast_root_path}/core")
|
||||
set(reicast_shell_path "${reicast_root_path}/shell")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${reicast_shell_path}/cmake")
|
||||
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_VERSION --tags)
|
||||
configure_file(${reicast_core_path}/version.h.in ${reicast_core_path}/version.h @ONLY)
|
||||
|
||||
|
||||
|
||||
|
||||
## reicast build modules #
|
||||
#
|
||||
|
||||
set(reicast_SRCS "")
|
||||
|
||||
include(config) # configure build settings, must be first
|
||||
|
||||
|
||||
|
||||
### libdreamcast.cmake #########################################################################
|
||||
|
||||
set(d_core ${reicast_core_path})
|
||||
|
||||
file(GLOB_RECURSE hw_SRCS ${d_core}/hw/*.cpp ${d_core}/hw/*.h)
|
||||
|
||||
file(GLOB cfg_SRCS ${d_core}/cfg/*.cpp ${d_core}/cfg/*.h)
|
||||
file(GLOB rend_SRCS ${d_core}/rend/*.cpp ${d_core}/rend/*.h)
|
||||
file(GLOB input_SRCS ${d_core}/input/*.cpp ${d_core}/input/*.h)
|
||||
file(GLOB reios_SRCS ${d_core}/reios/*.cpp ${d_core}/reios/*.h)
|
||||
file(GLOB imgread_SRCS ${d_core}/imgread/*.cpp ${d_core}/imgread/*.h)
|
||||
file(GLOB profiler_SRCS ${d_core}/profiler/*.cpp ${d_core}/profiler/*.h)
|
||||
file(GLOB archive_SRCS ${d_core}/archive/*.cpp ${d_core}/archive/*.h)
|
||||
|
||||
#### option(rend)
|
||||
file(GLOB gl4_SRCS ${d_core}/rend/gl4/*.cpp ${d_core}/rend/gl4/*.h)
|
||||
file(GLOB gles_SRCS ${d_core}/rend/gles/*.cpp ${d_core}/rend/gles/*.h)
|
||||
|
||||
set(core_SRCS
|
||||
${hw_SRCS}
|
||||
${cfg_SRCS}
|
||||
${rend_SRCS}
|
||||
${gl4_SRCS}
|
||||
${gles_SRCS}
|
||||
${input_SRCS}
|
||||
${reios_SRCS}
|
||||
${imgread_SRCS}
|
||||
${profiler_SRCS}
|
||||
${d_core}/archive/archive.cpp ${d_core}/archive/archive.h
|
||||
${d_core}/nullDC.cpp
|
||||
${d_core}/stdclass.cpp
|
||||
${d_core}/dispframe.cpp
|
||||
${d_core}/serialize.cpp
|
||||
)
|
||||
|
||||
|
||||
if(${BUILD_COMPILER} EQUAL ${COMPILER_GCC}) # Add Clang if NOT WIN32 *FIXME*
|
||||
list(APPEND core_SRCS ${archive_SRCS})
|
||||
endif()
|
||||
|
||||
if(${FEAT_SHREC} EQUAL ${DYNAREC_JIT})
|
||||
#
|
||||
if(${HOST_CPU} EQUAL ${CPU_X86})
|
||||
list(APPEND core_SRCS
|
||||
${d_core}/rec-x86/rec_x86_driver.cpp
|
||||
${d_core}/rec-x86/rec_x86_il.cpp
|
||||
${d_core}/rec-x86/rec_x86_asm.cpp # change for linux , rec_lin86_asm.S
|
||||
${d_core}/rec-x86/rec_x86_ngen.h
|
||||
)
|
||||
elseif(${HOST_CPU} EQUAL ${CPU_ARM})
|
||||
list(APPEND core_SRCS
|
||||
${d_core}/rec-ARM/ngen_arm.S
|
||||
${d_core}/rec-ARM/rec_arm.cpp
|
||||
)
|
||||
elseif(${HOST_CPU} EQUAL ${CPU_X64})
|
||||
|
||||
### FIXME: asm with cmake ninja+VC
|
||||
if(${BUILD_COMPILER} EQUAL ${COMPILER_VC})
|
||||
list(APPEND core_SRCS ${d_core}/rec-x64/msvc.asm)
|
||||
endif()
|
||||
|
||||
list(APPEND core_SRCS ${d_core}/rec-x64/rec_x64.cpp ${d_core}/rec-x64/x64_regalloc.h)
|
||||
|
||||
elseif(${HOST_CPU} EQUAL ${CPU_A64})
|
||||
list(APPEND core_SRCS ${d_core}/rec-ARM64/rec_arm64.cpp ${d_core}/rec-ARM64/arm64_regalloc.h)
|
||||
|
||||
else()
|
||||
message(" FEAT_SHREC==DYNAREC_JIT && HOST_CPU Unknown Default add arch or disable rec if not avail.")
|
||||
error()
|
||||
endif()
|
||||
#
|
||||
elseif(${FEAT_SHREC} EQUAL ${DYNAREC_CPP})
|
||||
list(APPEND core_SRCS ${d_core}/rec-cpp/rec_cpp.cpp)
|
||||
endif()
|
||||
|
||||
add_definitions(/DFEAT_HAS_SOFTREND=0)
|
||||
|
||||
|
||||
### deps.cmake #################################################################################
|
||||
|
||||
set(d_deps ${reicast_core_path}/deps)
|
||||
include_directories ("${d_deps}")
|
||||
include_directories ("${d_deps}/picotcp/include")
|
||||
include_directories ("${d_deps}/picotcp/modules")
|
||||
|
||||
file(GLOB xbyak_H ${d_deps}/xbyak/*.h) # include headers into cmake target/project view
|
||||
|
||||
file(GLOB chdr_SRCS ${d_deps}/chdr/*.c)
|
||||
file(GLOB lzma_SRCS ${d_deps}/lzma/*.c)
|
||||
file(GLOB lz_SRCS ${d_deps}/zlib/*.c)
|
||||
file(GLOB lzip_SRCS ${d_deps}/libzip/*.c)
|
||||
file(GLOB lpng_SRCS ${d_deps}/libpng/*.c)
|
||||
file(GLOB lelf_SRCS ${d_deps}/libelf/el*.cpp)
|
||||
file(GLOB crypt_SRCS ${d_deps}/crypto/*.cpp)
|
||||
file(GLOB imgui_SRCS ${d_deps}/imgui/*.cpp)
|
||||
file(GLOB lws_SRCS ${d_deps}/libwebsocket/*.c)
|
||||
|
||||
file(GLOB picoModS ${d_deps}/picotcp/modules/*.c)
|
||||
file(GLOB picoStkS ${d_deps}/picotcp/stack/*.c)
|
||||
set(pico_SRCS ${picoModS} ${picoStkS})
|
||||
|
||||
set(deps_SRCS
|
||||
${lz_SRCS}
|
||||
${lpng_SRCS}
|
||||
${lelf_SRCS}
|
||||
${chdr_SRCS}
|
||||
${crypt_SRCS}
|
||||
${imgui_SRCS}
|
||||
${d_deps}/xbrz/xbrz.cpp
|
||||
${d_deps}/dirent/dirent.c
|
||||
${d_deps}/xxhash/xxhash.c
|
||||
${d_deps}/chdpsr/cdipsr.cpp # sigh, this dir is named chdpsr for some reason ...
|
||||
${d_deps}/coreio/coreio.cpp
|
||||
# ${d_deps}/ifaddrs/ifaddrs.c
|
||||
${xbyak_H}
|
||||
)
|
||||
|
||||
if(${BUILD_COMPILER} EQUAL ${COMPILER_GCC}) # Add Clang if NOT WIN32 *FIXME*
|
||||
list(APPEND deps_SRCS
|
||||
${lzip_SRCS}
|
||||
${lzma_SRCS}
|
||||
${pico_SRCS}
|
||||
)
|
||||
add_definitions(-D_7ZIP_ST -DCHD5_LZMA)
|
||||
endif()
|
||||
|
||||
### libosd.cmake ################################################################################
|
||||
|
||||
|
||||
set(d_aout ${reicast_core_path}/oslib)
|
||||
|
||||
include_directories ("${d_core}/khronos")
|
||||
|
||||
## I really should just glob all of the dirs and ;shrug; if guards don't do it all ##
|
||||
|
||||
set(osd_SRCS "")
|
||||
|
||||
list(APPEND osd_SRCS ${d_aout}/audiostream.cpp)
|
||||
|
||||
if (${HOST_OS} EQUAL ${OS_WINDOWS})
|
||||
|
||||
list(APPEND osd_SRCS ${d_core}/windows/winmain.cpp)
|
||||
list(APPEND osd_SRCS ${d_core}/windows/win_vmem.cpp)
|
||||
list(APPEND osd_SRCS ${d_aout}/audiobackend_directsound.cpp)
|
||||
|
||||
|
||||
link_libraries(dsound.lib winmm.lib xinput.lib wsock32.lib opengl32.lib)
|
||||
|
||||
|
||||
elseif (${HOST_OS} EQUAL ${OS_LINUX} OR ${HOST_OS} EQUAL ${OS_ANDROID})
|
||||
|
||||
list(APPEND osd_SRCS
|
||||
${d_core}/linux/common.cpp
|
||||
${d_core}/linux/context.cpp
|
||||
${d_core}/linux/nixprof/nixprof.cpp
|
||||
|
||||
${d_aout}/audiobackend_oss.cpp # add option
|
||||
) # todo: configure linux audio lib options
|
||||
|
||||
if(NOT ANDROID)
|
||||
list(APPEND osd_SRCS
|
||||
${d_core}/linux-dist/x11.cpp
|
||||
${d_core}/linux-dist/main.cpp
|
||||
${d_core}/linux-dist/evdev.cpp)
|
||||
|
||||
add_definitions(-DSUPPORT_X11) ## don't use GLES ?
|
||||
link_libraries(X11)
|
||||
else()
|
||||
list(APPEND osd_SRCS
|
||||
.//android-studio/reicast/src/main/jni/src/Android.cpp
|
||||
.//android-studio/reicast/src/main/jni/src/utils.cpp
|
||||
# .//android-studio/reicast/src/main/jni/src/XperiaPlay.c
|
||||
)
|
||||
endif() # ANDROID
|
||||
|
||||
add_definitions(-DGLES -DUSE_EVDEV)
|
||||
|
||||
link_libraries(pthread dl rt asound Xext GLESv2 EGL)
|
||||
|
||||
elseif(${HOST_OS} EQUAL ${OS_DARWIN})
|
||||
#
|
||||
list(APPEND objc_SRCS
|
||||
./shell/apple/emulator-osx/emulator-osx/osx-main.mm
|
||||
./shell/apple/emulator-osx/emulator-osx/AppDelegate.swift
|
||||
./shell/apple/emulator-osx/emulator-osx/EmuGLView.swift
|
||||
)
|
||||
|
||||
set_source_files_properties(${objc_SRCS} PROPERTIES COMPILE_FLAGS "-x objective-c++")
|
||||
|
||||
list(APPEND osd_SRCS ${objc_SRCS}
|
||||
${d_osd}/linux/common.cpp
|
||||
${d_osd}/linux/context.cpp
|
||||
${d_osd}/audiobackend/audiobackend_coreaudio.cpp
|
||||
# if NOT USE_SWIFT / ObjC
|
||||
#${d_osd}/apple/osx_osd.cpp
|
||||
)
|
||||
|
||||
else()
|
||||
#
|
||||
message("OS Unhandled")
|
||||
error()
|
||||
#
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
##
|
||||
|
||||
include_directories ("${reicast_core_path}")
|
||||
|
||||
|
||||
|
||||
|
||||
set(reicast_SRCS ${core_SRCS} ${deps_SRCS} ${osd_SRCS})
|
||||
|
||||
add_executable(${TNAME}${binSuffix} ${reicast_SRCS} ${deps_SRCS})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(APPLE)
|
||||
enable_language(Swift)
|
||||
set_property(TARGET ${TNAME} PROPERTY XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "./shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h")
|
||||
|
||||
target_link_libraries(${TNAME}
|
||||
# "-framework Cocoa"
|
||||
# "-framework AppKit"
|
||||
"-framework CoreData"
|
||||
"-framework CoreAudio"
|
||||
"-framework AudioUnit"
|
||||
"-framework AudioToolbox"
|
||||
"-framework Foundation"
|
||||
)
|
||||
|
||||
#### OSX Notes, when not using xcode you have to make app bundle, edit plist and copy, convert MainMenu.xib to nib and copy,
|
||||
#null@devpc:~$ /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/MacOS/reicast ; exit;
|
||||
#2019-03-18 14:28:44.842 reicast[11468:131797] Unknown class _TtC12emulator_osx9EmuGLView in Interface Builder file at path /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/Resources/MainMenu.nib.
|
||||
#2019-03-18 14:28:44.842 reicast[11468:131797] Unknown class _TtC12emulator_osx11AppDelegate in Interface Builder file at path /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/Resources/MainMenu.nib.
|
||||
#2019-03-18 14:28:44.860 reicast[11468:131797] Failed to connect (window) outlet from (NSObject) to (NSWindow): missing setter or instance variable
|
||||
#
|
||||
|
||||
endif() #APPLE
|
||||
|
||||
|
||||
if(DEBUG_CMAKE)
|
||||
message(" ------------------------------------------------")
|
||||
message(" - HOST_OS: ${HOST_OS} - HOST_CPU: ${HOST_CPU} ")
|
||||
message(" - host_os: ${host_os} - host_arch: ${host_arch} ")
|
||||
message(" ------------------------------------------------")
|
||||
message(" C Flags: ${CMAKE_C_FLAGS} ")
|
||||
message(" CXX Flags: ${CMAKE_CXX_FLAGS} ")
|
||||
message(" LINK_DIRS: ${LINK_DIRECTORIES}")
|
||||
message("LINK_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
message(" ------------------------------------------------\n")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"environments": [
|
||||
{
|
||||
"environment": "toolchain.generic",
|
||||
"TOOLCHAIN_FILE": "ps4sdk.cmake"
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "win-x86-Debug",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_x86Debug",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x86"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "win-x86-Release",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_x86Release",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x86"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "win-x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_x64Debug",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "-DNINJA=1",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "win-x64-Release",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_x64Release",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "-DNINJA=1",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "win-x64-Clang-RelWithDebInfo",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_x64Release",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": "",
|
||||
"variables": [
|
||||
{
|
||||
"name": "CMAKE_C_COMPILER",
|
||||
"value": "clang-cl.exe"
|
||||
},
|
||||
{
|
||||
"name": "CMAKE_CXX_COMPILER",
|
||||
"value": "clang-cl.exe"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Console SDK's
|
||||
{
|
||||
"name": "PS4 SDK",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_PS4SDK",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"toolchain.generic"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=${projectDir}\\cmake\\ps4sdk.cmake",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "NSW SDK",
|
||||
"generator": "Ninja",
|
||||
"description": "TemplateDescription_Localize_PS4SDK",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"toolchain.generic"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=${projectDir}\\cmake\\devkitA64.cmake",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
|
||||
// UWP and VS Gen (temp?)
|
||||
{
|
||||
"name": "uwp-x64-Release",
|
||||
"generator": "Visual Studio 15 2017 Win64",
|
||||
"description": "TemplateDescription_Localize_x64Release",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "win-x64-MSBuild-Release",
|
||||
"generator": "Visual Studio 15 2017 Win64",
|
||||
"description": "TemplateDescription_Localize_x64Release",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
//"MINGW64_ROOT": "C:\\msys64\\mingw64",
|
||||
"BIN_ROOT": "${env.MINGW64_ROOT}\\bin",
|
||||
"FLAVOR": "x86_64-w64-mingw32",
|
||||
"TOOLSET_VERSION": "7.3.0",
|
||||
"PATH": "${env.MINGW64_ROOT}\\bin;${env.MINGW64_ROOT}\\..\\usr\\local\\bin;${env.MINGW64_ROOT}\\..\\usr\\bin;${env.MINGW64_ROOT}\\..\\bin;${env.PATH}",
|
||||
"INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\tr1;${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\${env.FLAVOR}",
|
||||
"environment": "mingw_64"
|
||||
}
|
||||
],
|
||||
"name": "Mingw64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"mingw_64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": "",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"variables": [
|
||||
{
|
||||
"name": "CMAKE_C_COMPILER",
|
||||
"value": "${env.BIN_ROOT}\\gcc.exe"
|
||||
},
|
||||
{
|
||||
"name": "CMAKE_CXX_COMPILER",
|
||||
"value": "${env.BIN_ROOT}\\g++.exe"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
//"MINGW64_ROOT": "C:\\msys64\\mingw64",
|
||||
"BIN_ROOT": "${env.MINGW64_ROOT}\\bin",
|
||||
"FLAVOR": "x86_64-w64-mingw32",
|
||||
"TOOLSET_VERSION": "7.3.0",
|
||||
"PATH": "${env.MINGW64_ROOT}\\bin;${env.MINGW64_ROOT}\\..\\usr\\local\\bin;${env.MINGW64_ROOT}\\..\\usr\\bin;${env.MINGW64_ROOT}\\..\\bin;${env.PATH}",
|
||||
"INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\tr1;${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\${env.FLAVOR}",
|
||||
"environment": "mingw_64"
|
||||
}
|
||||
],
|
||||
"name": "Mingw64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"mingw_64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\${name}\\install",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": "",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"variables": [
|
||||
{
|
||||
"name": "CMAKE_C_COMPILER",
|
||||
"value": "${env.BIN_ROOT}\\gcc.exe"
|
||||
},
|
||||
{
|
||||
"name": "CMAKE_CXX_COMPILER",
|
||||
"value": "${env.BIN_ROOT}\\g++.exe"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
39
README.md
39
README.md
|
@ -1,19 +1,18 @@
|
|||
[](https://build.snapcraft.io/user/reicast/reicast-emulator)
|
||||
|
||||
reicast
|
||||
===========
|
||||
reicast is a multi-platform Sega Dreamcast emulator.
|
||||
**reicast** is a multi-platform Sega Dreamcast emulator.
|
||||
|
||||
This is a developer-oriented resource, if you just want bins head over to http://reicast.com/
|
||||
|
||||
For development discussion, join [#reicast in freenode](https://webchat.freenode.net/?channels=reicast)
|
||||
or stop by the [reicast Discord server](http://discord.gg/Hc6CF72)
|
||||
|
||||
Caution
|
||||
-------
|
||||
The source is a mess, and dragons might eat your cat when you clone this project. We're working on cleaning things up, but don't hold your breath. Why don't you lend a hand?
|
||||
|
||||
Rebranding/(hard)forks
|
||||
----------------
|
||||
If you are interested into further porting/adapting/whatever, *please* don't fork off. I hate that. Really.
|
||||
If you are interested into further porting/adapting/whatever, *please* do not fork off.
|
||||
We hate that. **Really**.
|
||||
|
||||
Let's try to keep everything under a single project :)
|
||||
|
||||
|
@ -28,7 +27,8 @@ Bugs that do not include a form may be closed until it is filled out.
|
|||
|
||||
Contributing
|
||||
------------
|
||||
For small/one-off fixes a PR from a github fork is alright. For longer term collaboration we prefer to use namespaced branches in the form of `<username>/<whatever>` in the main repo.
|
||||
- For small/one-off fixes, a PR from a GitHub fork is alright.
|
||||
- For longer term collaboration, we prefer to use namespaced branches in the form of `<username>/<whatever>` in the main repo.
|
||||
|
||||
Before you work on something major, make sure to check the issue tracker to coordinate with other contributors, and open an issue to get feedback before doing big changes/PRs. It is always polite to check the history of the code you're working on and collaborate with the people that have worked on it. You can introduce yourself in [Meet the team](https://github.com/reicast/reicast-emulator/issues/1113).
|
||||
|
||||
|
@ -109,23 +109,26 @@ Or open the .xcodeproj in Xcode and hit "Build".
|
|||
|
||||
Building for Linux
|
||||
------------------
|
||||
Requirements:
|
||||
* build-essential
|
||||
* libasound2
|
||||
* libegl1-mesa-dev
|
||||
* libgles2-mesa-dev
|
||||
* libasound2-dev
|
||||
* mesa-common-dev
|
||||
* libgl1-mesa-dev
|
||||
|
||||
From project root directory:
|
||||
### Using traditional make
|
||||
- Requirements:
|
||||
* build-essential
|
||||
* libasound2
|
||||
* libegl1-mesa-dev
|
||||
* libgles2-mesa-dev
|
||||
* libasound2-dev
|
||||
* mesa-common-dev
|
||||
* libgl1-mesa-dev
|
||||
|
||||
- From project root directory:
|
||||
```
|
||||
cd shell/linux
|
||||
|
||||
make
|
||||
```
|
||||
|
||||
### Using snap
|
||||
- Refer to our [snap README](https://github.com/reicast/reicast-emulator/tree/master/snap/README.md)
|
||||
|
||||
Translations
|
||||
------------
|
||||
New and updated translations are always appreciated!
|
||||
|
@ -178,7 +181,6 @@ Our IRC channel is [#reicast @ chat.freenode.net](irc://chat.freenode.net/reicas
|
|||
The original reicast team consisted of drk||Raziel (mostly just writing code),
|
||||
PsyMan (debugging/testing and everything else) and a little bit of gb_away
|
||||
|
||||
|
||||
Special thanks
|
||||
--------------
|
||||
In previous iterations a lot of people have worked on this, notably David
|
||||
|
@ -186,3 +188,4 @@ Miller (aka, ZeZu), the nullDC team, friends from #pcsx2 and all over the world
|
|||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
|
||||
|
|
61
appveyor.yml
61
appveyor.yml
|
@ -1,31 +1,50 @@
|
|||
version: git-{branch}-{build}
|
||||
image: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- EXTRA_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin\
|
||||
LAUNCH_BUILD: mingw32-make platform=win32
|
||||
LAUNCH_PATH: shell\linux\
|
||||
configuration:
|
||||
- RelWithDebInfo
|
||||
- fast
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
before_build:
|
||||
- cmd: >-
|
||||
if "%CONFIGURATION%"=="RelWithDebInfo" (set BUILD_PATH=build)
|
||||
|
||||
if "%CONFIGURATION%"=="fast" (set BUILD_PATH=shell\linux)
|
||||
|
||||
set EXTRA_PATH=C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin\
|
||||
|
||||
set PATH=%EXTRA_PATH%;%PATH%
|
||||
|
||||
if not exist %BUILD_PATH% (mkdir %BUILD_PATH%)
|
||||
|
||||
if "%CONFIGURATION%"=="RelWithDebInfo" (cmake -B %BUILD_PATH% -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo)
|
||||
|
||||
cd %BUILD_PATH%
|
||||
|
||||
build_script:
|
||||
- cmd: >-
|
||||
set PATH=%EXTRA_PATH%;%PATH%
|
||||
|
||||
cd %LAUNCH_PATH%
|
||||
|
||||
%LAUNCH_BUILD%
|
||||
|
||||
- cmd: >-
|
||||
if "%CONFIGURATION%"=="RelWithDebInfo" (msbuild reicast.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll")
|
||||
|
||||
if "%CONFIGURATION%"=="fast" (mingw32-make platform=win32)
|
||||
|
||||
after_build:
|
||||
- cmd: cd ..\..
|
||||
- cmd: mkdir artifacts
|
||||
- cmd: move shell\linux\reicast.exe artifacts/reicast-win_x64-fast-%APPVEYOR_REPO_COMMIT%.exe
|
||||
- cmd: copy %EXTRA_PATH%\libgcc_s_seh-1.dll artifacts
|
||||
- cmd: copy %EXTRA_PATH%\libwinpthread-1.dll artifacts
|
||||
- cmd: copy %EXTRA_PATH%\libgomp-1.dll artifacts
|
||||
- cmd: >-
|
||||
if "%CONFIGURATION%"=="RelWithDebInfo" (cd .. && set EXE_PATH=build\RelWithDebInfo\reicast.exe)
|
||||
|
||||
if "%CONFIGURATION%"=="fast" (cd ..\.. && set EXE_PATH=shell\linux\nosym-reicast.exe)
|
||||
|
||||
mkdir artifacts
|
||||
|
||||
move %EXE_PATH% artifacts\reicast-win_%PLATFORM%-%CONFIGURATION%-%APPVEYOR_REPO_COMMIT%.exe
|
||||
|
||||
if "%CONFIGURATION%"=="fast" (copy %EXTRA_PATH%\libgcc_s_seh-1.dll artifacts && copy %EXTRA_PATH%\libwinpthread-1.dll artifacts && copy %EXTRA_PATH%\libgomp-1.dll artifacts)
|
||||
|
||||
artifacts:
|
||||
- path: artifacts
|
||||
name: reicast-win_x64-fast-$(APPVEYOR_REPO_COMMIT)
|
||||
name: reicast-win_$(PLATFORM)-$(CONFIGURATION)-$(APPVEYOR_REPO_COMMIT)
|
||||
|
||||
deploy:
|
||||
- provider: S3
|
||||
|
@ -35,5 +54,5 @@ deploy:
|
|||
region: eu-west-1
|
||||
bucket: reicast-builds-windows
|
||||
folder: 'builds/heads/$(APPVEYOR_REPO_BRANCH)-$(APPVEYOR_REPO_COMMIT)'
|
||||
artifact: reicast-win_x64-fast-$(APPVEYOR_REPO_COMMIT)
|
||||
set_public: true
|
||||
artifact: reicast-win_$(PLATFORM)-$(CONFIGURATION)-$(APPVEYOR_REPO_COMMIT)
|
||||
set_public: true
|
|
@ -0,0 +1 @@
|
|||
/version.h
|
|
@ -1,4 +1,15 @@
|
|||
core
|
||||
# core/libdreamcast
|
||||
===========
|
||||
|
||||
All of the interesting bits are here
|
||||
Here lies the core of our codebase. Everything that's OS inspecific rests here.
|
||||
** Please check per directory README for more info **
|
||||
|
||||
### Some rudimentary categories are:
|
||||
- hw -- DC Hardware Components Implementation
|
||||
- nullDC.cpp -- NullDC, thy mighty child (also referenced as "debugger")
|
||||
- emitter -- Cookie machine
|
||||
- khronos -- Vulkan stuff
|
||||
- oslib -- Codebase abstraction effort
|
||||
- cfg -- Configuration backend structure
|
||||
- reios -- (Our)Implementation of the DreamCast BIOS (Not functional)
|
||||
- deps -- External C libraries (hackish, hand-written versions)
|
||||
|
|
|
@ -21,12 +21,15 @@
|
|||
|
||||
#include "archive.h"
|
||||
#include "7zArchive.h"
|
||||
#ifndef _MSC_VER
|
||||
#include "ZipArchive.h"
|
||||
#endif
|
||||
|
||||
Archive *OpenArchive(const char *path)
|
||||
{
|
||||
std::string base_path(path);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
Archive *sz_archive = new SzArchive();
|
||||
if (sz_archive->Open(base_path.c_str()) || sz_archive->Open((base_path + ".7z").c_str()) || sz_archive->Open((base_path + ".7Z").c_str()))
|
||||
return sz_archive;
|
||||
|
@ -36,6 +39,7 @@ Archive *OpenArchive(const char *path)
|
|||
if (zip_archive->Open(base_path.c_str()) || zip_archive->Open((base_path + ".zip").c_str()) || zip_archive->Open((base_path + ".ZIP").c_str()))
|
||||
return zip_archive;
|
||||
delete zip_archive;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
158
core/build.h
158
core/build.h
|
@ -127,10 +127,18 @@
|
|||
#define DC_PLATFORM_AURORA 6 /* Needs to be done, Uses newer 300 mhz sh4 + 150 mhz pvr mbx SoC */
|
||||
|
||||
|
||||
|
||||
//HOST_OS
|
||||
#define OS_WINDOWS 0x10000001
|
||||
#define OS_LINUX 0x10000002
|
||||
#define OS_DARWIN 0x10000003
|
||||
#define OS_IOS 0x10000004
|
||||
#define OS_ANDROID 0x10000005
|
||||
|
||||
#define OS_UWP 0x10000011
|
||||
#define OS_NSW_HOS 0x80000001
|
||||
#define OS_PS4_BSD 0x80000002
|
||||
|
||||
|
||||
//HOST_CPU
|
||||
#define CPU_X86 0x20000001
|
||||
|
@ -138,11 +146,16 @@
|
|||
#define CPU_MIPS 0x20000003
|
||||
#define CPU_X64 0x20000004
|
||||
#define CPU_GENERIC 0x20000005 //used for pnacl, emscripten, etc
|
||||
#define CPU_ARM64 0x20000006
|
||||
#define CPU_PPC 0x20000006
|
||||
#define CPU_PPC64 0x20000007
|
||||
#define CPU_ARM64 0x20000008
|
||||
#define CPU_MIPS64 0x20000009
|
||||
|
||||
//BUILD_COMPILER
|
||||
#define COMPILER_VC 0x30000001
|
||||
#define COMPILER_GCC 0x30000002
|
||||
#define COMPILER_VC 0x30000001
|
||||
#define COMPILER_GCC 0x30000002
|
||||
#define COMPILER_CLANG 0x30000003
|
||||
#define COMPILER_INTEL 0x30000004
|
||||
|
||||
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
|
||||
#define DYNAREC_NONE 0x40000001
|
||||
|
@ -152,6 +165,8 @@
|
|||
|
||||
//automatic
|
||||
|
||||
#ifndef CMAKE_BUILD
|
||||
|
||||
#if defined(_WIN32) && !defined(TARGET_WIN86) && !defined(TARGET_WIN64)
|
||||
#if !defined(_M_AMD64) && !defined(__x86_64__)
|
||||
#define TARGET_WIN86
|
||||
|
@ -233,6 +248,8 @@
|
|||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
|
||||
#endif // !CMAKE_BUILD
|
||||
|
||||
|
||||
#if defined(TARGET_NO_NIXPROF)
|
||||
#define FEAT_HAS_NIXPROF 0
|
||||
|
@ -286,10 +303,6 @@
|
|||
#define FEAT_HAS_SOFTREND BUILD_COMPILER == COMPILER_VC //GCC wants us to enable sse4 globaly to enable intrins
|
||||
#endif
|
||||
|
||||
#define RAM_SIZE_MAX (32*1024*1024)
|
||||
#define VRAM_SIZE_MAX (16*1024*1024)
|
||||
#define ARAM_SIZE_MAX (8*1024*1024)
|
||||
|
||||
//Depricated build configs
|
||||
#ifdef HOST_NO_REC
|
||||
#error Dont use HOST_NO_REC
|
||||
|
@ -298,3 +311,134 @@
|
|||
#ifdef HOST_NO_AREC
|
||||
#error Dont use HOST_NO_AREC
|
||||
#endif
|
||||
|
||||
|
||||
// Compiler Related
|
||||
|
||||
#define COMPILER_VC_OR_CLANG_WIN32 ((BUILD_COMPILER == COMPILER_VC) || (BUILD_COMPILER == COMPILER_CLANG) && defined(WIN32))
|
||||
|
||||
#if BUILD_COMPILER!=COMPILER_VC
|
||||
#define ATTR_USED __attribute__((used))
|
||||
#define ATTR_UNUSED __attribute__((used))
|
||||
#else
|
||||
#define ATTR_USED
|
||||
#define ATTR_UNUSED
|
||||
#endif
|
||||
|
||||
|
||||
// Some restrictions on FEAT_NO_RWX_PAGES
|
||||
#if defined(FEAT_NO_RWX_PAGES) && FEAT_SHREC == DYNAREC_JIT
|
||||
#if HOST_CPU != CPU_X64 && HOST_CPU != CPU_ARM64
|
||||
#error "FEAT_NO_RWX_PAGES Only implemented for X64 and ARMv8"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// TARGET PLATFORM
|
||||
|
||||
#define RAM_SIZE_MAX (32*1024*1024)
|
||||
#define VRAM_SIZE_MAX (16*1024*1024)
|
||||
#define ARAM_SIZE_MAX (8*1024*1024)
|
||||
|
||||
#if (DC_PLATFORM==DC_PLATFORM_DREAMCAST)
|
||||
|
||||
#define BUILD_DREAMCAST 1
|
||||
|
||||
//DC : 16 mb ram, 8 mb vram, 2 mb aram, 2 mb bios, 128k flash
|
||||
#define RAM_SIZE (16*1024*1024)
|
||||
#define VRAM_SIZE (8*1024*1024)
|
||||
#define ARAM_SIZE (2*1024*1024)
|
||||
#define BIOS_SIZE (2*1024*1024)
|
||||
#define FLASH_SIZE (128*1024)
|
||||
|
||||
#define ROM_PREFIX "dc_"
|
||||
#define ROM_NAMES
|
||||
#define NVR_OPTIONAL 0
|
||||
|
||||
#elif (DC_PLATFORM==DC_PLATFORM_DEV_UNIT)
|
||||
|
||||
#define BUILD_DEV_UNIT 1
|
||||
|
||||
//Devkit : 32 mb ram, 8? mb vram, 2? mb aram, 2? mb bios, ? flash
|
||||
#define RAM_SIZE (32*1024*1024)
|
||||
#define VRAM_SIZE (8*1024*1024)
|
||||
#define ARAM_SIZE (2*1024*1024)
|
||||
#define BIOS_SIZE (2*1024*1024)
|
||||
#define FLASH_SIZE (128*1024)
|
||||
|
||||
#define ROM_PREFIX "hkt_"
|
||||
#define ROM_NAMES
|
||||
#define NVR_OPTIONAL 0
|
||||
|
||||
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI)
|
||||
|
||||
//Naomi : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
|
||||
#define RAM_SIZE (32*1024*1024)
|
||||
#define VRAM_SIZE (16*1024*1024)
|
||||
#define ARAM_SIZE (8*1024*1024)
|
||||
#define BIOS_SIZE (2*1024*1024)
|
||||
#define BBSRAM_SIZE (32*1024)
|
||||
|
||||
#define ROM_PREFIX "naomi_"
|
||||
#define ROM_NAMES ";epr-21576d.bin"
|
||||
#define NVR_OPTIONAL 1
|
||||
|
||||
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI2)
|
||||
|
||||
//Naomi2 : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
|
||||
#define RAM_SIZE (32*1024*1024)
|
||||
#define VRAM_SIZE (16*1024*1024)
|
||||
#define ARAM_SIZE (8*1024*1024)
|
||||
#define BIOS_SIZE (2*1024*1024)
|
||||
#define BBSRAM_SIZE (32*1024)
|
||||
|
||||
#define ROM_PREFIX "n2_"
|
||||
#define ROM_NAMES
|
||||
#define NVR_OPTIONAL 1
|
||||
|
||||
#elif (DC_PLATFORM==DC_PLATFORM_ATOMISWAVE)
|
||||
|
||||
#define BUILD_ATOMISWAVE 1
|
||||
|
||||
//Atomiswave : 16 mb ram, 8 mb vram, 8 mb aram, 128kb bios on flash, 128kb battery-backed ram
|
||||
#define RAM_SIZE (16*1024*1024)
|
||||
#define VRAM_SIZE (8*1024*1024)
|
||||
#define ARAM_SIZE (8*1024*1024)
|
||||
#define BIOS_SIZE (128*1024)
|
||||
#define BBSRAM_SIZE (128*1024)
|
||||
|
||||
#define ROM_PREFIX "aw_"
|
||||
#define ROM_NAMES ";bios.ic23_l"
|
||||
#define NVR_OPTIONAL 1
|
||||
|
||||
#else
|
||||
#error invalid build config
|
||||
#endif
|
||||
|
||||
#define RAM_MASK (RAM_SIZE-1)
|
||||
#define VRAM_MASK (VRAM_SIZE-1)
|
||||
#define ARAM_MASK (ARAM_SIZE-1)
|
||||
#define BIOS_MASK (BIOS_SIZE-1)
|
||||
|
||||
#ifdef FLASH_SIZE
|
||||
#define FLASH_MASK (FLASH_SIZE-1)
|
||||
#endif
|
||||
|
||||
#ifdef BBSRAM_SIZE
|
||||
#define BBSRAM_MASK (BBSRAM_SIZE-1)
|
||||
#endif
|
||||
|
||||
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
|
||||
|
||||
#define AICA_CORE_CLOCK (GD_CLOCK*4/3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
|
||||
#define ADAC_CLOCK (AICA_CORE_CLOCK/2) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs
|
||||
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK/2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
|
||||
#define AICA_SDRAM_CLOCK (GD_CLOCK*2) //[67737600] GD-> PLL 2 -> SDRAM
|
||||
#define SH4_MAIN_CLOCK (200*1000*1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
|
||||
#define SH4_RAM_CLOCK (100*1000*1000) //[100000000] XTal(13.5) -> PLL (33.3) -> PLL 1:3 (100) , also suplied to HOLLY chip
|
||||
#define G2_BUS_CLOCK (25*1000*1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
|
||||
|
||||
#if defined(GLES) && !defined(GLES3)
|
||||
// Only use GL ES 2.0 API functions
|
||||
#define GLES2
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
static string cfgPath;
|
||||
static bool save_config = true;
|
||||
|
||||
static ConfigFile cfgdb;
|
||||
static emucfg::ConfigFile cfgdb;
|
||||
static string game_id;
|
||||
static bool has_game_specific_config = false;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
** cfg* prototypes, if you pass NULL to a cfgSave* it will wipe out the section
|
||||
** } if you pass it to lpKey it will wipe out that particular entry
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
|
@ -101,12 +101,14 @@ int setconfig(wchar** arg,int cl)
|
|||
|
||||
int showhelp(wchar** arg,int cl)
|
||||
{
|
||||
printf("Available commands :\n");
|
||||
printf("\nAvailable commands :\n");
|
||||
|
||||
printf("-config section:key=value [, ..]: add a virtual config value\n Virtual config values won't be saved to the .cfg file\n unless a different value is written to em\nNote :\n You can specify many settings in the xx:yy=zz , gg:hh=jj , ...\n format.The spaces between the values and ',' are needed.");
|
||||
printf("-config section:key=value [, ..]: add a virtual config value\n Virtual config values won't be saved to the .cfg file\n unless a different value is written to em\nNote :\n You can specify many settings in the xx:yy=zz , gg:hh=jj , ...\n format.The spaces between the values and ',' are needed.\n");
|
||||
printf("\n-help: show help info\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ParseCommandLine(int argc,wchar* argv[])
|
||||
{
|
||||
cfgSetVirtual("config", "image", "");
|
||||
|
@ -114,14 +116,12 @@ bool ParseCommandLine(int argc,wchar* argv[])
|
|||
wchar** arg=argv+1;
|
||||
while(cl>=0)
|
||||
{
|
||||
if (stricmp(*arg,"-help")==0)
|
||||
if (stricmp(*arg,"-help")==0 || stricmp(*arg,"--help")==0)
|
||||
{
|
||||
int as=showhelp(arg,cl);
|
||||
cl-=as;
|
||||
arg+=as;
|
||||
showhelp(arg,cl);
|
||||
return true;
|
||||
}
|
||||
else if (stricmp(*arg,"-config")==0)
|
||||
else if (stricmp(*arg,"-config")==0 || stricmp(*arg,"--config")==0)
|
||||
{
|
||||
int as=setconfig(arg,cl);
|
||||
cl-=as;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
wchar* trim_ws(wchar* str);
|
||||
|
||||
namespace emucfg {
|
||||
|
||||
/* ConfigEntry */
|
||||
|
||||
string ConfigEntry::get_string()
|
||||
|
@ -299,3 +301,5 @@ void ConfigFile::delete_entry(const std::string& section_name, const std::string
|
|||
section->delete_entry(entry_name);
|
||||
}
|
||||
|
||||
} // namespace emucfg
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "types.h"
|
||||
#include <map>
|
||||
|
||||
namespace emucfg {
|
||||
|
||||
struct ConfigEntry {
|
||||
std::string value;
|
||||
std::string get_string();
|
||||
|
@ -45,3 +47,6 @@ struct ConfigFile {
|
|||
void delete_section(const std::string& section_name);
|
||||
void delete_entry(const std::string& section_name, const std::string& entry_name);
|
||||
};
|
||||
|
||||
} // namespace emucfg
|
||||
|
||||
|
|
66
core/core.mk
66
core/core.mk
|
@ -1,26 +1,17 @@
|
|||
#LOCAL_PATH:=
|
||||
#LOCAL_PATH:=
|
||||
|
||||
#MFLAGS := -marm -march=armv7-a -mtune=cortex-a8 -mfpu=vfpv3-d16 -mfloat-abi=softfp
|
||||
#ASFLAGS := -march=armv7-a -mfpu=vfp-d16 -mfloat-abi=softfp
|
||||
#LDFLAGS := -Wl,-Map,$(notdir $@).map,--gc-sections -Wl,-O3 -Wl,--sort-common
|
||||
#LDFLAGS := -Wl,-Map,$(notdir $@).map,--gc-sections -Wl,-O3 -Wl,--sort-common
|
||||
|
||||
RZDCY_SRC_DIR ?= $(call my-dir)
|
||||
VERSION_SRC := $(RZDCY_SRC_DIR)/version/version.cpp
|
||||
VERSION_HEADER := $(RZDCY_SRC_DIR)/version.h
|
||||
|
||||
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ hw/modem/ \
|
||||
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
|
||||
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \
|
||||
hw/extdev/ hw/arm/ hw/naomi/ imgread/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
|
||||
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/ \
|
||||
deps/picotcp/modules/ deps/picotcp/stack/ deps/xxhash/ deps/libzip/ deps/imgui/ \
|
||||
archive/ input/
|
||||
|
||||
ifdef CHD5_LZMA
|
||||
RZDCY_MODULES += deps/lzma/
|
||||
endif
|
||||
|
||||
ifdef CHD5_FLAC
|
||||
RZDCY_MODULES += deps/flac/src/libFLAC/
|
||||
endif
|
||||
deps/xxhash/ deps/libzip/ deps/imgui/ archive/ input/
|
||||
|
||||
ifdef WEBUI
|
||||
RZDCY_MODULES += webui/
|
||||
|
@ -31,10 +22,6 @@ ifdef WEBUI
|
|||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_REC
|
||||
RZDCY_MODULES += hw/sh4/dyna/
|
||||
endif
|
||||
|
||||
ifndef NOT_ARM
|
||||
RZDCY_MODULES += rec-ARM/
|
||||
endif
|
||||
|
@ -66,10 +53,6 @@ else
|
|||
RZDCY_MODULES += rend/norend/
|
||||
endif
|
||||
|
||||
ifdef HAS_SOFTREND
|
||||
RZDCY_MODULES += rend/soft/
|
||||
endif
|
||||
|
||||
ifndef NO_NIXPROF
|
||||
RZDCY_MODULES += linux/nixprof/
|
||||
endif
|
||||
|
@ -90,12 +73,6 @@ ifdef FOR_WINDOWS
|
|||
RZDCY_MODULES += windows/
|
||||
endif
|
||||
|
||||
RZDCY_FILES := $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cpp))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cc))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.c))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.S))
|
||||
RZDCY_FILES += $(VERSION_SRC)
|
||||
|
||||
ifdef FOR_PANDORA
|
||||
RZDCY_CFLAGS := \
|
||||
$(CFLAGS) -c -O3 \
|
||||
|
@ -134,11 +111,17 @@ RZDCY_CFLAGS :=
|
|||
endif
|
||||
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR) -I$(RZDCY_SRC_DIR)/rend/gles -I$(RZDCY_SRC_DIR)/deps \
|
||||
-I$(RZDCY_SRC_DIR)/deps/picotcp/include -I$(RZDCY_SRC_DIR)/deps/picotcp/modules \
|
||||
-I$(RZDCY_SRC_DIR)/deps/vixl -I$(RZDCY_SRC_DIR)/khronos
|
||||
|
||||
ifdef USE_MODEM
|
||||
RZDCY_CFLAGS += -DENABLE_MODEM -I$(RZDCY_SRC_DIR)/deps/picotcp/include -I$(RZDCY_SRC_DIR)/deps/picotcp/modules
|
||||
RZDCY_MODULES += hw/modem/ deps/picotcp/modules/ deps/picotcp/stack/
|
||||
endif
|
||||
|
||||
ifdef NO_REC
|
||||
RZDCY_CFLAGS += -DTARGET_NO_REC
|
||||
RZDCY_CFLAGS += -DTARGET_NO_REC
|
||||
else
|
||||
RZDCY_MODULES += hw/sh4/dyna/
|
||||
endif
|
||||
|
||||
ifdef USE_GLES
|
||||
|
@ -147,17 +130,30 @@ endif
|
|||
|
||||
ifdef HAS_SOFTREND
|
||||
RZDCY_CFLAGS += -DTARGET_SOFTREND
|
||||
RZDCY_MODULES += rend/soft/
|
||||
endif
|
||||
|
||||
ifdef CHD5_FLAC
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
|
||||
RZDCY_CFLAGS += -DCHD5_FLAC -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
|
||||
RZDCY_CFLAGS += -DPACKAGE_VERSION=\"1.3.2\" -DFLAC__HAS_OGG=0 -DFLAC__NO_DLL -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -DHAVE_SYS_PARAM_H
|
||||
RZDCY_MODULES += deps/flac/src/libFLAC/
|
||||
endif
|
||||
|
||||
# 7-Zip/LZMA settings (CHDv5)
|
||||
ifdef CHD5_LZMA
|
||||
RZDCY_MODULES += deps/lzma/
|
||||
RZDCY_CFLAGS += -D_7ZIP_ST -DCHD5_LZMA
|
||||
endif
|
||||
|
||||
RZDCY_CXXFLAGS := $(RZDCY_CFLAGS) -fno-exceptions -fno-rtti -std=gnu++11
|
||||
|
||||
$(VERSION_SRC):
|
||||
echo "const char *version = \"`git describe --tags --always`\";" > $(VERSION_SRC)
|
||||
echo "const char *git_hash = \"`git rev-parse --short HEAD`\";" >> $(VERSION_SRC)
|
||||
echo "const char *build_date = \"`date '+%Y-%m-%d %H:%M:%S %Z'`\";" >> $(VERSION_SRC)
|
||||
RZDCY_FILES := $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cpp))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cc))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.c))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.S))
|
||||
|
||||
$(VERSION_HEADER):
|
||||
echo "#define REICAST_VERSION \"`git describe --tags --always`\"" > $(VERSION_HEADER)
|
||||
echo "#define GIT_HASH \"`git rev-parse --short HEAD`\"" >> $(VERSION_HEADER)
|
||||
echo "#define BUILD_DATE \"`date '+%Y-%m-%d %H:%M:%S %Z'`\"" >> $(VERSION_HEADER)
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
|
||||
Implementation of POSIX directory browsing functions and types for Win32.
|
||||
|
||||
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
|
||||
History: Created March 1997. Updated June 2003 and July 2012.
|
||||
Rights: See end of file.
|
||||
|
||||
*/
|
||||
|
||||
#include "dirent.h"
|
||||
#include <errno.h>
|
||||
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
|
||||
|
||||
struct DIR
|
||||
{
|
||||
handle_type handle; /* -1 for failed rewind */
|
||||
struct _finddata_t info;
|
||||
struct dirent result; /* d_name null iff first time */
|
||||
char *name; /* null-terminated char string */
|
||||
};
|
||||
|
||||
DIR *opendir(const char *name)
|
||||
{
|
||||
DIR *dir = 0;
|
||||
|
||||
if (name && name[0])
|
||||
{
|
||||
size_t base_length = strlen(name);
|
||||
const char *all = /* search pattern must end with suitable wildcard */
|
||||
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
|
||||
|
||||
if ((dir = (DIR *)malloc(sizeof *dir)) != 0 &&
|
||||
(dir->name = (char *)malloc(base_length + strlen(all) + 1)) != 0)
|
||||
{
|
||||
strcat(strcpy(dir->name, name), all);
|
||||
|
||||
if ((dir->handle =
|
||||
(handle_type)_findfirst(dir->name, &dir->info)) != -1)
|
||||
{
|
||||
dir->result.d_name = 0;
|
||||
}
|
||||
else /* rollback */
|
||||
{
|
||||
free(dir->name);
|
||||
free(dir);
|
||||
dir = 0;
|
||||
}
|
||||
}
|
||||
else /* rollback */
|
||||
{
|
||||
free(dir);
|
||||
dir = 0;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
int closedir(DIR *dir)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (dir)
|
||||
{
|
||||
if (dir->handle != -1)
|
||||
{
|
||||
result = _findclose(dir->handle);
|
||||
}
|
||||
|
||||
free(dir->name);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
if (result == -1) /* map all errors to EBADF */
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dir)
|
||||
{
|
||||
struct dirent *result = 0;
|
||||
|
||||
if (dir && dir->handle != -1)
|
||||
{
|
||||
if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
|
||||
{
|
||||
result = &dir->result;
|
||||
result->d_name = dir->info.name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rewinddir(DIR *dir)
|
||||
{
|
||||
if (dir && dir->handle != -1)
|
||||
{
|
||||
_findclose(dir->handle);
|
||||
dir->handle = (handle_type)_findfirst(dir->name, &dir->info);
|
||||
dir->result.d_name = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided
|
||||
that this copyright and permissions notice appear in all copies and
|
||||
derivatives.
|
||||
|
||||
This software is supplied "as is" without express or implied warranty.
|
||||
|
||||
But that said, if there are any problems please get in touch.
|
||||
|
||||
*/
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef DIRENT_INCLUDED
|
||||
#define DIRENT_INCLUDED
|
||||
|
||||
/*
|
||||
|
||||
Declaration of POSIX directory browsing functions and types for Win32.
|
||||
|
||||
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
|
||||
History: Created March 1997. Updated June 2003.
|
||||
Rights: See end of file.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct DIR DIR;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
char *d_name;
|
||||
};
|
||||
|
||||
DIR *opendir(const char *);
|
||||
int closedir(DIR *);
|
||||
struct dirent *readdir(DIR *);
|
||||
void rewinddir(DIR *);
|
||||
|
||||
/*
|
||||
|
||||
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided
|
||||
that this copyright and permissions notice appear in all copies and
|
||||
derivatives.
|
||||
|
||||
This software is supplied "as is" without express or implied warranty.
|
||||
|
||||
But that said, if there are any problems please get in touch.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
# Our Emitter
|
||||
### Oh god , x86 is a sooo badly designed opcode arch -_-
|
||||
---
|
||||
Emitters are the place where you have functions that you give symbolic
|
||||
instructions and you get binaries out.
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "aica.h"
|
||||
#include "aica_if.h"
|
||||
#include "sgc_if.h"
|
||||
#include "aica_mem.h"
|
||||
#include <math.h>
|
||||
|
@ -180,6 +181,7 @@ template void WriteAicaReg<2>(u32 reg,u32 data);
|
|||
s32 libAICA_Init()
|
||||
{
|
||||
init_mem();
|
||||
aica_Init();
|
||||
|
||||
verify(sizeof(*CommonData)==0x508);
|
||||
verify(sizeof(*DSPData)==0x15C8);
|
||||
|
@ -203,9 +205,12 @@ s32 libAICA_Init()
|
|||
return rv_ok;
|
||||
}
|
||||
|
||||
void libAICA_Reset(bool m)
|
||||
void libAICA_Reset(bool manual)
|
||||
{
|
||||
if (!manual)
|
||||
init_mem();
|
||||
sgc_Init();
|
||||
aica_Reset(manual);
|
||||
}
|
||||
|
||||
void libAICA_Term()
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
|
||||
#include <time.h>
|
||||
|
||||
VArray2 aica_ram;
|
||||
VLockedMemory aica_ram;
|
||||
u32 VREG;//video reg =P
|
||||
u32 ARMRST;//arm reset reg
|
||||
u32 rtc_EN=0;
|
||||
int dma_sched_id;
|
||||
u32 RealTimeClock;
|
||||
|
||||
u32 GetRTC_now()
|
||||
{
|
||||
|
@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
|
|||
switch( addr & 0xFF )
|
||||
{
|
||||
case 0:
|
||||
return settings.dreamcast.RTC>>16;
|
||||
return RealTimeClock>>16;
|
||||
case 4:
|
||||
return settings.dreamcast.RTC &0xFFFF;
|
||||
return RealTimeClock &0xFFFF;
|
||||
case 8:
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz)
|
|||
case 0:
|
||||
if (rtc_EN)
|
||||
{
|
||||
settings.dreamcast.RTC&=0xFFFF;
|
||||
settings.dreamcast.RTC|=(data&0xFFFF)<<16;
|
||||
RealTimeClock&=0xFFFF;
|
||||
RealTimeClock|=(data&0xFFFF)<<16;
|
||||
rtc_EN=0;
|
||||
}
|
||||
return;
|
||||
case 4:
|
||||
if (rtc_EN)
|
||||
{
|
||||
settings.dreamcast.RTC&=0xFFFF0000;
|
||||
settings.dreamcast.RTC|= data&0xFFFF;
|
||||
RealTimeClock&=0xFFFF0000;
|
||||
RealTimeClock|= data&0xFFFF;
|
||||
//TODO: Clean the internal timer ?
|
||||
}
|
||||
return;
|
||||
|
@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
|
|||
//Init/res/term
|
||||
void aica_Init()
|
||||
{
|
||||
//mmnnn ? gotta fill it w/ something
|
||||
RealTimeClock = GetRTC_now();
|
||||
}
|
||||
|
||||
void aica_Reset(bool Manual)
|
||||
{
|
||||
if (!Manual)
|
||||
{
|
||||
aica_ram.Zero();
|
||||
}
|
||||
aica_Init();
|
||||
}
|
||||
|
||||
void aica_Term()
|
||||
|
@ -183,6 +181,7 @@ int dma_end_sched(int tag, int cycl, int jitt)
|
|||
SB_ADST = 0x00000000;//dma done
|
||||
SB_ADLEN = 0x00000000;
|
||||
|
||||
// indicate that dma is not happening, or has been paused
|
||||
SB_ADSUSP |= 0x10;
|
||||
|
||||
asic_RaiseInterrupt(holly_SPU_DMA);
|
||||
|
@ -190,7 +189,6 @@ int dma_end_sched(int tag, int cycl, int jitt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Write_SB_ADST(u32 addr, u32 data)
|
||||
{
|
||||
//0x005F7800 SB_ADSTAG RW AICA:G2-DMA G2 start address
|
||||
|
@ -227,14 +225,24 @@ void Write_SB_ADST(u32 addr, u32 data)
|
|||
WriteMem32_nommu(dst+i,data);
|
||||
}
|
||||
*/
|
||||
|
||||
// idicate that dma is in progress
|
||||
SB_ADSUSP &= ~0x10;
|
||||
|
||||
// Schedule the end of DMA transfer interrupt
|
||||
int cycles = len * (SH4_MAIN_CLOCK / 2 / 25000000); // 16 bits @ 25 MHz
|
||||
if (cycles < 4096)
|
||||
dma_end_sched(0, 0, 0);
|
||||
if (!settings.aica.OldSyncronousDma)
|
||||
{
|
||||
|
||||
// Schedule the end of DMA transfer interrupt
|
||||
int cycles = len * (SH4_MAIN_CLOCK / 2 / 25000000); // 16 bits @ 25 MHz
|
||||
if (cycles < 4096)
|
||||
dma_end_sched(0, 0, 0);
|
||||
else
|
||||
sh4_sched_request(dma_sched_id, cycles);
|
||||
}
|
||||
else
|
||||
sh4_sched_request(dma_sched_id, cycles);
|
||||
{
|
||||
dma_end_sched(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#include "types.h"
|
||||
|
||||
extern u32 VREG;
|
||||
extern VArray2 aica_ram;
|
||||
extern VLockedMemory aica_ram;
|
||||
extern u32 RealTimeClock;
|
||||
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
|
||||
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
|
||||
u32 ReadMem_aica_reg(u32 addr,u32 sz);
|
||||
|
@ -17,4 +18,4 @@ void aica_Term();
|
|||
|
||||
void aica_sb_Init();
|
||||
void aica_sb_Reset(bool Manual);
|
||||
void aica_sb_Term();
|
||||
void aica_sb_Term();
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "deps/vixl/aarch64/macro-assembler-aarch64.h"
|
||||
using namespace vixl::aarch64;
|
||||
|
||||
extern void Arm64CacheFlush(void* start, void* end);
|
||||
extern void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
|
||||
|
||||
class DSPAssembler : public MacroAssembler
|
||||
{
|
||||
|
@ -54,9 +54,9 @@ public:
|
|||
Stp(xzr, xzr, MemOperand(x0, 48));
|
||||
Ret();
|
||||
FinalizeCode();
|
||||
#ifdef _ANDROID
|
||||
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
#endif
|
||||
vmem_platform_flush_cache(
|
||||
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>(),
|
||||
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -387,9 +387,9 @@ public:
|
|||
#endif
|
||||
FinalizeCode();
|
||||
|
||||
#ifdef _ANDROID
|
||||
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
#endif
|
||||
vmem_platform_flush_cache(
|
||||
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>(),
|
||||
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -751,7 +751,10 @@ __forceinline SampleType DecodeADPCM(u32 sample,s32 prev,s32& quant)
|
|||
u32 data=sample&7;
|
||||
|
||||
/*(1 - 2 * L4) * (L3 + L2/2 +L1/4 + 1/8) * quantized width (ƒΆn) + decode value (Xn - 1) */
|
||||
SampleType rv = prev + sign*((quant*adpcm_scale[data])>>3);
|
||||
SampleType rv = (quant * adpcm_scale[data]) >> 3;
|
||||
if (rv > 0x7FFF)
|
||||
rv = 0x7FFF;
|
||||
rv = sign * rv + prev;
|
||||
|
||||
quant = (quant * adpcm_qs[data])>>8;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#ifdef BKPT_SUPPORT
|
||||
#define CONSOLE_OUTPUT(a,b) \
|
||||
extern void (*dbgOutput)(char *, u32);\
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
using namespace vixl::aarch64;
|
||||
//#include "deps/vixl/aarch32/disasm-aarch32.h"
|
||||
|
||||
extern void Arm64CacheFlush(void* start, void* end);
|
||||
extern void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
|
||||
extern u32 arm_single_op(u32 opcode);
|
||||
extern "C" void arm_dispatch();
|
||||
extern "C" void arm_exit();
|
||||
|
@ -41,7 +41,7 @@ extern reg_pair arm_Reg[RN_ARM_REG_COUNT];
|
|||
MacroAssembler *assembler;
|
||||
|
||||
extern "C" void armFlushICache(void *bgn, void *end) {
|
||||
Arm64CacheFlush(bgn, end);
|
||||
vmem_platform_flush_cache(bgn, end, bgn, end);
|
||||
}
|
||||
|
||||
static MemOperand arm_reg_operand(u32 regn)
|
||||
|
@ -143,7 +143,9 @@ void armv_end(void* codestart, u32 cycl)
|
|||
|
||||
assembler->FinalizeCode();
|
||||
verify(assembler->GetBuffer()->GetCursorOffset() <= assembler->GetBuffer()->GetCapacity());
|
||||
Arm64CacheFlush(codestart, assembler->GetBuffer()->GetEndAddress<void*>());
|
||||
vmem_platform_flush_cache(
|
||||
codestart, assembler->GetBuffer()->GetEndAddress<void*>(),
|
||||
codestart, assembler->GetBuffer()->GetEndAddress<void*>());
|
||||
icPtr += assembler->GetBuffer()->GetSizeInBytes();
|
||||
|
||||
#if 0
|
||||
|
@ -499,8 +501,13 @@ __asm__ (
|
|||
".hidden arm_dispatch \n"
|
||||
"arm_dispatch: \n\t"
|
||||
"ldp w0, w1, [x28, #184] \n\t" // load Next PC, interrupt
|
||||
|
||||
"ubfx w2, w0, #2, #21 \n\t" // w2 = pc >> 2. Note: assuming address space <= 8 MB (23 bits)
|
||||
#if ARAM_SIZE == 2*1024*1024
|
||||
"ubfx w2, w0, #2, #19 \n\t" // w2 = pc >> 2. Note: assuming address space == 2 MB (21 bits)
|
||||
#elif ARAM_SIZE == 8*1024*1024
|
||||
"ubfx w2, w0, #2, #21 \n\t" // w2 = pc >> 2. Note: assuming address space == 8 MB (23 bits)
|
||||
#else
|
||||
#error Unsupported AICA RAM size
|
||||
#endif
|
||||
"cbnz w1, arm_dofiq \n\t" // if interrupt pending, handle it
|
||||
|
||||
"add x2, x26, x2, lsl #3 \n\t" // x2 = EntryPoints + pc << 1
|
||||
|
|
|
@ -378,19 +378,19 @@ struct DCFlashChip : MemChip
|
|||
else if ((val & 0xff) == 0x30)
|
||||
{
|
||||
// sector erase
|
||||
addr = max(addr, write_protect_size);
|
||||
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0x3FFF));
|
||||
memset(&data[addr&(~0x3FFF)],0xFF,0x4000);
|
||||
#else
|
||||
// AtomisWave's Macronix 29L001mc has 64k blocks
|
||||
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0xFFFF));
|
||||
u8 save[0x2000];
|
||||
// this area is write-protected on AW
|
||||
memcpy(save, data + 0x1a000, 0x2000);
|
||||
memset(&data[addr&(~0xFFFF)], 0xFF, 0x10000);
|
||||
memcpy(data + 0x1a000, save, 0x2000);
|
||||
if (addr >= write_protect_size)
|
||||
{
|
||||
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
u8 save[0x2000];
|
||||
// this area is write-protected on AW
|
||||
memcpy(save, data + 0x1a000, 0x2000);
|
||||
#endif
|
||||
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0x3FFF));
|
||||
memset(&data[addr&(~0x3FFF)],0xFF,0x4000);
|
||||
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
memcpy(data + 0x1a000, save, 0x2000);
|
||||
#endif
|
||||
}
|
||||
state = FS_Normal;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# GD-ROM: Gigabyte Disc Read-Only Memory
|
||||
|
||||
- This is the GD-ROM emulation part v3. v1 was unusable and v2 was our initial
|
||||
release.
|
||||
|
||||
### Notes:
|
||||
- Technical approach is wrong
|
||||
- Some secondary stuff are not (really) implemented
|
|
@ -256,6 +256,7 @@ void gd_set_state(gd_states state)
|
|||
|
||||
void gd_setdisc()
|
||||
{
|
||||
cdda.playing = false;
|
||||
DiscType newd = (DiscType)libGDR_GetDiscType();
|
||||
|
||||
switch(newd)
|
||||
|
|
|
@ -74,19 +74,19 @@ void RaiseAsicErr(HollyInterruptID inter)
|
|||
|
||||
void asic_RaiseInterrupt(HollyInterruptID inter)
|
||||
{
|
||||
u8 m=inter>>8;
|
||||
switch(m)
|
||||
{
|
||||
case 0:
|
||||
RaiseAsicNormal(inter);
|
||||
break;
|
||||
case 1:
|
||||
RaiseAsicExt(inter);
|
||||
break;
|
||||
case 2:
|
||||
RaiseAsicErr(inter);
|
||||
break;
|
||||
}
|
||||
u8 m=inter>>8;
|
||||
switch(m)
|
||||
{
|
||||
case 0:
|
||||
RaiseAsicNormal(inter);
|
||||
break;
|
||||
case 1:
|
||||
RaiseAsicExt(inter);
|
||||
break;
|
||||
case 2:
|
||||
RaiseAsicErr(inter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 Read_SB_ISTNRM(u32 addr)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "hw/naomi/naomi.h"
|
||||
|
||||
extern void dc_request_reset();
|
||||
|
||||
Array<RegisterStruct> sb_regs(0x540);
|
||||
|
||||
//(addr>= 0x005F6800) && (addr<=0x005F7CFF) -> 0x1500 bytes -> 0x540 possible registers , 125 actually exist only
|
||||
|
@ -194,7 +196,8 @@ void SB_SFRES_write32(u32 addr, u32 data)
|
|||
{
|
||||
if ((u16)data==0x7611)
|
||||
{
|
||||
printf("SB/HOLLY: System reset requested -- but cannot SOFT_RESET\n");
|
||||
printf("SB/HOLLY: System reset requested\n");
|
||||
dc_request_reset();
|
||||
}
|
||||
}
|
||||
void sb_Init()
|
||||
|
@ -780,7 +783,7 @@ void sb_Init()
|
|||
maple_Init();
|
||||
aica_sb_Init();
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST && defined(ENABLE_MODEM)
|
||||
ModemInit();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -206,7 +206,9 @@ T DYNACALL ReadMem_area0(u32 addr)
|
|||
}
|
||||
else if (likely((addr>= 0x005F8000) && (addr<=0x005F9FFF))) // :TA / PVR Core Reg.
|
||||
{
|
||||
if (sz != 4) return 0; // House of the Dead 2
|
||||
if (sz != 4)
|
||||
// House of the Dead 2
|
||||
return 0;
|
||||
return (T)pvr_ReadReg(addr);
|
||||
}
|
||||
}
|
||||
|
@ -215,8 +217,10 @@ T DYNACALL ReadMem_area0(u32 addr)
|
|||
{
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
|
||||
#else
|
||||
#elif defined(ENABLE_MODEM)
|
||||
return (T)ModemReadMem_A0_006(addr, sz);
|
||||
#else
|
||||
return (T)0;
|
||||
#endif
|
||||
}
|
||||
//map 0x0060 to 0x006F
|
||||
|
@ -300,7 +304,7 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
|
|||
{
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
libExtDevice_WriteMem_A0_006(addr, data, sz);
|
||||
#else
|
||||
#elif defined(ENABLE_MODEM)
|
||||
ModemWriteMem_A0_006(addr, data, sz);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "maple_devs.h"
|
||||
#include "maple_cfg.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
|
||||
#define HAS_VMU
|
||||
/*
|
||||
|
@ -28,13 +29,31 @@ extern u16 kcode[4];
|
|||
extern u32 vks[4];
|
||||
extern s8 joyx[4],joyy[4];
|
||||
extern u8 rt[4],lt[4];
|
||||
extern bool naomi_test_button;
|
||||
|
||||
u8 GetBtFromSgn(s8 val)
|
||||
{
|
||||
return val+128;
|
||||
}
|
||||
|
||||
u32 awave_button_mapping[] = {
|
||||
AWAVE_SERVICE_KEY, // DC_BTN_C
|
||||
AWAVE_BTN1_KEY, // DC_BTN_B
|
||||
AWAVE_BTN0_KEY, // DC_BTN_A
|
||||
AWAVE_START_KEY, // DC_BTN_START
|
||||
AWAVE_UP_KEY, // DC_DPAD_UP
|
||||
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
|
||||
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
|
||||
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
AWAVE_TEST_KEY, // DC_BTN_Z
|
||||
AWAVE_BTN3_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN2_KEY, // DC_BTN_X
|
||||
AWAVE_COIN_KEY, // DC_BTN_D
|
||||
// DC_DPAD2_UP
|
||||
// DC_DPAD2_DOWN
|
||||
// DC_DPAD2_LEFT
|
||||
// DC_DPAD2_RIGHT
|
||||
};
|
||||
|
||||
struct MapleConfigMap : IMapleConfigMap
|
||||
{
|
||||
maple_device* dev;
|
||||
|
@ -59,17 +78,32 @@ struct MapleConfigMap : IMapleConfigMap
|
|||
|
||||
pjs->kcode=kcode[player_num];
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
pjs->kcode |= 0xF901;
|
||||
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (naomi_test_button)
|
||||
pjs->kcode &= ~(1 << 14);
|
||||
// if (!(pjs->kcode & (1 << 9))) // Hack (Y -> service btn)
|
||||
// pjs->kcode &= ~(1 << 13);
|
||||
#endif
|
||||
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
|
||||
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
|
||||
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
|
||||
pjs->trigger[PJTI_R]=rt[player_num];
|
||||
pjs->trigger[PJTI_L]=lt[player_num];
|
||||
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
pjs->kcode = 0xFFFF;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((kcode[player_num] & (1 << i)) == 0)
|
||||
pjs->kcode &= ~awave_button_mapping[i];
|
||||
}
|
||||
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
|
||||
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
|
||||
{
|
||||
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
|
||||
pjs->joy[PJAI_Y1] = rt[player_num];
|
||||
pjs->joy[PJAI_X2] = lt[player_num];
|
||||
}
|
||||
else
|
||||
{
|
||||
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
|
||||
pjs->joy[PJAI_X2] = rt[player_num];
|
||||
pjs->joy[PJAI_Y2] = lt[player_num];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void SetImage(void* img)
|
||||
{
|
||||
|
@ -77,6 +111,16 @@ struct MapleConfigMap : IMapleConfigMap
|
|||
}
|
||||
};
|
||||
|
||||
bool maple_atomiswave_coin_chute(int slot)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((kcode[slot] & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
|
||||
{
|
||||
if (MapleDevices[bus][port] != NULL)
|
||||
|
@ -100,17 +144,32 @@ void mcfg_CreateAtomisWaveControllers()
|
|||
// Then other devices on port 2 and 3 for analog axes, light guns, ...
|
||||
mcfg_Create(MDT_SegaController, 0, 5);
|
||||
mcfg_Create(MDT_SegaController, 1, 5);
|
||||
// mcfg_Create(MDT_SegaController, 2, 5, 0);
|
||||
// mcfg_Create(MDT_SegaController, 3, 5, 1);
|
||||
// mcfg_Create(MDT_LightGun, 2, 5, 0);
|
||||
// mcfg_Create(MDT_LightGun, 3, 5, 1);
|
||||
// mcfg_Create(MDT_Mouse, 2, 5, 0);
|
||||
// Guilty Gear Isuka (4P) needs 4 std controllers
|
||||
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
|
||||
// Maximum Speed same
|
||||
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
|
||||
// Sports Shooting same
|
||||
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3
|
||||
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL)
|
||||
{
|
||||
// Game needs analog axes
|
||||
mcfg_Create(MDT_SegaController, 2, 5, 0);
|
||||
mcfg_Create(MDT_SegaController, 3, 5, 1);
|
||||
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
|
||||
// Maximum Speed same
|
||||
}
|
||||
else if (settings.input.JammaSetup == 1)
|
||||
{
|
||||
// 4 players
|
||||
mcfg_Create(MDT_SegaController, 2, 5);
|
||||
mcfg_Create(MDT_SegaController, 3, 5);
|
||||
}
|
||||
else if (settings.input.JammaSetup == 5)
|
||||
{
|
||||
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
|
||||
// Sports Shooting same
|
||||
mcfg_Create(MDT_LightGun, 2, 5, 0);
|
||||
mcfg_Create(MDT_LightGun, 3, 5, 1);
|
||||
}
|
||||
else if (settings.input.JammaSetup == 3)
|
||||
{
|
||||
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2
|
||||
mcfg_Create(MDT_Mouse, 2, 5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mcfg_CreateDevices()
|
||||
|
|
|
@ -68,3 +68,5 @@ void mcfg_CreateAtomisWaveControllers();
|
|||
void mcfg_DestroyDevices();
|
||||
void mcfg_SerializeDevices(void **data, unsigned int *total_size);
|
||||
void mcfg_UnserializeDevices(void **data, unsigned int *total_size);
|
||||
|
||||
bool maple_atomiswave_coin_chute(int slot);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "hw/naomi/naomi.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
#include "hw/pvr/spg.h"
|
||||
#include "input/gamepad.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "deps/zlib/zlib.h"
|
||||
|
@ -198,6 +199,35 @@ struct maple_base: maple_device
|
|||
*/
|
||||
struct maple_sega_controller: maple_base
|
||||
{
|
||||
virtual u32 get_capabilities() {
|
||||
// byte 0: 0 0 0 0 0 0 0 0
|
||||
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||
// byte 3: R L D U St A B C
|
||||
|
||||
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
|
||||
}
|
||||
|
||||
virtual u32 transform_kcode(u32 kcode) {
|
||||
return kcode;
|
||||
}
|
||||
|
||||
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return pjs.trigger[PJTI_R]; // Right trigger
|
||||
case 1:
|
||||
return pjs.trigger[PJTI_L]; // Left trigger
|
||||
case 2:
|
||||
return pjs.joy[PJAI_X1]; // Stick X
|
||||
case 3:
|
||||
return pjs.joy[PJAI_Y1]; // Stick Y
|
||||
default:
|
||||
return 0x80; // unused
|
||||
}
|
||||
}
|
||||
|
||||
virtual MapleDeviceType get_device_type()
|
||||
{
|
||||
return MDT_SegaController;
|
||||
|
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
|
|||
|
||||
//struct data
|
||||
//3*4
|
||||
w32( 0xfe060f00);
|
||||
w32( 0);
|
||||
w32( 0);
|
||||
w32(get_capabilities());
|
||||
w32(0);
|
||||
w32(0);
|
||||
|
||||
//1 area code
|
||||
w8(0xFF);
|
||||
|
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
|
|||
|
||||
//state data
|
||||
//2 key code
|
||||
w16(pjs.kcode);
|
||||
w16(transform_kcode(pjs.kcode));
|
||||
|
||||
//triggers
|
||||
//1 R
|
||||
w8(pjs.trigger[PJTI_R]);
|
||||
w8(get_analog_axis(0, pjs));
|
||||
//1 L
|
||||
w8(pjs.trigger[PJTI_L]);
|
||||
w8(get_analog_axis(1, pjs));
|
||||
|
||||
//joyx
|
||||
//1
|
||||
w8(pjs.joy[PJAI_X1]);
|
||||
w8(get_analog_axis(2, pjs));
|
||||
//joyy
|
||||
//1
|
||||
w8(pjs.joy[PJAI_Y1]);
|
||||
w8(get_analog_axis(3, pjs));
|
||||
|
||||
//not used
|
||||
//1
|
||||
w8(0x80);
|
||||
w8(get_analog_axis(4, pjs));
|
||||
//1
|
||||
w8(0x80);
|
||||
w8(get_analog_axis(5, pjs));
|
||||
}
|
||||
|
||||
return MDRS_DataTransfer;
|
||||
|
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
|
|||
}
|
||||
};
|
||||
|
||||
struct maple_atomiswave_controller: maple_sega_controller
|
||||
{
|
||||
virtual u32 get_capabilities() override {
|
||||
// byte 0: 0 0 0 0 0 0 0 0
|
||||
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||
// byte 3: R L D U St A B C
|
||||
|
||||
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
|
||||
}
|
||||
|
||||
virtual u32 transform_kcode(u32 kcode) override {
|
||||
return kcode | AWAVE_TRIGGER_KEY;
|
||||
}
|
||||
|
||||
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
|
||||
switch (index)
|
||||
{
|
||||
case 2:
|
||||
return pjs.joy[PJAI_X1];
|
||||
case 3:
|
||||
return pjs.joy[PJAI_Y1];
|
||||
case 4:
|
||||
return pjs.joy[PJAI_X2];
|
||||
case 5:
|
||||
return pjs.joy[PJAI_Y2];
|
||||
default:
|
||||
return 0x80;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Sega Dreamcast Visual Memory Unit
|
||||
This is pretty much done (?)
|
||||
|
@ -644,9 +706,7 @@ struct maple_sega_vmu: maple_base
|
|||
}
|
||||
}
|
||||
config->SetImage(lcd_data_decoded);
|
||||
#if !defined(TARGET_PANDORA) && HOST_OS != OS_DARWIN
|
||||
push_vmu_screen(lcd_data_decoded);
|
||||
#endif
|
||||
push_vmu_screen(bus_id, bus_port, lcd_data_decoded);
|
||||
#if 0
|
||||
// Update LCD window
|
||||
if (!dev->lcd.visible)
|
||||
|
@ -791,7 +851,7 @@ struct maple_microphone: maple_base
|
|||
switch (cmd)
|
||||
{
|
||||
case MDC_DeviceRequest:
|
||||
LOGI("maple_microphone::dma MDC_DeviceRequest");
|
||||
LOGI("maple_microphone::dma MDC_DeviceRequest\n");
|
||||
//this was copied from the controller case with just the id and name replaced!
|
||||
|
||||
//caps
|
||||
|
@ -826,7 +886,7 @@ struct maple_microphone: maple_base
|
|||
|
||||
case MDCF_GetCondition:
|
||||
{
|
||||
LOGI("maple_microphone::dma MDCF_GetCondition");
|
||||
LOGI("maple_microphone::dma MDCF_GetCondition\n");
|
||||
//this was copied from the controller case with just the id replaced!
|
||||
|
||||
//PlainJoystickState pjs;
|
||||
|
@ -863,7 +923,7 @@ struct maple_microphone: maple_base
|
|||
|
||||
case MDC_DeviceReset:
|
||||
//uhhh do nothing?
|
||||
LOGI("maple_microphone::dma MDC_DeviceReset");
|
||||
LOGI("maple_microphone::dma MDC_DeviceReset\n");
|
||||
return MDRS_DeviceReply;
|
||||
|
||||
case MDCF_MICControl:
|
||||
|
@ -932,7 +992,7 @@ struct maple_microphone: maple_base
|
|||
LOGI("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword);
|
||||
return MDRS_DeviceReply;
|
||||
case MDRE_TransmitAgain:
|
||||
LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain");
|
||||
LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransmitAgain\n");
|
||||
//apparently this doesnt matter
|
||||
//wptr(micdata, SIZE_OF_MIC_DATA);
|
||||
return MDRS_DeviceReply;//MDRS_DataTransfer;
|
||||
|
@ -1269,6 +1329,10 @@ struct maple_mouse : maple_base
|
|||
|
||||
struct maple_lightgun : maple_base
|
||||
{
|
||||
virtual u32 transform_kcode(u32 kcode) {
|
||||
return kcode | 0xFF01;
|
||||
}
|
||||
|
||||
virtual MapleDeviceType get_device_type()
|
||||
{
|
||||
return MDT_LightGun;
|
||||
|
@ -1317,21 +1381,13 @@ struct maple_lightgun : maple_base
|
|||
PlainJoystickState pjs;
|
||||
config->GetInput(&pjs);
|
||||
|
||||
// Also use the mouse buttons
|
||||
if (!(mo_buttons & 4)) // Left button
|
||||
pjs.kcode &= ~4; // A
|
||||
if (!(mo_buttons & 2)) // Right button
|
||||
pjs.kcode &= ~2; // B
|
||||
if (!(mo_buttons & 8)) // Wheel button
|
||||
pjs.kcode &= ~8; // Start
|
||||
|
||||
//caps
|
||||
//4
|
||||
w32(MFID_0_Input);
|
||||
|
||||
//state data
|
||||
//2 key code
|
||||
w16(pjs.kcode | 0xFF01);
|
||||
w16(transform_kcode(pjs.kcode));
|
||||
|
||||
//not used
|
||||
//2
|
||||
|
@ -1357,6 +1413,13 @@ struct maple_lightgun : maple_base
|
|||
}
|
||||
};
|
||||
|
||||
struct atomiswave_lightgun : maple_lightgun
|
||||
{
|
||||
virtual u32 transform_kcode(u32 kcode) override {
|
||||
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
|
||||
}
|
||||
};
|
||||
|
||||
extern u16 kcode[4];
|
||||
extern s8 joyx[4],joyy[4];
|
||||
extern u8 rt[4], lt[4];
|
||||
|
@ -1383,20 +1446,29 @@ static u16 getRightTriggerAxis()
|
|||
return rt[0] << 8;
|
||||
}
|
||||
|
||||
NaomiInputMapping Naomi_Mapping = {
|
||||
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
|
||||
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
|
||||
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
|
||||
u32 naomi_button_mapping[] = {
|
||||
NAOMI_SERVICE_KEY, // DC_BTN_C
|
||||
NAOMI_BTN1_KEY, // DC_BTN_B
|
||||
NAOMI_BTN0_KEY, // DC_BTN_A
|
||||
NAOMI_START_KEY, // DC_BTN_START
|
||||
NAOMI_UP_KEY, // DC_DPAD_UP
|
||||
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
|
||||
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
|
||||
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
NAOMI_TEST_KEY, // DC_BTN_Z
|
||||
NAOMI_BTN3_KEY, // DC_BTN_Y
|
||||
NAOMI_BTN2_KEY, // DC_BTN_X
|
||||
NAOMI_COIN_KEY, // DC_BTN_D
|
||||
// DC_DPAD2_UP
|
||||
// DC_DPAD2_DOWN
|
||||
// DC_DPAD2_LEFT
|
||||
// DC_DPAD2_RIGHT
|
||||
};
|
||||
|
||||
/*
|
||||
* Sega JVS I/O board
|
||||
*/
|
||||
bool coin_chute;
|
||||
static bool old_coin_chute;
|
||||
static int coin_count;
|
||||
bool naomi_test_button = false;
|
||||
static bool old_coin_chute[4];
|
||||
static int coin_count[4];
|
||||
|
||||
struct maple_naomi_jamma;
|
||||
|
||||
|
@ -2315,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
{
|
||||
JVS_STATUS1(); // report byte
|
||||
|
||||
LOGJVS("btns ");
|
||||
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
|
||||
// FIXME in-lst mapping
|
||||
u8 buttons[8] = { 0 };
|
||||
u32 keycode = ~kcode[0];
|
||||
for (int i = 0; i < 16; i++)
|
||||
if ((keycode & (1 << i)) != 0)
|
||||
{
|
||||
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
|
||||
}
|
||||
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
|
||||
u16 buttons[4] = { 0 };
|
||||
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
|
||||
{
|
||||
u8 *cur_btns = &buttons[(first_player + player) * 2];
|
||||
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]);
|
||||
JVS_OUT(cur_btns[0]);
|
||||
if (buffer_in[cmdi + 2] == 2)
|
||||
u32 keycode = ~kcode[first_player + player];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
LOGJVS("%02x ", cur_btns[1]);
|
||||
JVS_OUT(cur_btns[1]);
|
||||
if ((keycode & (1 << i)) != 0)
|
||||
buttons[player] |= naomi_button_mapping[i];
|
||||
}
|
||||
}
|
||||
|
||||
LOGJVS("btns ");
|
||||
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
|
||||
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
|
||||
{
|
||||
u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
|
||||
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
|
||||
JVS_OUT(cur_btns >> 8);
|
||||
if (buffer_in[cmdi + 2] == 2)
|
||||
{
|
||||
LOGJVS("%02x ", cur_btns & 0xFF);
|
||||
JVS_OUT(cur_btns);
|
||||
}
|
||||
}
|
||||
// for (int player = 0; player < jvs_request[channel][cmdi + 1]; player++)
|
||||
// {
|
||||
// u32 keycode = ~kcode[player];
|
||||
// if (keycode & DC_BTN_C)
|
||||
// keycode |= 0xFFff;
|
||||
//
|
||||
// if (jvs_request[channel][cmdi + 2] == 1)
|
||||
// JVS_OUT(keycode);
|
||||
// else
|
||||
// w16(keycode);
|
||||
// }
|
||||
cmdi += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21: // Read coins
|
||||
{
|
||||
if (coin_chute && !old_coin_chute)
|
||||
coin_count++;
|
||||
old_coin_chute = coin_chute;
|
||||
JVS_STATUS1(); // report byte
|
||||
LOGJVS("coins ");
|
||||
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
|
||||
{
|
||||
if (slot == 0)
|
||||
bool coin_chute = false;
|
||||
u32 keycode = ~kcode[first_player + slot];
|
||||
for (int i = 0; i < 16 && !coin_chute; i++)
|
||||
{
|
||||
LOGJVS("0:%d ", coin_count);
|
||||
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB
|
||||
JVS_OUT(coin_count); // coin count LSB
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGJVS("%d:0 ", slot);
|
||||
JVS_OUT(0);
|
||||
JVS_OUT(0);
|
||||
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
|
||||
coin_chute = true;
|
||||
}
|
||||
if (coin_chute && !old_coin_chute[first_player + slot])
|
||||
coin_count[first_player + slot] += 1;
|
||||
old_coin_chute[first_player + slot] = coin_chute;
|
||||
|
||||
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
|
||||
// status (2 highest bits, 0: normal), coin count MSB
|
||||
JVS_OUT((coin_count[first_player + slot] >> 8) & 0x3F);
|
||||
// coin count LSB
|
||||
JVS_OUT(coin_count[first_player + slot]);
|
||||
}
|
||||
cmdi += 2;
|
||||
}
|
||||
|
@ -2395,34 +2460,50 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
}
|
||||
LOGJVS("x,y:%4x,%4x ", x, y);
|
||||
JVS_OUT(x >> 8); // X, MSB
|
||||
JVS_OUT(x); // X, LSB
|
||||
JVS_OUT(x); // X, LSB
|
||||
JVS_OUT(y >> 8); // Y, MSB
|
||||
JVS_OUT(y); // Y, LSB
|
||||
JVS_OUT(y); // Y, LSB
|
||||
axis = 2;
|
||||
}
|
||||
|
||||
int full_axis_count = 0;
|
||||
int half_axis_count = 0;
|
||||
for (; axis < buffer_in[cmdi + 1]; axis++)
|
||||
{
|
||||
// FIXME Need to know how many axes per player for proper mapping
|
||||
u16 axis_value;
|
||||
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL)
|
||||
axis_value = Naomi_Mapping.axis[axis + first_player * 4]();
|
||||
if (NaomiGameInputs != NULL
|
||||
&& axis < ARRAY_SIZE(NaomiGameInputs->axes)
|
||||
&& NaomiGameInputs->axes[axis].name != NULL
|
||||
&& NaomiGameInputs->axes[axis].type == Half)
|
||||
{
|
||||
if (half_axis_count == 0)
|
||||
axis_value = rt[first_player] << 8;
|
||||
else if (half_axis_count == 1)
|
||||
axis_value = lt[first_player] << 8;
|
||||
else
|
||||
axis_value = 0;
|
||||
half_axis_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (axis) {
|
||||
switch (full_axis_count) {
|
||||
case 0:
|
||||
axis_value = (joyx[first_player + axis / 4] + 128) << 8;
|
||||
axis_value = (joyx[first_player] + 128) << 8;
|
||||
break;
|
||||
case 1:
|
||||
axis_value = (joyy[first_player + axis / 4] + 128) << 8;
|
||||
break;
|
||||
case 2:
|
||||
axis_value = rt[first_player + axis / 4] << 8;
|
||||
break;
|
||||
case 3:
|
||||
axis_value = lt[first_player + axis / 4] << 8;
|
||||
axis_value = (joyy[first_player] + 128) << 8;
|
||||
break;
|
||||
// TODO right analog stick
|
||||
// case 2:
|
||||
// axis_value = (joyrx[first_player] + 128) << 8;
|
||||
// break;
|
||||
// case 3:
|
||||
// axis_value = (joyry[first_player] + 128) << 8;
|
||||
// break;
|
||||
default:
|
||||
axis_value = 128;
|
||||
}
|
||||
full_axis_count++;
|
||||
}
|
||||
LOGJVS("%d:%4x ", axis, axis_value);
|
||||
JVS_OUT(axis_value >> 8);
|
||||
|
@ -2495,8 +2576,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
break;
|
||||
|
||||
case 0x30: // substract coin
|
||||
if (buffer_in[cmdi + 1] == 1)
|
||||
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
|
||||
if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
|
||||
coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
|
||||
JVS_STATUS1(); // report byte
|
||||
cmdi += 4;
|
||||
break;
|
||||
|
@ -2544,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
|
|||
switch(type)
|
||||
{
|
||||
case MDT_SegaController:
|
||||
rv=new maple_sega_controller();
|
||||
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||
rv = new maple_sega_controller();
|
||||
#else
|
||||
rv = new maple_atomiswave_controller();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MDT_Microphone:
|
||||
|
@ -2568,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
|
|||
break;
|
||||
|
||||
case MDT_LightGun:
|
||||
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||
rv = new maple_lightgun();
|
||||
#else
|
||||
rv = new atomiswave_lightgun();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MDT_NaomiJamma:
|
||||
|
|
|
@ -101,6 +101,6 @@ maple_device* maple_Create(MapleDeviceType type);
|
|||
#define SIZE_OF_MIC_DATA 480 //ALSO DEFINED IN SipEmulator.java
|
||||
#ifndef TARGET_PANDORA
|
||||
int get_mic_data(u8* buffer); //implemented in Android.cpp
|
||||
int push_vmu_screen(u8* buffer); //implemented in Android.cpp
|
||||
#endif
|
||||
void push_vmu_screen(int bus_id, int bus_port, u8* buffer);
|
||||
#define MAPLE_PORTS 4
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "maple_if.h"
|
||||
#include "maple_cfg.h"
|
||||
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
|
@ -36,6 +37,7 @@ int maple_schid;
|
|||
*/
|
||||
|
||||
void maple_DoDma();
|
||||
static void maple_handle_reconnect();
|
||||
|
||||
//really hackish
|
||||
//misses delay , and stop/start implementation
|
||||
|
@ -69,6 +71,9 @@ void maple_vblank()
|
|||
maple_ddt_pending_reset=false;
|
||||
}
|
||||
}
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
maple_handle_reconnect();
|
||||
#endif
|
||||
}
|
||||
void maple_SB_MSHTCL_Write(u32 addr, u32 data)
|
||||
{
|
||||
|
@ -273,3 +278,22 @@ void maple_Term()
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
static u64 reconnect_time;
|
||||
|
||||
void maple_ReconnectDevices()
|
||||
{
|
||||
mcfg_DestroyDevices();
|
||||
reconnect_time = sh4_sched_now64() + SH4_MAIN_CLOCK / 10;
|
||||
}
|
||||
|
||||
static void maple_handle_reconnect()
|
||||
{
|
||||
if (reconnect_time != 0 && reconnect_time <= sh4_sched_now64())
|
||||
{
|
||||
reconnect_time = 0;
|
||||
mcfg_CreateDevices();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,5 +8,6 @@ extern maple_device* MapleDevices[4][6];
|
|||
void maple_Init();
|
||||
void maple_Reset(bool Manual);
|
||||
void maple_Term();
|
||||
void maple_ReconnectDevices();
|
||||
|
||||
void maple_vblank();
|
||||
void maple_vblank();
|
||||
|
|
|
@ -21,7 +21,6 @@ _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
|
|||
//upper 8b of the address
|
||||
void* _vmem_MemInfo_ptr[0x100];
|
||||
|
||||
|
||||
void _vmem_get_ptrs(u32 sz,bool write,void*** vmap,void*** func)
|
||||
{
|
||||
*vmap=_vmem_MemInfo_ptr;
|
||||
|
@ -385,10 +384,7 @@ void _vmem_reset()
|
|||
verify(_vmem_register_handler(0,0,0,0,0,0)==0);
|
||||
}
|
||||
|
||||
void _vmem_term()
|
||||
{
|
||||
|
||||
}
|
||||
void _vmem_term() {}
|
||||
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
|
@ -409,414 +405,120 @@ void* malloc_pages(size_t size) {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool _vmem_reserve_nonvmem()
|
||||
{
|
||||
virt_ram_base = 0;
|
||||
|
||||
p_sh4rcb=(Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
|
||||
|
||||
mem_b.size=RAM_SIZE;
|
||||
mem_b.data=(u8*)malloc_pages(RAM_SIZE);
|
||||
|
||||
vram.size=VRAM_SIZE;
|
||||
vram.data=(u8*)malloc_pages(VRAM_SIZE);
|
||||
|
||||
aica_ram.size=ARAM_SIZE;
|
||||
aica_ram.data=(u8*)malloc_pages(ARAM_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _vmem_bm_reset_nvmem();
|
||||
|
||||
// Resets the FPCB table (by either clearing it to the default val
|
||||
// or by flushing it and making it fault on access again.
|
||||
void _vmem_bm_reset() {
|
||||
if (virt_ram_base) {
|
||||
#if !defined(TARGET_NO_NVMEM)
|
||||
_vmem_bm_reset_nvmem();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TARGET_IPHONE
|
||||
if (!virt_ram_base)
|
||||
#endif
|
||||
{
|
||||
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, FPCB_SIZE);
|
||||
}
|
||||
// If we allocated it via vmem:
|
||||
if (virt_ram_base)
|
||||
vmem_platform_reset_mem(p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
|
||||
else
|
||||
// We allocated it via a regular malloc/new/whatever on the heap
|
||||
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
|
||||
}
|
||||
|
||||
static void _vmem_release_nonvmem()
|
||||
{
|
||||
free(p_sh4rcb);
|
||||
free(vram.data);
|
||||
free(aica_ram.data);
|
||||
free(mem_b.data);
|
||||
}
|
||||
// This gets called whenever there is a pagefault, it is possible that it lands
|
||||
// on the fpcb memory range, which is allocated on miss. Returning true tells the
|
||||
// fault handler this was us, and that the page is resolved and can continue the execution.
|
||||
bool BM_LockedWrite(u8* address) {
|
||||
if (!virt_ram_base)
|
||||
return false; // No vmem, therefore not us who caused this.
|
||||
|
||||
#if !defined(TARGET_NO_NVMEM)
|
||||
uintptr_t ptrint = (uintptr_t)address;
|
||||
uintptr_t start = (uintptr_t)p_sh4rcb->fpcb;
|
||||
uintptr_t end = start + sizeof(p_sh4rcb->fpcb);
|
||||
|
||||
#define MAP_RAM_START_OFFSET 0
|
||||
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
|
||||
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
|
||||
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
HANDLE mem_handle;
|
||||
|
||||
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
|
||||
{
|
||||
void* ptr;
|
||||
void* rv;
|
||||
|
||||
u32 map_times=addrsz/size;
|
||||
verify((addrsz%size)==0);
|
||||
verify(map_times>=1);
|
||||
|
||||
rv= MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
|
||||
if (!rv)
|
||||
return 0;
|
||||
|
||||
for (u32 i=1;i<map_times;i++)
|
||||
{
|
||||
dst+=size;
|
||||
ptr=MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
|
||||
if (!ptr) return 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void* _nvmem_unused_buffer(u32 start,u32 end)
|
||||
{
|
||||
void* ptr=VirtualAlloc(&virt_ram_base[start],end-start,MEM_RESERVE,PAGE_NOACCESS);
|
||||
|
||||
if (ptr == 0)
|
||||
return 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* _nvmem_alloc_mem()
|
||||
{
|
||||
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
|
||||
|
||||
void* rv= (u8*)VirtualAlloc(0, 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (rv) VirtualFree(rv,0,MEM_RELEASE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MAP_NOSYNC
|
||||
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
|
||||
#endif
|
||||
|
||||
#ifdef _ANDROID
|
||||
#include <linux/ashmem.h>
|
||||
|
||||
#ifndef ASHMEM_DEVICE
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
#endif
|
||||
int ashmem_create_region(const char *name, size_t size)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
fd = open(ASHMEM_DEVICE, O_RDWR);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (name) {
|
||||
char buf[ASHMEM_NAME_LEN];
|
||||
|
||||
strlcpy(buf, name, sizeof(buf));
|
||||
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
return fd;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fd;
|
||||
void* _nvmem_unused_buffer(u32 start,u32 end)
|
||||
{
|
||||
void* ptr=mmap(&virt_ram_base[start], end-start, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (MAP_FAILED==ptr)
|
||||
return 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
|
||||
{
|
||||
void* ptr;
|
||||
void* rv;
|
||||
|
||||
printf("MAP %08X w/ %d\n",dst,offset);
|
||||
u32 map_times=addrsz/size;
|
||||
verify((addrsz%size)==0);
|
||||
verify(map_times>=1);
|
||||
u32 prot=PROT_READ|(w?PROT_WRITE:0);
|
||||
rv= mmap(&virt_ram_base[dst], size, prot, MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
|
||||
if (MAP_FAILED==rv || rv!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
|
||||
{
|
||||
printf("MAP1 failed %d\n",errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u32 i=1;i<map_times;i++)
|
||||
{
|
||||
dst+=size;
|
||||
ptr=mmap(&virt_ram_base[dst], size, prot , MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
|
||||
if (MAP_FAILED==ptr || ptr!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
|
||||
{
|
||||
printf("MAP2 failed %d\n",errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void* _nvmem_alloc_mem()
|
||||
{
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
string path = get_writable_data_path("/dcnzorz_mem");
|
||||
fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink(path.c_str());
|
||||
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
|
||||
#elif !defined(_ANDROID)
|
||||
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
|
||||
shm_unlink("/dcnzorz_mem");
|
||||
if (fd==-1)
|
||||
{
|
||||
fd = open("dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink("dcnzorz_mem");
|
||||
}
|
||||
|
||||
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
|
||||
#else
|
||||
|
||||
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
|
||||
if (false)//this causes writebacks to flash -> slow and stuttery
|
||||
{
|
||||
fd = open("/data/data/com.reicast.emulator/files/dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink("/data/data/com.reicast.emulator/files/dcnzorz_mem");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
u32 sz = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
|
||||
void* rv=mmap(0, sz, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
verify(rv != NULL);
|
||||
munmap(rv,sz);
|
||||
return (u8*)rv + 0x10000 - unat(rv)%0x10000;//align to 64 KB (Needed for linaro mmap not to extend to next region)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define map_buffer(dsts,dste,offset,sz,w) {ptr=_nvmem_map_buffer(dsts,dste-dsts,offset,sz,w);if (!ptr) return false;}
|
||||
#define unused_buffer(start,end) {ptr=_nvmem_unused_buffer(start,end);if (!ptr) return false;}
|
||||
|
||||
u32 pagecnt;
|
||||
void _vmem_bm_reset_nvmem()
|
||||
{
|
||||
#if defined(TARGET_NO_NVMEM)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_IPHONE
|
||||
//On iOS & nacl we allways allocate all of the mapping table
|
||||
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_READ | PROT_WRITE);
|
||||
return;
|
||||
#endif
|
||||
pagecnt=0;
|
||||
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
VirtualFree(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MEM_DECOMMIT);
|
||||
#else
|
||||
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_NONE);
|
||||
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_DONTNEED);
|
||||
#ifdef MADV_REMOVE
|
||||
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_REMOVE);
|
||||
#else
|
||||
//OSX, IOS
|
||||
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_FREE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf("Freeing fpcb\n");
|
||||
}
|
||||
|
||||
bool BM_LockedWrite(u8* address)
|
||||
{
|
||||
if (!_nvmem_enabled())
|
||||
return false;
|
||||
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
u32 addr=address-(u8*)p_sh4rcb->fpcb;
|
||||
|
||||
address=(u8*)p_sh4rcb->fpcb+ (addr&~PAGE_MASK);
|
||||
|
||||
if (addr<sizeof(p_sh4rcb->fpcb))
|
||||
{
|
||||
//printf("Allocated %d PAGES [%08X]\n",++pagecnt,addr);
|
||||
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
verify(VirtualAlloc(address,PAGE_SIZE,MEM_COMMIT,PAGE_READWRITE));
|
||||
#else
|
||||
mprotect (address, PAGE_SIZE, PROT_READ | PROT_WRITE);
|
||||
#endif
|
||||
|
||||
bm_vmem_pagefill((void**)address,PAGE_SIZE);
|
||||
|
||||
if (ptrint >= start && ptrint < end) {
|
||||
// Alloc the page then and initialize it to default values
|
||||
void *aligned_addr = (void*)(ptrint & (~PAGE_MASK));
|
||||
vmem_platform_ondemand_page(aligned_addr, PAGE_SIZE);
|
||||
bm_vmem_pagefill((void**)aligned_addr, PAGE_SIZE);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
die("BM_LockedWrite and NO REC");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _vmem_reserve()
|
||||
{
|
||||
void* ptr=0;
|
||||
|
||||
bool _vmem_reserve() {
|
||||
// TODO: Static assert?
|
||||
verify((sizeof(Sh4RCB)%PAGE_SIZE)==0);
|
||||
|
||||
if (settings.dynarec.disable_nvmem)
|
||||
return _vmem_reserve_nonvmem();
|
||||
VMemType vmemstatus = MemTypeError;
|
||||
|
||||
virt_ram_base=(u8*)_nvmem_alloc_mem();
|
||||
// Use vmem only if settings mandate so, and if we have proper exception handlers.
|
||||
#ifndef TARGET_NO_EXCEPTIONS
|
||||
if (!settings.dynarec.disable_nvmem)
|
||||
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
|
||||
#endif
|
||||
|
||||
if (virt_ram_base==0)
|
||||
return _vmem_reserve_nonvmem();
|
||||
|
||||
p_sh4rcb=(Sh4RCB*)virt_ram_base;
|
||||
// Fallback to statically allocated buffers, this results in slow-ops being generated.
|
||||
if (vmemstatus == MemTypeError) {
|
||||
printf("Warning! nvmem is DISABLED (due to failure or not being built-in\n");
|
||||
virt_ram_base = 0;
|
||||
|
||||
// Map the sh4 context but protect access to Sh4RCB.fpcb[]
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
//verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE));
|
||||
verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE,PAGE_NOACCESS));
|
||||
// Allocate it all and initialize it.
|
||||
p_sh4rcb = (Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
|
||||
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
|
||||
|
||||
verify(VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),MEM_COMMIT,PAGE_READWRITE));
|
||||
#else
|
||||
verify(p_sh4rcb==mmap(p_sh4rcb,sizeof(Sh4RCB),PROT_NONE,MAP_PRIVATE | MAP_ANON, -1, 0));
|
||||
mprotect((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),PROT_READ|PROT_WRITE);
|
||||
#endif
|
||||
virt_ram_base+=sizeof(Sh4RCB);
|
||||
mem_b.size = RAM_SIZE;
|
||||
mem_b.data = (u8*)malloc_pages(RAM_SIZE);
|
||||
|
||||
//Area 0
|
||||
//[0x00000000 ,0x00800000) -> unused
|
||||
unused_buffer(0x00000000,0x00800000);
|
||||
vram.size = VRAM_SIZE;
|
||||
vram.data = (u8*)malloc_pages(VRAM_SIZE);
|
||||
|
||||
//I wonder, aica ram warps here ?.?
|
||||
//I really should check teh docs before codin ;p
|
||||
//[0x00800000,0x00A00000);
|
||||
map_buffer(0x00800000,0x01000000,MAP_ARAM_START_OFFSET,ARAM_SIZE,false);
|
||||
map_buffer(0x20000000,0x20000000+ARAM_SIZE,MAP_ARAM_START_OFFSET,ARAM_SIZE,true);
|
||||
aica_ram.size = ARAM_SIZE;
|
||||
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
|
||||
}
|
||||
else {
|
||||
printf("Info: nvmem is enabled, with addr space of size %s\n", vmemstatus == MemType4GB ? "4GB" : "512MB");
|
||||
printf("Info: p_sh4rcb: %p virt_ram_base: %p\n", p_sh4rcb, virt_ram_base);
|
||||
// Map the different parts of the memory file into the new memory range we got.
|
||||
#define MAP_RAM_START_OFFSET 0
|
||||
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
|
||||
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
|
||||
const vmem_mapping mem_mappings[] = {
|
||||
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
|
||||
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica, wraps too
|
||||
{0x20000000, 0x20000000+ARAM_SIZE, MAP_ARAM_START_OFFSET, ARAM_SIZE, true},
|
||||
{0x01000000, 0x04000000, 0, 0, false}, // More unused
|
||||
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
|
||||
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
|
||||
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
|
||||
};
|
||||
vmem_platform_create_mappings(&mem_mappings[0], sizeof(mem_mappings) / sizeof(mem_mappings[0]));
|
||||
|
||||
aica_ram.size=ARAM_SIZE;
|
||||
aica_ram.data=(u8*)ptr;
|
||||
//[0x01000000 ,0x04000000) -> unused
|
||||
unused_buffer(0x01000000,0x04000000);
|
||||
|
||||
// Point buffers to actual data pointers
|
||||
aica_ram.size = ARAM_SIZE;
|
||||
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writtable AICA addrspace
|
||||
|
||||
//Area 1
|
||||
//[0x04000000,0x05000000) -> vram (16mb, warped on dc)
|
||||
map_buffer(0x04000000,0x05000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
|
||||
|
||||
vram.size=VRAM_SIZE;
|
||||
vram.data=(u8*)ptr;
|
||||
vram.size = VRAM_SIZE;
|
||||
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writtable and lockable)
|
||||
|
||||
//[0x05000000,0x06000000) -> unused (32b path)
|
||||
unused_buffer(0x05000000,0x06000000);
|
||||
|
||||
//[0x06000000,0x07000000) -> vram mirror
|
||||
map_buffer(0x06000000,0x07000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
|
||||
|
||||
|
||||
//[0x07000000,0x08000000) -> unused (32b path) mirror
|
||||
unused_buffer(0x07000000,0x08000000);
|
||||
|
||||
//Area 2
|
||||
//[0x08000000,0x0C000000) -> unused
|
||||
unused_buffer(0x08000000,0x0C000000);
|
||||
|
||||
//Area 3
|
||||
//[0x0C000000,0x0D000000) -> main ram
|
||||
//[0x0D000000,0x0E000000) -> main ram mirror
|
||||
//[0x0E000000,0x0F000000) -> main ram mirror
|
||||
//[0x0F000000,0x10000000) -> main ram mirror
|
||||
map_buffer(0x0C000000,0x10000000,MAP_RAM_START_OFFSET,RAM_SIZE,true);
|
||||
|
||||
mem_b.size=RAM_SIZE;
|
||||
mem_b.data=(u8*)ptr;
|
||||
|
||||
//Area 4
|
||||
//Area 5
|
||||
//Area 6
|
||||
//Area 7
|
||||
//all -> Unused
|
||||
//[0x10000000,0x20000000) -> unused
|
||||
unused_buffer(0x10000000,0x20000000);
|
||||
|
||||
printf("vmem reserve: base: %08X, aram: %08x, vram: %08X, ram: %08X\n",virt_ram_base,aica_ram.data,vram.data,mem_b.data);
|
||||
mem_b.size = RAM_SIZE;
|
||||
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
|
||||
}
|
||||
|
||||
// Clear out memory
|
||||
aica_ram.Zero();
|
||||
vram.Zero();
|
||||
mem_b.Zero();
|
||||
|
||||
printf("Mem alloc successful!\n");
|
||||
|
||||
return virt_ram_base!=0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _vmem_release()
|
||||
{
|
||||
if (!_nvmem_enabled())
|
||||
_vmem_release_nonvmem();
|
||||
else
|
||||
{
|
||||
if (virt_ram_base != NULL)
|
||||
{
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
VirtualFree(virt_ram_base, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(virt_ram_base, 0x20000000);
|
||||
#endif
|
||||
virt_ram_base = NULL;
|
||||
}
|
||||
#if HOST_OS != OS_WINDOWS
|
||||
close(fd);
|
||||
#endif
|
||||
#define freedefptr(x) \
|
||||
if (x) { free(x); x = NULL; }
|
||||
|
||||
void _vmem_release() {
|
||||
if (virt_ram_base)
|
||||
vmem_platform_destroy();
|
||||
else {
|
||||
freedefptr(p_sh4rcb);
|
||||
freedefptr(vram.data);
|
||||
freedefptr(aica_ram.data);
|
||||
freedefptr(mem_b.data);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool _vmem_reserve()
|
||||
{
|
||||
return _vmem_reserve_nonvmem();
|
||||
}
|
||||
void _vmem_release()
|
||||
{
|
||||
_vmem_release_nonvmem();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,41 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
enum VMemType {
|
||||
MemType4GB,
|
||||
MemType512MB,
|
||||
MemTypeError
|
||||
};
|
||||
|
||||
struct vmem_mapping {
|
||||
u32 start_address, end_address;
|
||||
unsigned memoffset, memsize;
|
||||
bool allow_writes;
|
||||
};
|
||||
|
||||
// Platform specific vmemory API
|
||||
// To initialize (maybe) the vmem subsystem
|
||||
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
|
||||
// To reset the on-demand allocated pages.
|
||||
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
|
||||
// To handle a fault&allocate an ondemand page.
|
||||
void vmem_platform_ondemand_page(void *address, unsigned size_bytes);
|
||||
// To create the mappings in the address space.
|
||||
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps);
|
||||
// Just tries to wipe as much as possible in the relevant area.
|
||||
void vmem_platform_destroy();
|
||||
// Given a block of data in the .text section, prepares it for JIT action.
|
||||
// both code_area and size are page aligned. Returns success.
|
||||
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rwx);
|
||||
// Same as above but uses two address spaces one with RX and RW protections.
|
||||
// Note: this function doesnt have to be implemented, it's a fallback for the above one.
|
||||
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rw, uintptr_t *rx_offset);
|
||||
// This might not need an implementation (ie x86/64 cpus).
|
||||
void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
|
||||
|
||||
// Note: if you want to disable vmem magic in any given platform, implement the
|
||||
// above functions as empty functions and make vmem_platform_init return MemTypeError.
|
||||
|
||||
//Typedef's
|
||||
//ReadMem
|
||||
typedef u8 DYNACALL _vmem_ReadMem8FP(u32 Address);
|
||||
|
@ -70,4 +105,4 @@ static inline bool _nvmem_enabled() {
|
|||
return virt_ram_base != 0;
|
||||
}
|
||||
|
||||
void _vmem_bm_reset();
|
||||
void _vmem_bm_reset();
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "types.h"
|
||||
|
||||
#if BUILD_COMPILER!=COMPILER_VC && (BUILD_COMPILER!=COMPILER_CLANG || !defined(WIN32))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
@ -145,3 +148,5 @@ char *read_name(char *reader, char *buffer, int *count)
|
|||
|
||||
return name;
|
||||
}
|
||||
|
||||
#endif // !COMPILER_VC_OR_CLANG_WIN32
|
|
@ -162,6 +162,11 @@ ROM board internal layouts:
|
|||
*/
|
||||
#include "awcartridge.h"
|
||||
#include "awave_regs.h"
|
||||
#ifdef _MSC_VER
|
||||
#undef min
|
||||
#undef max
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
u32 AWCartridge::ReadMem(u32 address, u32 size) {
|
||||
verify(size != 1);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "hw/holly/sb.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/holly/holly_intc.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
|
||||
#include "naomi.h"
|
||||
#include "naomi_cart.h"
|
||||
|
@ -15,7 +16,7 @@ u32 naomi_updates;
|
|||
|
||||
//#define NAOMI_COMM
|
||||
|
||||
u32 BoardID=0x980055AA;
|
||||
static const u32 BoardID=0x980055AA;
|
||||
u32 GSerialBuffer=0,BSerialBuffer=0;
|
||||
int GBufPos=0,BBufPos=0;
|
||||
int GState=0,BState=0;
|
||||
|
@ -388,6 +389,7 @@ u32 reg_dimm_48; //parameters
|
|||
u32 reg_dimm_4c=0x11; //status/control reg ?
|
||||
|
||||
bool NaomiDataRead = false;
|
||||
static bool aw_ram_test_skipped = false;
|
||||
|
||||
void naomi_process(u32 r3c,u32 r40,u32 r44, u32 r48)
|
||||
{
|
||||
|
@ -552,6 +554,8 @@ void naomi_reg_Term()
|
|||
void naomi_reg_Reset(bool Manual)
|
||||
{
|
||||
NaomiDataRead = false;
|
||||
aw_ram_test_skipped = false;
|
||||
BLastCmd = 0;
|
||||
}
|
||||
|
||||
void Update_naomi()
|
||||
|
@ -631,8 +635,6 @@ void Update_naomi()
|
|||
}
|
||||
|
||||
static u8 aw_maple_devs;
|
||||
extern bool coin_chute;
|
||||
static bool once = false;
|
||||
|
||||
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
||||
addr &= 0x7ff;
|
||||
|
@ -645,18 +647,19 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
|||
// c/d - 3P/4P coin inputs (EX. IO board), active low
|
||||
//
|
||||
// (ab == 0) -> BIOS skip RAM test
|
||||
if (!once)
|
||||
if (!aw_ram_test_skipped)
|
||||
{
|
||||
// Skip RAM test at startup
|
||||
once = true;
|
||||
aw_ram_test_skipped = true;
|
||||
return 0;
|
||||
}
|
||||
if (coin_chute)
|
||||
{
|
||||
// FIXME Coin Error if coin_chute is set for too long
|
||||
return 0xE;
|
||||
u8 coin_input = 0xF;
|
||||
for (int slot = 0; slot < 4; slot++)
|
||||
if (maple_atomiswave_coin_chute(slot))
|
||||
coin_input &= ~(1 << slot);
|
||||
return coin_input;
|
||||
}
|
||||
return 0xF;
|
||||
|
||||
case 0x284: // Atomiswave maple devices
|
||||
// ddcc0000 where cc/dd are the types of devices on maple bus 2 and 3:
|
||||
|
|
|
@ -28,11 +28,11 @@ bool bios_loaded = false;
|
|||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
fd_t* RomCacheMap;
|
||||
fd_t* RomCacheMap = NULL;
|
||||
u32 RomCacheMapCount;
|
||||
|
||||
char naomi_game_id[33];
|
||||
InputDescriptors *naomi_game_inputs;
|
||||
InputDescriptors *NaomiGameInputs;
|
||||
u8 *naomi_default_eeprom;
|
||||
|
||||
extern RomChip sys_rom;
|
||||
|
@ -246,7 +246,7 @@ static bool naomi_cart_LoadZip(char *filename)
|
|||
break;
|
||||
}
|
||||
CurrentCartridge->SetKey(game->key);
|
||||
naomi_game_inputs = game->inputs;
|
||||
NaomiGameInputs = game->inputs;
|
||||
|
||||
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
|
||||
{
|
||||
|
@ -636,11 +636,11 @@ bool naomi_cart_SelectFile()
|
|||
if (!naomi_cart_LoadRom(SelectedFile))
|
||||
{
|
||||
printf("Cannot load %s: error %d\n", SelectedFile, errno);
|
||||
cfgSetVirtual("config", "image", "");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
cfgSaveStr("emu", "gamefile", SelectedFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,6 @@ struct InputDescriptors
|
|||
AxisDescriptor axes[8];
|
||||
};
|
||||
|
||||
extern InputDescriptors *naomi_game_inputs;
|
||||
extern InputDescriptors *NaomiGameInputs;
|
||||
|
||||
#endif //NAOMI_CART_H
|
||||
|
|
|
@ -82,8 +82,7 @@ bool renderer_enabled = true; // Signals the renderer thread to exit
|
|||
bool renderer_changed = false; // Signals the renderer thread to switch renderer
|
||||
|
||||
#if !defined(TARGET_NO_THREADS)
|
||||
cResetEvent rs(false,true);
|
||||
cResetEvent re(false,true);
|
||||
cResetEvent rs, re;
|
||||
#endif
|
||||
|
||||
int max_idx,max_mvo,max_op,max_pt,max_tr,max_vtx,max_modt, ovrn;
|
||||
|
@ -99,6 +98,7 @@ TA_context* _pvrrc;
|
|||
void SetREP(TA_context* cntx);
|
||||
void killtex();
|
||||
bool render_output_framebuffer();
|
||||
static void rend_create_renderer();
|
||||
|
||||
void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
|
||||
FILE* fw = fopen(file, "wb");
|
||||
|
@ -267,6 +267,13 @@ bool rend_frame(TA_context* ctx, bool draw_osd) {
|
|||
|
||||
bool rend_single_frame()
|
||||
{
|
||||
if (renderer_changed)
|
||||
{
|
||||
renderer_changed = false;
|
||||
rend_term_renderer();
|
||||
rend_create_renderer();
|
||||
rend_init_renderer();
|
||||
}
|
||||
//wait render start only if no frame pending
|
||||
do
|
||||
{
|
||||
|
@ -363,6 +370,7 @@ void rend_init_renderer()
|
|||
}
|
||||
printf("Selected renderer initialization failed. Falling back to default renderer.\n");
|
||||
renderer = fallback_renderer;
|
||||
fallback_renderer = NULL; // avoid double-free
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +386,6 @@ void rend_term_renderer()
|
|||
delete fallback_renderer;
|
||||
fallback_renderer = NULL;
|
||||
}
|
||||
tactx_Term();
|
||||
}
|
||||
|
||||
void* rend_thread(void* p)
|
||||
|
@ -392,13 +399,6 @@ void* rend_thread(void* p)
|
|||
{
|
||||
if (rend_single_frame())
|
||||
renderer->Present();
|
||||
if (renderer_changed)
|
||||
{
|
||||
renderer_changed = false;
|
||||
rend_term_renderer();
|
||||
rend_create_renderer();
|
||||
rend_init_renderer();
|
||||
}
|
||||
}
|
||||
|
||||
rend_term_renderer();
|
||||
|
@ -539,6 +539,7 @@ void rend_end_render()
|
|||
void rend_stop_renderer()
|
||||
{
|
||||
renderer_enabled = false;
|
||||
tactx_Term();
|
||||
}
|
||||
|
||||
void rend_vblank()
|
||||
|
|
|
@ -9,7 +9,7 @@ f32 vrf(u32 addr);
|
|||
u32 vri(u32 addr);
|
||||
|
||||
//vram 32-64b
|
||||
extern VArray2 vram;
|
||||
extern VLockedMemory vram;
|
||||
//read
|
||||
u8 DYNACALL pvr_read_area1_8(u32 addr);
|
||||
u16 DYNACALL pvr_read_area1_16(u32 addr);
|
||||
|
@ -36,4 +36,4 @@ extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb);
|
|||
|
||||
void YUV_init();
|
||||
//registers
|
||||
#define PVR_BASE 0x005F8000
|
||||
#define PVR_BASE 0x005F8000
|
||||
|
|
|
@ -88,6 +88,8 @@ double full_rps;
|
|||
static u32 lightgun_line = 0xffff;
|
||||
static u32 lightgun_hpos;
|
||||
|
||||
double mspdf;
|
||||
|
||||
u32 fskip=0;
|
||||
//called from sh4 context , should update pvr/ta state and everything else
|
||||
int spg_line_sched(int tag, int cycl, int jit)
|
||||
|
@ -174,7 +176,7 @@ int spg_line_sched(int tag, int cycl, int jit)
|
|||
}
|
||||
|
||||
double frames_done=spd_cpu/2;
|
||||
double mspdf=1/frames_done*1000;
|
||||
mspdf=1/frames_done*1000;
|
||||
|
||||
full_rps=(spd_fps+fskip/ts);
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ void VDecEnd()
|
|||
|
||||
cMutex mtx_rqueue;
|
||||
TA_context* rqueue;
|
||||
cResetEvent frame_finished(false, true);
|
||||
cResetEvent frame_finished;
|
||||
|
||||
double last_frame = 0;
|
||||
u64 last_cyces = 0;
|
||||
|
|
|
@ -1311,10 +1311,10 @@ public:
|
|||
idx[1]=vbase+1;
|
||||
idx[2]=vbase+2;
|
||||
idx[3]=vbase+3;
|
||||
idx[4]=vbase+3;
|
||||
idx[5]=vbase+4;
|
||||
idx[4]=vbase+3;
|
||||
idx[5]=vbase+4;
|
||||
|
||||
CurrentPP->count=vdrc.idx.used()-CurrentPP->first-2;
|
||||
CurrentPP->count=vdrc.idx.used()-CurrentPP->first-2;
|
||||
|
||||
Vertex* cv = vdrc.verts.Append(4);
|
||||
|
||||
|
@ -1519,7 +1519,6 @@ int ta_parse_cnt = 0;
|
|||
bool ta_parse_vdrc(TA_context* ctx)
|
||||
{
|
||||
bool rv=false;
|
||||
|
||||
verify( vd_ctx == 0);
|
||||
vd_ctx = ctx;
|
||||
vd_rc = vd_ctx->rend;
|
||||
|
|
|
@ -86,49 +86,55 @@ u32 bm_gc_luc,bm_gcf_luc;
|
|||
|
||||
#define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
|
||||
|
||||
// This returns an executable address
|
||||
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
|
||||
{
|
||||
//rdv_FailedToFindBlock_pc=addr;
|
||||
DynarecCodeEntryPtr rv=(DynarecCodeEntryPtr)FPCA(addr);
|
||||
DynarecCodeEntryPtr rv = (DynarecCodeEntryPtr)FPCA(addr);
|
||||
|
||||
return (DynarecCodeEntryPtr)rv;
|
||||
}
|
||||
|
||||
// This returns an executable address
|
||||
DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr)
|
||||
{
|
||||
return (DynarecCodeEntryPtr)bm_GetCode(addr);
|
||||
}
|
||||
|
||||
// This returns an executable address
|
||||
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr)
|
||||
{
|
||||
DynarecCodeEntryPtr cde=bm_GetCode(addr);
|
||||
DynarecCodeEntryPtr cde = bm_GetCode(addr); // Returns RX ptr
|
||||
|
||||
if (cde==ngen_FailedToFindBlock)
|
||||
if (cde == ngen_FailedToFindBlock)
|
||||
return 0;
|
||||
else
|
||||
return bm_GetBlock((void*)cde);
|
||||
return bm_GetBlock((void*)cde); // Returns RX pointer
|
||||
}
|
||||
|
||||
// This takes a RX address and returns the info block ptr (RW space)
|
||||
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code)
|
||||
{
|
||||
blkmap_t::iterator iter=blkmap.find((RuntimeBlockInfo*)dynarec_code);
|
||||
if (iter!=blkmap.end())
|
||||
void *dynarecrw = CC_RX2RW(dynarec_code);
|
||||
blkmap_t::iterator iter = blkmap.find((RuntimeBlockInfo*)dynarecrw);
|
||||
if (iter != blkmap.end())
|
||||
{
|
||||
verify((*iter)->contains_code((u8*)dynarec_code));
|
||||
verify((*iter)->contains_code((u8*)dynarecrw));
|
||||
return *iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("bm_GetBlock(%p) failed ..\n",dynarec_code);
|
||||
printf("bm_GetBlock(%p) failed ..\n", dynarec_code);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes RX pointer and returns a RW pointer
|
||||
RuntimeBlockInfo* bm_GetStaleBlock(void* dynarec_code)
|
||||
{
|
||||
void *dynarecrw = CC_RX2RW(dynarec_code);
|
||||
for(u32 i=0;i<del_blocks.size();i++)
|
||||
{
|
||||
if (del_blocks[i]->contains_code((u8*)dynarec_code))
|
||||
if (del_blocks[i]->contains_code((u8*)dynarecrw))
|
||||
return del_blocks[i];
|
||||
}
|
||||
|
||||
|
@ -145,9 +151,8 @@ void bm_AddBlock(RuntimeBlockInfo* blk)
|
|||
}
|
||||
blkmap.insert(blk);
|
||||
|
||||
|
||||
verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock);
|
||||
FPCA(blk->addr)=blk->code;
|
||||
FPCA(blk->addr) = (DynarecCodeEntryPtr)CC_RW2RX(blk->code);
|
||||
|
||||
#ifdef DYNA_OPROF
|
||||
if (oprofHandle)
|
||||
|
@ -304,6 +309,8 @@ void bm_Rebuild()
|
|||
{
|
||||
return;
|
||||
|
||||
die("this is broken in multiple levels, including compile options");
|
||||
|
||||
void RASDASD();
|
||||
RASDASD();
|
||||
|
||||
|
@ -321,7 +328,7 @@ void bm_Rebuild()
|
|||
//constprop(all_blocks[i]);
|
||||
//#endif
|
||||
}
|
||||
ngen_Compile(all_blocks[i],false,false,all_blocks[i]->staging_runs>0,do_opts);
|
||||
ngen_Compile(all_blocks[i],NoCheck,false,all_blocks[i]->staging_runs>0,do_opts);
|
||||
|
||||
blkmap.insert(all_blocks[i]);
|
||||
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);
|
||||
|
@ -337,9 +344,9 @@ void bm_Rebuild()
|
|||
rebuild_counter=30;
|
||||
}
|
||||
|
||||
void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ)
|
||||
void bm_vmem_pagefill(void** ptr, u32 size_bytes)
|
||||
{
|
||||
for (size_t i=0; i<PAGE_SZ/sizeof(ptr[0]); i++)
|
||||
for (size_t i=0; i < size_bytes / sizeof(ptr[0]); i++)
|
||||
{
|
||||
ptr[i]=(void*)ngen_FailedToFindBlock;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ void bm_WriteBlockMap(const string& file);
|
|||
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr);
|
||||
|
||||
extern "C" {
|
||||
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
|
||||
ATTR_USED DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
|
||||
}
|
||||
|
||||
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code);
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
#include "types.h"
|
||||
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#elif HOST_OS==OS_LINUX
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "../sh4_interpreter.h"
|
||||
#include "../sh4_opcode_list.h"
|
||||
#include "../sh4_core.h"
|
||||
#include "../sh4_if.h"
|
||||
#include "hw/sh4/sh4_interrupts.h"
|
||||
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
|
@ -26,9 +20,7 @@
|
|||
#include "decoder.h"
|
||||
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
//uh uh
|
||||
|
||||
#if !defined(_WIN64)
|
||||
u8 SH4_TCB[CODE_SIZE+4096]
|
||||
#if HOST_OS == OS_WINDOWS || FEAT_SHREC != DYNAREC_JIT
|
||||
;
|
||||
|
@ -39,10 +31,9 @@ u8 SH4_TCB[CODE_SIZE+4096]
|
|||
#else
|
||||
#error SH4_TCB ALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
u8* CodeCache;
|
||||
|
||||
uintptr_t cc_rx_offset;
|
||||
|
||||
u32 LastAddr;
|
||||
u32 LastAddr_min;
|
||||
|
@ -86,6 +77,15 @@ void recSh4_Run()
|
|||
|
||||
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx);
|
||||
printf("cntx // fpcb offset: %td // pc offset: %td // pc %08X\n",(u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb,sh4rcb.cntx.pc);
|
||||
|
||||
if (!settings.dynarec.safemode)
|
||||
printf("Warning: Dynarec safe mode is off\n");
|
||||
|
||||
if (settings.dynarec.unstable_opt)
|
||||
printf("Warning: Unstable optimizations is on\n");
|
||||
|
||||
if (settings.dynarec.SmcCheckLevel != FullCheck)
|
||||
printf("Warning: SMC check mode is %d\n", settings.dynarec.SmcCheckLevel);
|
||||
|
||||
verify(rcb_noffs(&next_pc)==-184);
|
||||
ngen_mainloop(sh4_dyna_rcb);
|
||||
|
@ -119,34 +119,51 @@ u32 emit_FreeSpace()
|
|||
}
|
||||
|
||||
|
||||
bool DoCheck(u32 pc)
|
||||
SmcCheckEnum DoCheck(u32 pc)
|
||||
{
|
||||
if (IsOnRam(pc))
|
||||
{
|
||||
if (!settings.dynarec.unstable_opt)
|
||||
return true;
|
||||
|
||||
pc&=0xFFFFFF;
|
||||
switch(pc)
|
||||
{
|
||||
//DOA2LE
|
||||
case 0x3DAFC6:
|
||||
case 0x3C83F8:
|
||||
switch (settings.dynarec.SmcCheckLevel) {
|
||||
|
||||
//Shenmue 2
|
||||
case 0x348000:
|
||||
|
||||
//Shenmue
|
||||
case 0x41860e:
|
||||
|
||||
// Heuristic-elimintaed FastChecks
|
||||
case NoCheck: {
|
||||
if (IsOnRam(pc))
|
||||
{
|
||||
pc&=0xFFFFFF;
|
||||
switch(pc)
|
||||
{
|
||||
//DOA2LE
|
||||
case 0x3DAFC6:
|
||||
case 0x3C83F8:
|
||||
|
||||
return true;
|
||||
//Shenmue 2
|
||||
case 0x348000:
|
||||
|
||||
//Shenmue
|
||||
case 0x41860e:
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
return FastCheck;
|
||||
|
||||
default:
|
||||
return NoCheck;
|
||||
}
|
||||
}
|
||||
return NoCheck;
|
||||
}
|
||||
break;
|
||||
|
||||
// Fast Check everything
|
||||
case FastCheck:
|
||||
return FastCheck;
|
||||
|
||||
// Full Check everything
|
||||
case FullCheck:
|
||||
return FullCheck;
|
||||
|
||||
default:
|
||||
die("Unhandled settings.dynarec.SmcCheckLevel");
|
||||
return FullCheck;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnalyseBlock(RuntimeBlockInfo* blk);
|
||||
|
@ -249,7 +266,7 @@ DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
|
|||
//printf("rdv_FailedToFindBlock ~ %08X\n",pc);
|
||||
next_pc=pc;
|
||||
|
||||
return rdv_CompilePC();
|
||||
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC());
|
||||
}
|
||||
|
||||
static void ngen_FailedToFindBlock_internal() {
|
||||
|
@ -288,35 +305,27 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 pc)
|
|||
{
|
||||
next_pc=pc;
|
||||
recSh4_ClearCache();
|
||||
return rdv_CompilePC();
|
||||
}
|
||||
|
||||
DynarecCodeEntryPtr rdv_FindCode()
|
||||
{
|
||||
DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
|
||||
if (rv==ngen_FailedToFindBlock)
|
||||
return 0;
|
||||
|
||||
return rv;
|
||||
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC());
|
||||
}
|
||||
|
||||
DynarecCodeEntryPtr rdv_FindOrCompile()
|
||||
{
|
||||
DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
|
||||
if (rv==ngen_FailedToFindBlock)
|
||||
rv=rdv_CompilePC();
|
||||
DynarecCodeEntryPtr rv = bm_GetCode(next_pc); // Returns exec addr
|
||||
if (rv == ngen_FailedToFindBlock)
|
||||
rv = (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC()); // Returns rw addr
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
|
||||
{
|
||||
RuntimeBlockInfo* rbi=bm_GetBlock(code);
|
||||
// code is the RX addr to return after, however bm_GetBlock returns RW
|
||||
RuntimeBlockInfo* rbi = bm_GetBlock(code);
|
||||
|
||||
if (!rbi)
|
||||
{
|
||||
printf("Stale block ..");
|
||||
rbi=bm_GetStaleBlock(code);
|
||||
rbi = bm_GetStaleBlock(code);
|
||||
}
|
||||
|
||||
verify(rbi != NULL);
|
||||
|
@ -339,7 +348,7 @@ void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
|
|||
next_pc=rbi->NextBlock;
|
||||
}
|
||||
|
||||
DynarecCodeEntryPtr rv=rdv_FindOrCompile();
|
||||
DynarecCodeEntryPtr rv = rdv_FindOrCompile(); // Returns rx ptr
|
||||
|
||||
bool do_link=bm_GetBlock(code)==rbi;
|
||||
|
||||
|
@ -429,56 +438,23 @@ void recSh4_Init()
|
|||
if (_nvmem_enabled()) {
|
||||
verify(mem_b.data==((u8*)p_sh4rcb->sq_buffer+512+0x0C000000));
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#ifdef _MSC_VER
|
||||
for (int i = 10; i < 1300; i++) {
|
||||
|
||||
// Prepare some pointer to the pre-allocated code cache:
|
||||
void *candidate_ptr = (void*)(((unat)SH4_TCB + 4095) & ~4095);
|
||||
|
||||
//align to next page ..
|
||||
u8* ptr = (u8*)recSh4_Init - i * 1024 * 1024;
|
||||
|
||||
CodeCache = (u8*)VirtualAlloc(ptr, CODE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);//; (u8*)(((unat)SH4_TCB+4095)& ~4095);
|
||||
|
||||
if (CodeCache)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
CodeCache = (u8*)VirtualAlloc(NULL, CODE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#endif
|
||||
verify(CodeCache != NULL);
|
||||
#else
|
||||
CodeCache = (u8*)(((unat)SH4_TCB+4095)& ~4095);
|
||||
#endif
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
munmap(CodeCache, CODE_SIZE);
|
||||
CodeCache = (u8*)mmap(CodeCache, CODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
|
||||
#endif
|
||||
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
DWORD old;
|
||||
VirtualProtect(CodeCache,CODE_SIZE,PAGE_EXECUTE_READWRITE,&old);
|
||||
#elif HOST_OS == OS_LINUX || HOST_OS == OS_DARWIN
|
||||
|
||||
printf("\n\t CodeCache addr: %p | from: %p | addr here: %p\n", CodeCache, CodeCache, recSh4_Init);
|
||||
|
||||
#if FEAT_SHREC == DYNAREC_JIT
|
||||
if (mprotect(CodeCache, CODE_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC))
|
||||
{
|
||||
perror("\n\tError,Couldn’t mprotect CodeCache!");
|
||||
die("Couldn’t mprotect CodeCache");
|
||||
}
|
||||
// Call the platform-specific magic to make the pages RWX
|
||||
CodeCache = NULL;
|
||||
#ifdef FEAT_NO_RWX_PAGES
|
||||
verify(vmem_platform_prepare_jit_block(candidate_ptr, CODE_SIZE, (void**)&CodeCache, &cc_rx_offset));
|
||||
#else
|
||||
verify(vmem_platform_prepare_jit_block(candidate_ptr, CODE_SIZE, (void**)&CodeCache));
|
||||
#endif
|
||||
// Ensure the pointer returned is non-null
|
||||
verify(CodeCache != NULL);
|
||||
|
||||
#if TARGET_IPHONE
|
||||
memset((u8*)mmap(CodeCache, CODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0),0xFF,CODE_SIZE);
|
||||
#else
|
||||
memset(CodeCache,0xFF,CODE_SIZE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
memset(CodeCache, 0xFF, CODE_SIZE);
|
||||
ngen_init();
|
||||
bm_Reset();
|
||||
}
|
||||
|
||||
void recSh4_Term()
|
||||
|
@ -506,4 +482,5 @@ void Get_Sh4Recompiler(sh4_if* rv)
|
|||
rv->IsCpuRunning = recSh4_IsCpuRunning;
|
||||
rv->ResetCache = recSh4_ClearCache;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FEAT_SHREC != DYNAREC_NONE
|
||||
|
|
|
@ -48,6 +48,19 @@
|
|||
|
||||
#define CODE_SIZE (10*1024*1024)
|
||||
|
||||
// When NO_RWX is enabled there's two address-spaces, one executable and
|
||||
// one writtable. The emitter and most of the code in rec-* will work with
|
||||
// the RW pointer. However the fpcb table and other pointers during execution
|
||||
// (ie. exceptions) are RX pointers. These two macros convert between them by
|
||||
// sub/add the pointer offset. CodeCache will point to the RW pointer for simplicity.
|
||||
#ifdef FEAT_NO_RWX_PAGES
|
||||
extern uintptr_t cc_rx_offset;
|
||||
#define CC_RW2RX(ptr) (void*)(((uintptr_t)(ptr)) + cc_rx_offset)
|
||||
#define CC_RX2RW(ptr) (void*)(((uintptr_t)(ptr)) - cc_rx_offset)
|
||||
#else
|
||||
#define CC_RW2RX(ptr) (ptr)
|
||||
#define CC_RX2RW(ptr) (ptr)
|
||||
#endif
|
||||
|
||||
//alternative emit ptr, set to 0 to use the main buffer
|
||||
extern u32* emit_ptr;
|
||||
|
@ -85,7 +98,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
|
|||
void ngen_init();
|
||||
|
||||
//Called to compile a block
|
||||
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise);
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise);
|
||||
|
||||
//Called when blocks are reseted
|
||||
void ngen_ResetBlocks();
|
||||
|
|
|
@ -668,25 +668,10 @@ shil_opc(cvt_f2i_t)
|
|||
shil_canonical
|
||||
(
|
||||
u32,f1,(f32 f1),
|
||||
if (f1 > 2147483520.0f) // IEEE 754: 0x4effffff
|
||||
if (f1 > 2147483520.0f) // IEEE 754: 0x4effffff
|
||||
return 0x7fffffff;
|
||||
else
|
||||
return (s32)f1;
|
||||
|
||||
// No fast-math
|
||||
// if (f1 != f1) // NaN
|
||||
// return 0x80000000;
|
||||
// else if (f1 > 2147483520.0f) // IEEE 754: 0x4effffff
|
||||
// return 0x7fffffff;
|
||||
// else
|
||||
// {
|
||||
// u32 res = (s32)f1;
|
||||
// // Fix result sign for Intel CPUs
|
||||
// if (res == 0x80000000 && *(s32 *)&f1 > 0)
|
||||
// res = 0x7fffffff;
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
)
|
||||
|
||||
shil_compile
|
||||
|
|
|
@ -628,12 +628,12 @@ sh4op(i1111_nnnn_0011_1101)
|
|||
if (fpscr.PR == 0)
|
||||
{
|
||||
u32 n = GetN(op);
|
||||
fpul = (u32)(s32)min(fr[n], 2147483520.0f); // IEEE 754: 0x4effffff
|
||||
fpul = (u32)(s32)min(fr[n], 2147483520.0f); // IEEE 754: 0x4effffff
|
||||
|
||||
// Intel CPUs convert out of range float numbers to 0x80000000. Manually set the correct sign
|
||||
if (fpul == 0x80000000)
|
||||
{
|
||||
if (*(int *)&fr[n] > 0) // Using integer math to avoid issues with Inf and NaN
|
||||
if (*(int *)&fr[n] > 0) // Using integer math to avoid issues with Inf and NaN
|
||||
fpul--;
|
||||
}
|
||||
}
|
||||
|
@ -646,7 +646,7 @@ sh4op(i1111_nnnn_0011_1101)
|
|||
// Intel CPUs convert out of range float numbers to 0x80000000. Manually set the correct sign
|
||||
if (fpul == 0x80000000)
|
||||
{
|
||||
if (*(s64 *)&f > 0) // Using integer math to avoid issues with Inf and NaN
|
||||
if (*(s64 *)&f > 0) // Using integer math to avoid issues with Inf and NaN
|
||||
fpul--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ int AicaUpdate(int tag, int c, int j)
|
|||
|
||||
int DreamcastSecond(int tag, int c, int j)
|
||||
{
|
||||
settings.dreamcast.RTC++;
|
||||
RealTimeClock++;
|
||||
|
||||
#if 1 //HOST_OS==OS_WINDOWS
|
||||
prof_periodical();
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
//Types
|
||||
|
||||
#define printf_smc(...) // printf
|
||||
|
||||
|
||||
u32 CCN_QACR_TR[2];
|
||||
|
||||
|
@ -72,13 +74,18 @@ void CCN_CCR_write(u32 addr, u32 value)
|
|||
temp.reg_data=value;
|
||||
|
||||
|
||||
//what is 0xAC13DBF8 from ?
|
||||
if (temp.ICI && curr_pc!=0xAC13DBF8)
|
||||
{
|
||||
//printf("Sh4: i-cache invalidation %08X\n",curr_pc);
|
||||
// Shikigami No Shiro II sets ICI frequently
|
||||
// Any reason to flush the dynarec cache for this?
|
||||
//sh4_cpu.ResetCache();
|
||||
if (temp.ICI) {
|
||||
printf_smc("Sh4: i-cache invalidation %08X\n",curr_pc);
|
||||
|
||||
if (settings.dynarec.SmcCheckLevel != FullCheck) {
|
||||
//TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
|
||||
//which game is 0xAC13DBF8 from ?
|
||||
if (curr_pc != 0xAC13DBF8)
|
||||
{
|
||||
printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
|
||||
sh4_cpu.ResetCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp.ICI=0;
|
||||
|
|
|
@ -314,7 +314,7 @@ struct Sh4RCB
|
|||
Sh4Context cntx;
|
||||
};
|
||||
|
||||
extern Sh4RCB* p_sh4rcb;
|
||||
extern "C" Sh4RCB* p_sh4rcb;
|
||||
extern u8* sh4_dyna_rcb;
|
||||
|
||||
INLINE u32 sh4_sr_GetFull()
|
||||
|
|
|
@ -61,6 +61,7 @@ void ExecuteDelayslot_RTE();
|
|||
extern "C" {
|
||||
|
||||
int UpdateSystem();
|
||||
__attribute__((used)) int UpdateSystem_INTC();
|
||||
|
||||
ATTR_USED int UpdateSystem_INTC();
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
|
||||
//main system mem
|
||||
VArray2 mem_b;
|
||||
VLockedMemory mem_b;
|
||||
|
||||
void _vmem_init();
|
||||
void _vmem_reset();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "types.h"
|
||||
|
||||
//main system mem
|
||||
extern VArray2 mem_b;
|
||||
extern VLockedMemory mem_b;
|
||||
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "modules/mmu.h"
|
||||
|
|
|
@ -25,15 +25,15 @@ u64 sh4_sched_ffb;
|
|||
u32 sh4_sched_intr;
|
||||
|
||||
|
||||
vector<sched_list> list;
|
||||
vector<sched_list> sch_list; // using list as external inside a macro confuses clang and msc
|
||||
|
||||
int sh4_sched_next_id=-1;
|
||||
|
||||
u32 sh4_sched_remaining(int id, u32 reference)
|
||||
{
|
||||
if (list[id].end != -1)
|
||||
if (sch_list[id].end != -1)
|
||||
{
|
||||
return list[id].end - reference;
|
||||
return sch_list[id].end - reference;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ void sh4_sched_ffts()
|
|||
u32 diff=-1;
|
||||
int slot=-1;
|
||||
|
||||
for (size_t i=0;i<list.size();i++)
|
||||
for (size_t i=0;i<sch_list.size();i++)
|
||||
{
|
||||
if (sh4_sched_remaining(i)<diff)
|
||||
{
|
||||
|
@ -79,9 +79,9 @@ int sh4_sched_register(int tag, sh4_sched_callback* ssc)
|
|||
{
|
||||
sched_list t={ssc,tag,-1,-1};
|
||||
|
||||
list.push_back(t);
|
||||
sch_list.push_back(t);
|
||||
|
||||
return list.size()-1;
|
||||
return sch_list.size()-1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -103,16 +103,16 @@ void sh4_sched_request(int id, int cycles)
|
|||
{
|
||||
verify(cycles== -1 || (cycles >= 0 && cycles <= SH4_MAIN_CLOCK));
|
||||
|
||||
list[id].start=sh4_sched_now();
|
||||
sch_list[id].start=sh4_sched_now();
|
||||
|
||||
if (cycles == -1) {
|
||||
list[id].end = -1;
|
||||
sch_list[id].end = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
list[id].end = list[id].start + cycles;
|
||||
if (list[id].end == -1)
|
||||
list[id].end++;
|
||||
sch_list[id].end = sch_list[id].start + cycles;
|
||||
if (sch_list[id].end == -1)
|
||||
sch_list[id].end++;
|
||||
}
|
||||
|
||||
sh4_sched_ffts();
|
||||
|
@ -120,10 +120,10 @@ void sh4_sched_request(int id, int cycles)
|
|||
|
||||
int sh4_sched_elapsed(int id)
|
||||
{
|
||||
if (list[id].end!=-1)
|
||||
if (sch_list[id].end!=-1)
|
||||
{
|
||||
int rv=sh4_sched_now()-list[id].start;
|
||||
list[id].start=sh4_sched_now();
|
||||
int rv=sh4_sched_now()-sch_list[id].start;
|
||||
sch_list[id].start=sh4_sched_now();
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
|
@ -132,12 +132,12 @@ int sh4_sched_elapsed(int id)
|
|||
|
||||
void handle_cb(int id)
|
||||
{
|
||||
int remain=list[id].end-list[id].start;
|
||||
int remain=sch_list[id].end-sch_list[id].start;
|
||||
int elapsd=sh4_sched_elapsed(id);
|
||||
int jitter=elapsd-remain;
|
||||
|
||||
list[id].end=-1;
|
||||
int re_sch=list[id].cb(list[id].tag,remain,jitter);
|
||||
sch_list[id].end=-1;
|
||||
int re_sch=sch_list[id].cb(sch_list[id].tag,remain,jitter);
|
||||
|
||||
if (re_sch > 0)
|
||||
sh4_sched_request(id, max(0, re_sch - jitter));
|
||||
|
@ -156,7 +156,7 @@ void sh4_sched_tick(int cycles)
|
|||
sh4_sched_intr++;
|
||||
if (sh4_sched_next_id!=-1)
|
||||
{
|
||||
for (int i=0;i<list.size();i++)
|
||||
for (int i=0;i<sch_list.size();i++)
|
||||
{
|
||||
int remaining = sh4_sched_remaining(i, fztime);
|
||||
verify(remaining >= 0 || remaining == -1);
|
||||
|
|
|
@ -13,7 +13,7 @@ struct CHDDisc : Disc
|
|||
|
||||
u32 hunkbytes;
|
||||
u32 sph;
|
||||
|
||||
|
||||
CHDDisc()
|
||||
{
|
||||
chd=0;
|
||||
|
@ -22,8 +22,8 @@ struct CHDDisc : Disc
|
|||
|
||||
bool TryOpen(const wchar* file);
|
||||
|
||||
~CHDDisc()
|
||||
{
|
||||
~CHDDisc()
|
||||
{
|
||||
if (hunk_mem)
|
||||
delete [] hunk_mem;
|
||||
if (chd)
|
||||
|
@ -48,7 +48,7 @@ struct CHDTrack : TrackFile
|
|||
this->swap_bytes = swap_bytes;
|
||||
}
|
||||
|
||||
virtual void Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type)
|
||||
virtual void Read(u32 FAD, u8* dst, SectorFormat* sector_type, u8* subcode, SubcodeFormat* subcode_type)
|
||||
{
|
||||
u32 fad_offs = FAD + Offset;
|
||||
u32 hunk=(fad_offs)/disc->sph;
|
||||
|
@ -58,9 +58,9 @@ struct CHDTrack : TrackFile
|
|||
disc->old_hunk = hunk;
|
||||
}
|
||||
|
||||
u32 hunk_ofs=fad_offs%disc->sph;
|
||||
u32 hunk_ofs = fad_offs%disc->sph;
|
||||
|
||||
memcpy(dst,disc->hunk_mem+hunk_ofs*(2352+96),fmt);
|
||||
memcpy(dst, disc->hunk_mem + hunk_ofs * (2352+96), fmt);
|
||||
|
||||
if (swap_bytes)
|
||||
{
|
||||
|
@ -71,7 +71,6 @@ struct CHDTrack : TrackFile
|
|||
dst[i + 1] = b;
|
||||
}
|
||||
}
|
||||
|
||||
*sector_type=fmt==2352?SECFMT_2352:SECFMT_2048_MODE1;
|
||||
|
||||
//While space is reserved for it, the images contain no actual subcodes
|
||||
|
@ -100,23 +99,24 @@ bool CHDDisc::TryOpen(const wchar* file)
|
|||
|
||||
sph = hunkbytes/(2352+96);
|
||||
|
||||
if (hunkbytes%(2352+96)!=0)
|
||||
if (hunkbytes%(2352+96)!=0)
|
||||
{
|
||||
printf("chd: hunkbytes is invalid, %d\n",hunkbytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
u32 tag;
|
||||
u8 flags;
|
||||
char temp[512];
|
||||
u32 temp_len;
|
||||
u32 total_frames=150;
|
||||
s32 Offset = 0;
|
||||
u32 total_frames = 150;
|
||||
|
||||
u32 Offset = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char type[16], subtype[16], pgtype[16], pgsub[16];
|
||||
int tkid=-1,frames=0,pregap=0,postgap=0, padframes=0;
|
||||
int tkid=-1, frames=0, pregap=0, postgap=0, padframes=0;
|
||||
|
||||
err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, tracks.size(), temp, sizeof(temp), &temp_len, &tag, &flags);
|
||||
if (err == CHDERR_NONE)
|
||||
|
@ -124,7 +124,7 @@ bool CHDDisc::TryOpen(const wchar* file)
|
|||
//"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
|
||||
sscanf(temp, CDROM_TRACK_METADATA2_FORMAT, &tkid, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap);
|
||||
}
|
||||
else if (CHDERR_NONE == (err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, tracks.size(), temp, sizeof(temp), &temp_len, &tag, &flags)) )
|
||||
else if (CHDERR_NONE== (err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, tracks.size(), temp, sizeof(temp), &temp_len, &tag, &flags)) )
|
||||
{
|
||||
//CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
|
||||
sscanf(temp, CDROM_TRACK_METADATA_FORMAT, &tkid, type, subtype, &frames);
|
||||
|
@ -136,7 +136,6 @@ bool CHDDisc::TryOpen(const wchar* file)
|
|||
{
|
||||
err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, tracks.size(), temp, sizeof(temp), &temp_len, &tag, &flags);
|
||||
}
|
||||
|
||||
if (err == CHDERR_NONE)
|
||||
{
|
||||
//GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
|
||||
|
@ -160,8 +159,12 @@ bool CHDDisc::TryOpen(const wchar* file)
|
|||
t.EndFAD = total_frames - 1;
|
||||
t.ADDR = 0;
|
||||
t.CTRL = strcmp(type,"AUDIO") == 0 ? 0 : 4;
|
||||
t.file = new CHDTrack(this, t.StartFAD, Offset - t.StartFAD, strcmp(type,"MODE1") ? 2352 : 2048, t.CTRL == 0 && head->version >= 5);
|
||||
|
||||
t.file = new CHDTrack(this, t.StartFAD, Offset - t.StartFAD, strcmp(type, "MODE1") ? 2352 : 2048,
|
||||
// audio tracks are byteswapped in CHDv5+
|
||||
t.CTRL == 0 && head->version >= 5);
|
||||
|
||||
// CHD files are padded, so we have to respect the offset
|
||||
int padded = (frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING;
|
||||
Offset += padded * CD_TRACK_PADDING;
|
||||
|
||||
|
@ -186,7 +189,7 @@ bool CHDDisc::TryOpen(const wchar* file)
|
|||
Disc* chd_parse(const wchar* file)
|
||||
{
|
||||
CHDDisc* rv = new CHDDisc();
|
||||
|
||||
|
||||
if (rv->TryOpen(file))
|
||||
return rv;
|
||||
else
|
||||
|
|
|
@ -133,7 +133,7 @@ bool ConvertSector(u8* in_buff , u8* out_buff , int from , int to,int sector)
|
|||
|
||||
Disc* OpenDisc(const wchar* fn)
|
||||
{
|
||||
Disc* rv = nullptr;
|
||||
Disc* rv = NULL;
|
||||
|
||||
for (unat i=0; drivers[i] && !rv; i++) { // ;drivers[i] && !(rv=drivers[i](fn));
|
||||
rv = drivers[i](fn);
|
||||
|
|
|
@ -3,10 +3,22 @@
|
|||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
// On windows, transform / to \\
|
||||
|
||||
string normalize_path_separator(string path)
|
||||
{
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
std::replace(path.begin(), path.end(), '/', '\\');
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// given file/name.ext or file\name.ext returns file/ or file\, depending on the platform
|
||||
// given name.ext returns ./ or .\, depending on the platform
|
||||
string OS_dirname(string file)
|
||||
{
|
||||
file = normalize_path_separator(file);
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
const char sep = '\\';
|
||||
#else
|
||||
|
@ -25,19 +37,6 @@ string OS_dirname(string file)
|
|||
return file.substr(0, last_slash + 1);
|
||||
}
|
||||
|
||||
// On windows, transform / to \\
|
||||
// On linux, transform \\ to /
|
||||
string normalize_path_separator(string path)
|
||||
{
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
std::replace( path.begin(), path.end(), '/', '\\');
|
||||
#else
|
||||
std::replace( path.begin(), path.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#if 0 // TODO: Move this to some tests, make it platform agnostic
|
||||
namespace {
|
||||
struct OS_dirname_Test {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <ntddscsi.h>
|
||||
#include "SCSIDEFS.H"
|
||||
|
@ -388,4 +388,4 @@ Disc* ioctl_parse(const wchar* file)
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -53,8 +53,8 @@ enum DreamcastKey
|
|||
|
||||
// System axes
|
||||
EMU_AXIS_NONE = 0x00000,
|
||||
EMU_AXIS_DPAD1_X = 0x00001,
|
||||
EMU_AXIS_DPAD1_Y = 0x00002,
|
||||
EMU_AXIS_DPAD2_X = 0x00003,
|
||||
EMU_AXIS_DPAD2_Y = 0x00004,
|
||||
EMU_AXIS_DPAD1_X = DC_DPAD_LEFT,
|
||||
EMU_AXIS_DPAD1_Y = DC_DPAD_UP,
|
||||
EMU_AXIS_DPAD2_X = DC_DPAD2_LEFT,
|
||||
EMU_AXIS_DPAD2_Y = DC_DPAD2_RIGHT,
|
||||
};
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <limits.h>
|
||||
#include "gamepad_device.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
#define MAPLE_PORT_CFG_PREFIX "maple_"
|
||||
|
||||
extern void dc_exit();
|
||||
|
||||
|
@ -32,7 +36,8 @@ std::mutex GamepadDevice::_gamepads_mutex;
|
|||
|
||||
bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
||||
{
|
||||
if (_input_detected != NULL && _detecting_button && pressed)
|
||||
if (_input_detected != NULL && _detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && pressed)
|
||||
{
|
||||
_input_detected(code);
|
||||
_input_detected = NULL;
|
||||
|
@ -46,7 +51,39 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
if (key < 0x10000)
|
||||
{
|
||||
if (pressed)
|
||||
{
|
||||
kcode[_maple_port] &= ~(u16)key;
|
||||
// Avoid two opposite dpad keys being pressed simultaneously
|
||||
switch (key)
|
||||
{
|
||||
case DC_DPAD_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_DOWN;
|
||||
break;
|
||||
case DC_DPAD_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_UP;
|
||||
break;
|
||||
case DC_DPAD_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_RIGHT;
|
||||
break;
|
||||
case DC_DPAD_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_LEFT;
|
||||
break;
|
||||
case DC_DPAD2_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_DOWN;
|
||||
break;
|
||||
case DC_DPAD2_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_UP;
|
||||
break;
|
||||
case DC_DPAD2_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT;
|
||||
break;
|
||||
case DC_DPAD2_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_LEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
kcode[_maple_port] |= (u16)key;
|
||||
}
|
||||
|
@ -84,7 +121,8 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
|||
v = (get_axis_min_value(code) + get_axis_range(code) - value) * 255 / get_axis_range(code) - 128;
|
||||
else
|
||||
v = (value - get_axis_min_value(code)) * 255 / get_axis_range(code) - 128; //-128 ... + 127 range
|
||||
if (_input_detected != NULL && !_detecting_button && (v >= 64 || v <= -64))
|
||||
if (_input_detected != NULL && !_detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && (v >= 64 || v <= -64))
|
||||
{
|
||||
_input_detected(code);
|
||||
_input_detected = NULL;
|
||||
|
@ -235,3 +273,51 @@ void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms)
|
|||
gamepad->rumble(power, inclination, duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void GamepadDevice::detect_btn_input(input_detected_cb button_pressed)
|
||||
{
|
||||
_input_detected = button_pressed;
|
||||
_detecting_button = true;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
}
|
||||
|
||||
void GamepadDevice::detect_axis_input(input_detected_cb axis_moved)
|
||||
{
|
||||
_input_detected = axis_moved;
|
||||
_detecting_button = false;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
}
|
||||
|
||||
void GamepadDevice::Register(std::shared_ptr<GamepadDevice> gamepad)
|
||||
{
|
||||
int maple_port = cfgLoadInt("input",
|
||||
(MAPLE_PORT_CFG_PREFIX + gamepad->unique_id()).c_str(), 12345);
|
||||
if (maple_port != 12345)
|
||||
gamepad->set_maple_port(maple_port);
|
||||
|
||||
_gamepads_mutex.lock();
|
||||
_gamepads.push_back(gamepad);
|
||||
_gamepads_mutex.unlock();
|
||||
}
|
||||
|
||||
void GamepadDevice::Unregister(std::shared_ptr<GamepadDevice> gamepad)
|
||||
{
|
||||
gamepad->save_mapping();
|
||||
_gamepads_mutex.lock();
|
||||
for (auto it = _gamepads.begin(); it != _gamepads.end(); it++)
|
||||
if (*it == gamepad) {
|
||||
_gamepads.erase(it);
|
||||
break;
|
||||
}
|
||||
_gamepads_mutex.unlock();
|
||||
}
|
||||
|
||||
void GamepadDevice::SaveMaplePorts()
|
||||
{
|
||||
for (int i = 0; i < GamepadDevice::GetGamepadCount(); i++)
|
||||
{
|
||||
std::shared_ptr<GamepadDevice> gamepad = GamepadDevice::GetGamepad(i);
|
||||
if (gamepad != NULL && !gamepad->unique_id().empty())
|
||||
cfgSaveInt("input", (MAPLE_PORT_CFG_PREFIX + gamepad->unique_id()).c_str(), gamepad->maple_port());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,20 +31,13 @@ public:
|
|||
const std::string& name() { return _name; }
|
||||
int maple_port() { return _maple_port; }
|
||||
void set_maple_port(int port) { _maple_port = port; }
|
||||
const std::string& unique_id() { return _unique_id; }
|
||||
virtual bool gamepad_btn_input(u32 code, bool pressed);
|
||||
bool gamepad_axis_input(u32 code, int value);
|
||||
virtual ~GamepadDevice() {}
|
||||
|
||||
void detect_btn_input(input_detected_cb button_pressed)
|
||||
{
|
||||
_input_detected = button_pressed;
|
||||
_detecting_button = true;
|
||||
}
|
||||
void detect_axis_input(input_detected_cb axis_moved)
|
||||
{
|
||||
_input_detected = axis_moved;
|
||||
_detecting_button = false;
|
||||
}
|
||||
void detect_btn_input(input_detected_cb button_pressed);
|
||||
void detect_axis_input(input_detected_cb axis_moved);
|
||||
void cancel_detect_input()
|
||||
{
|
||||
_input_detected = NULL;
|
||||
|
@ -58,28 +51,13 @@ public:
|
|||
virtual void update_rumble() {}
|
||||
bool is_rumble_enabled() { return _rumble_enabled; }
|
||||
|
||||
static void Register(std::shared_ptr<GamepadDevice> gamepad)
|
||||
{
|
||||
_gamepads_mutex.lock();
|
||||
_gamepads.push_back(gamepad);
|
||||
_gamepads_mutex.unlock();
|
||||
}
|
||||
static void Register(std::shared_ptr<GamepadDevice> gamepad);
|
||||
|
||||
static void Unregister(std::shared_ptr<GamepadDevice> gamepad)
|
||||
{
|
||||
gamepad->save_mapping();
|
||||
_gamepads_mutex.lock();
|
||||
for (auto it = _gamepads.begin(); it != _gamepads.end(); it++)
|
||||
if (*it == gamepad)
|
||||
{
|
||||
_gamepads.erase(it);
|
||||
break;
|
||||
}
|
||||
_gamepads_mutex.unlock();
|
||||
}
|
||||
static void Unregister(std::shared_ptr<GamepadDevice> gamepad);
|
||||
|
||||
static int GetGamepadCount();
|
||||
static std::shared_ptr<GamepadDevice> GetGamepad(int index);
|
||||
static void SaveMaplePorts();
|
||||
|
||||
protected:
|
||||
GamepadDevice(int maple_port, const char *api_name, bool remappable = true)
|
||||
|
@ -91,6 +69,7 @@ protected:
|
|||
virtual void load_axis_min_max(u32 axis) {}
|
||||
|
||||
std::string _name;
|
||||
std::string _unique_id = "";
|
||||
InputMapping *input_mapper;
|
||||
std::map<u32, int> axis_min_values;
|
||||
std::map<u32, unsigned int> axis_ranges;
|
||||
|
@ -104,6 +83,7 @@ private:
|
|||
std::string _api_name;
|
||||
int _maple_port;
|
||||
bool _detecting_button = false;
|
||||
double _detection_start_time;
|
||||
input_detected_cb _input_detected;
|
||||
bool _remappable;
|
||||
float _dead_zone = 0.1f;
|
||||
|
|
|
@ -104,6 +104,8 @@ void InputMapping::set_axis(DreamcastKey id, u32 code, bool is_inverted)
|
|||
}
|
||||
}
|
||||
|
||||
using namespace emucfg;
|
||||
|
||||
void InputMapping::load(FILE* fp)
|
||||
{
|
||||
ConfigFile mf;
|
||||
|
|
|
@ -9,12 +9,18 @@ public:
|
|||
: GamepadDevice(maple_port, "evdev"), _fd(fd), _rumble_effect_id(-1), _devnode(devnode)
|
||||
{
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
char name[256] = "Unknown";
|
||||
if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||
char buf[256] = "Unknown";
|
||||
if (ioctl(fd, EVIOCGNAME(sizeof(buf) - 1), buf) < 0)
|
||||
perror("evdev: ioctl(EVIOCGNAME)");
|
||||
else
|
||||
printf("evdev: Opened device '%s' ", name);
|
||||
_name = name;
|
||||
printf("evdev: Opened device '%s' ", buf);
|
||||
_name = buf;
|
||||
buf[0] = 0;
|
||||
if (ioctl(fd, EVIOCGUNIQ(sizeof(buf) - 1), buf) == 0)
|
||||
_unique_id = buf;
|
||||
if (_unique_id.empty())
|
||||
_unique_id = devnode;
|
||||
|
||||
if (!find_mapping(mapping_file))
|
||||
{
|
||||
#if defined(TARGET_PANDORA)
|
||||
|
@ -22,18 +28,18 @@ public:
|
|||
#elif defined(TARGET_GCW0)
|
||||
mapping_file = "controller_gcwz.cfg";
|
||||
#else
|
||||
if (!strcmp(name, "Microsoft X-Box 360 pad")
|
||||
|| !strcmp(name, "Xbox 360 Wireless Receiver")
|
||||
|| !strcmp(name, "Xbox 360 Wireless Receiver (XBOX)"))
|
||||
if (_name == "Microsoft X-Box 360 pad"
|
||||
|| _name == "Xbox 360 Wireless Receiver"
|
||||
|| _name == "Xbox 360 Wireless Receiver (XBOX)")
|
||||
{
|
||||
mapping_file = "controller_xpad.cfg";
|
||||
}
|
||||
else if (strstr(name, "Xbox Gamepad (userspace driver)") != NULL)
|
||||
else if (_name.find("Xbox Gamepad (userspace driver)") != std::string::npos)
|
||||
{
|
||||
mapping_file = "controller_xboxdrv.cfg";
|
||||
}
|
||||
else if (strstr(name, "keyboard") != NULL ||
|
||||
strstr(name, "Keyboard") != NULL)
|
||||
else if (_name.find("keyboard") != std::string::npos
|
||||
|| _name.find("Keyboard") != std::string::npos)
|
||||
{
|
||||
mapping_file = "keyboard.cfg";
|
||||
}
|
||||
|
|
|
@ -408,7 +408,6 @@ int main(int argc, wchar* argv[])
|
|||
#endif
|
||||
|
||||
int get_mic_data(u8* buffer) { return 0; }
|
||||
int push_vmu_screen(u8* buffer) { return 0; }
|
||||
|
||||
void os_DebugBreak()
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
X11MouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "X11")
|
||||
{
|
||||
_name = "Mouse";
|
||||
_unique_id = "x11_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = new MouseInputMapping();
|
||||
}
|
||||
|
@ -83,8 +84,6 @@ Atom wmDeleteMessage;
|
|||
void* x11_vis;
|
||||
|
||||
extern bool dump_frame_switch;
|
||||
extern bool naomi_test_button;
|
||||
extern bool coin_chute;
|
||||
|
||||
void dc_exit(void);
|
||||
|
||||
|
@ -274,16 +273,6 @@ void input_x11_handle()
|
|||
x11_fullscreen = !x11_fullscreen;
|
||||
x11_window_set_fullscreen(x11_fullscreen);
|
||||
}
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
else if (e.xkey.keycode == KEY_F8)
|
||||
{
|
||||
coin_chute = e.type == KeyPress;
|
||||
}
|
||||
else if (e.xkey.keycode == KEY_F7)
|
||||
{
|
||||
naomi_test_button = e.type == KeyPress;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -372,6 +361,11 @@ void input_x11_init()
|
|||
printf("X11 Keyboard input disabled by config.\n");
|
||||
}
|
||||
|
||||
static int x11_error_handler(Display *, XErrorEvent *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void x11_window_create()
|
||||
{
|
||||
if (cfgLoadInt("pvr", "nox11", 0) == 0)
|
||||
|
@ -530,20 +524,22 @@ void x11_window_create()
|
|||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
None
|
||||
};
|
||||
int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&x11_error_handler);
|
||||
|
||||
x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs);
|
||||
if (!x11_glc)
|
||||
{
|
||||
printf("Open GL 4.3 not supported\n");
|
||||
// Try GL 3.1
|
||||
// Try GL 3.0
|
||||
context_attribs[1] = 3;
|
||||
context_attribs[3] = 1;
|
||||
context_attribs[3] = 0;
|
||||
x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs);
|
||||
if (!x11_glc)
|
||||
{
|
||||
die("Open GL 3.1 not supported\n");
|
||||
die("Open GL 3.0 not supported\n");
|
||||
}
|
||||
}
|
||||
XSetErrorHandler(old_handler);
|
||||
XSync(x11Display, False);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -181,6 +181,7 @@ public:
|
|||
X11KbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "X11")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "x11_keyboard";
|
||||
if (!find_mapping())
|
||||
input_mapper = new KbInputMapping();
|
||||
}
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
#include <sys/personality.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#if HOST_OS == OS_DARWIN
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
|
||||
|
@ -57,19 +53,14 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(TARGET_NO_EXCEPTIONS)
|
||||
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
|
||||
{
|
||||
rei_host_context_t ctx;
|
||||
|
||||
context_from_segfault(&ctx, segfault_ctx);
|
||||
|
||||
bool dyna_cde = ((unat)ctx.pc>(unat)CodeCache) && ((unat)ctx.pc<(unat)(CodeCache + CODE_SIZE));
|
||||
bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE));
|
||||
|
||||
//ucontext_t* ctx=(ucontext_t*)ctxr;
|
||||
//printf("mprot hit @ ptr 0x%08X @@ code: %08X, %d\n",si->si_addr,ctx->uc_mcontext.arm_pc,dyna_cde);
|
||||
|
||||
|
||||
if (VramLockedWrite((u8*)si->si_addr) || BM_LockedWrite((u8*)si->si_addr))
|
||||
return;
|
||||
#if FEAT_SHREC == DYNAREC_JIT
|
||||
|
@ -108,12 +99,9 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
|
|||
signal(SIGSEGV, SIG_DFL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
void install_fault_handler (void)
|
||||
void install_fault_handler(void)
|
||||
{
|
||||
#if !defined(TARGET_NO_EXCEPTIONS)
|
||||
struct sigaction act, segv_oact;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_sigaction = fault_handler;
|
||||
|
@ -127,172 +115,14 @@ void install_fault_handler (void)
|
|||
act.sa_sigaction = sigill_handler;
|
||||
sigaction(SIGILL, &act, &segv_oact);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(TARGET_NO_THREADS)
|
||||
|
||||
//Thread class
|
||||
cThread::cThread(ThreadEntryFP* function,void* prm)
|
||||
{
|
||||
Entry=function;
|
||||
param=prm;
|
||||
}
|
||||
|
||||
void cThread::Start()
|
||||
{
|
||||
pthread_create( (pthread_t*)&hThread, NULL, Entry, param);
|
||||
}
|
||||
|
||||
void cThread::WaitToEnd()
|
||||
{
|
||||
pthread_join((pthread_t)hThread,0);
|
||||
}
|
||||
|
||||
//End thread class
|
||||
#endif
|
||||
|
||||
//cResetEvent Calss
|
||||
cResetEvent::cResetEvent(bool State,bool Auto)
|
||||
{
|
||||
//sem_init((sem_t*)hEvent, 0, State?1:0);
|
||||
verify(State==false&&Auto==true);
|
||||
pthread_mutex_init(&mutx, NULL);
|
||||
pthread_cond_init(&cond, NULL);
|
||||
}
|
||||
cResetEvent::~cResetEvent()
|
||||
{
|
||||
//Destroy the event object ?
|
||||
|
||||
}
|
||||
void cResetEvent::Set()//Signal
|
||||
{
|
||||
pthread_mutex_lock( &mutx );
|
||||
state=true;
|
||||
pthread_cond_signal( &cond);
|
||||
pthread_mutex_unlock( &mutx );
|
||||
}
|
||||
void cResetEvent::Reset()//reset
|
||||
{
|
||||
pthread_mutex_lock( &mutx );
|
||||
state=false;
|
||||
pthread_mutex_unlock( &mutx );
|
||||
}
|
||||
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
|
||||
{
|
||||
pthread_mutex_lock( &mutx );
|
||||
if (!state)
|
||||
{
|
||||
struct timespec ts;
|
||||
#if HOST_OS == OS_DARWIN
|
||||
// OSX doesn't have clock_gettime.
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
ts.tv_sec = mts.tv_sec;
|
||||
ts.tv_nsec = mts.tv_nsec;
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
ts.tv_sec += msec / 1000;
|
||||
ts.tv_nsec += (msec % 1000) * 1000000;
|
||||
while (ts.tv_nsec > 1000000000)
|
||||
{
|
||||
ts.tv_nsec -= 1000000000;
|
||||
ts.tv_sec++;
|
||||
}
|
||||
pthread_cond_timedwait( &cond, &mutx, &ts );
|
||||
}
|
||||
bool rc = state;
|
||||
state=false;
|
||||
pthread_mutex_unlock( &mutx );
|
||||
|
||||
return rc;
|
||||
}
|
||||
void cResetEvent::Wait()//Wait for signal , then reset
|
||||
{
|
||||
pthread_mutex_lock( &mutx );
|
||||
if (!state)
|
||||
{
|
||||
pthread_cond_wait( &cond, &mutx );
|
||||
}
|
||||
state=false;
|
||||
pthread_mutex_unlock( &mutx );
|
||||
}
|
||||
|
||||
//End AutoResetEvent
|
||||
#else // !defined(TARGET_NO_EXCEPTIONS)
|
||||
// No exceptions/nvmem dummy handlers.
|
||||
void install_fault_handler(void) {}
|
||||
#endif // !defined(TARGET_NO_EXCEPTIONS)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
void VArray2::LockRegion(u32 offset,u32 size)
|
||||
{
|
||||
#if !defined(TARGET_NO_EXCEPTIONS)
|
||||
u32 inpage=offset & PAGE_MASK;
|
||||
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ );
|
||||
if (rv!=0)
|
||||
{
|
||||
printf("mprotect(%8s,%08X,R) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
|
||||
die("mprotect failed ..\n");
|
||||
}
|
||||
|
||||
#else
|
||||
//printf("VA2: LockRegion\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void print_mem_addr()
|
||||
{
|
||||
FILE *ifp, *ofp;
|
||||
|
||||
char outputFilename[] = "/data/data/com.reicast.emulator/files/mem_alloc.txt";
|
||||
|
||||
ifp = fopen("/proc/self/maps", "r");
|
||||
|
||||
if (ifp == NULL) {
|
||||
fprintf(stderr, "Can't open input file /proc/self/maps!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ofp = fopen(outputFilename, "w");
|
||||
|
||||
if (ofp == NULL) {
|
||||
fprintf(stderr, "Can't open output file %s!\n",
|
||||
outputFilename);
|
||||
#if HOST_OS == OS_LINUX
|
||||
ofp = stderr;
|
||||
#else
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
char line [ 512 ];
|
||||
while (fgets(line, sizeof line, ifp) != NULL) {
|
||||
fprintf(ofp, "%s", line);
|
||||
}
|
||||
|
||||
fclose(ifp);
|
||||
if (ofp != stderr)
|
||||
fclose(ofp);
|
||||
}
|
||||
|
||||
void VArray2::UnLockRegion(u32 offset,u32 size)
|
||||
{
|
||||
#if !defined(TARGET_NO_EXCEPTIONS)
|
||||
u32 inpage=offset & PAGE_MASK;
|
||||
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ | PROT_WRITE);
|
||||
if (rv!=0)
|
||||
{
|
||||
print_mem_addr();
|
||||
printf("mprotect(%8p,%08X,RW) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
|
||||
die("mprotect failed ..\n");
|
||||
}
|
||||
#else
|
||||
//printf("VA2: UnLockRegion\n");
|
||||
#endif
|
||||
}
|
||||
double os_GetSeconds()
|
||||
{
|
||||
timeval a;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
|
||||
// Implementation of the vmem related function for POSIX-like platforms.
|
||||
// There's some minimal amount of platform specific hacks to support
|
||||
// Android and OSX since they are slightly different in some areas.
|
||||
|
||||
// This implements the VLockedMemory interface, as defined in _vmem.h
|
||||
// The implementation allows it to be empty (that is, to not lock memory).
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#ifndef MAP_NOSYNC
|
||||
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
|
||||
#endif
|
||||
|
||||
#ifdef _ANDROID
|
||||
#include <linux/ashmem.h>
|
||||
#ifndef ASHMEM_DEVICE
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
#undef PAGE_MASK
|
||||
#define PAGE_MASK (PAGE_SIZE-1)
|
||||
#else
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_MASK (PAGE_SIZE-1)
|
||||
#endif
|
||||
|
||||
// Android specific ashmem-device stuff for creating shared memory regions
|
||||
int ashmem_create_region(const char *name, size_t size) {
|
||||
int fd = open(ASHMEM_DEVICE, O_RDWR);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif // #ifdef _ANDROID
|
||||
|
||||
void VLockedMemory::LockRegion(unsigned offset, unsigned size_bytes) {
|
||||
size_t inpage = offset & PAGE_MASK;
|
||||
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ)) {
|
||||
die("mprotect failed ..\n");
|
||||
}
|
||||
}
|
||||
|
||||
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size_bytes) {
|
||||
size_t inpage = offset & PAGE_MASK;
|
||||
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ|PROT_WRITE)) {
|
||||
// Add some way to see why it failed? gdb> info proc mappings
|
||||
die("mprotect failed ..\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Allocates memory via a fd on shmem/ahmem or even a file on disk
|
||||
static int allocate_shared_filemem(unsigned size) {
|
||||
int fd = -1;
|
||||
#if defined(_ANDROID)
|
||||
// Use Android's specific shmem stuff.
|
||||
fd = ashmem_create_region(0, size);
|
||||
#else
|
||||
#if HOST_OS != OS_DARWIN
|
||||
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR, S_IREAD | S_IWRITE);
|
||||
shm_unlink("/dcnzorz_mem");
|
||||
#endif
|
||||
|
||||
// if shmem does not work (or using OSX) fallback to a regular file on disk
|
||||
if (fd < 0) {
|
||||
string path = get_writable_data_path("/dcnzorz_mem");
|
||||
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink(path.c_str());
|
||||
}
|
||||
// If we can't open the file, fallback to slow mem.
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
// Finally make the file as big as we need!
|
||||
if (ftruncate(fd, size)) {
|
||||
// Can't get as much memory as needed, fallback.
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
|
||||
// The function supports allocating 512MB or 4GB addr spaces.
|
||||
|
||||
static int shmem_fd = -1, shmem_fd2 = -1;
|
||||
|
||||
// vmem_base_addr points to an address space of 512MB (or 4GB) that can be used for fast memory ops.
|
||||
// In negative offsets of the pointer (up to FPCB size, usually 65/129MB) the context and jump table
|
||||
// can be found. If the platform init returns error, the user is responsible for initializing the
|
||||
// memory using a fallback (that is, regular mallocs and falling back to slow memory JIT).
|
||||
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
|
||||
// Firt let's try to allocate the shm-backed memory
|
||||
shmem_fd = allocate_shared_filemem(RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
|
||||
if (shmem_fd < 0)
|
||||
return MemTypeError;
|
||||
|
||||
// Now try to allocate a contiguous piece of memory.
|
||||
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
|
||||
void *first_ptr = mmap(0, memsize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (!first_ptr) {
|
||||
close(shmem_fd);
|
||||
return MemTypeError;
|
||||
}
|
||||
|
||||
// Align pointer to 64KB too, some Linaro bug (no idea but let's just be safe I guess).
|
||||
uintptr_t ptrint = (uintptr_t)first_ptr;
|
||||
ptrint = (ptrint + 0x10000 - 1) & (~0xffff);
|
||||
*sh4rcb_addr = (void*)ptrint;
|
||||
*vmem_base_addr = (void*)(ptrint + sizeof(Sh4RCB));
|
||||
void *sh4rcb_base_ptr = (void*)(ptrint + FPCB_SIZE);
|
||||
|
||||
// Now map the memory for the SH4 context, do not include FPCB on purpose (paged on demand).
|
||||
mprotect(sh4rcb_base_ptr, sizeof(Sh4RCB) - FPCB_SIZE, PROT_READ | PROT_WRITE);
|
||||
|
||||
return MemType512MB;
|
||||
}
|
||||
|
||||
// Just tries to wipe as much as possible in the relevant area.
|
||||
void vmem_platform_destroy() {
|
||||
munmap(virt_ram_base, 0x20000000);
|
||||
}
|
||||
|
||||
// Resets a chunk of memory by deleting its data and setting its protection back.
|
||||
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
|
||||
// Mark them as non accessible.
|
||||
mprotect(ptr, size_bytes, PROT_NONE);
|
||||
// Tell the kernel to flush'em all (FIXME: perhaps unmap+mmap 'd be better?)
|
||||
madvise(ptr, size_bytes, MADV_DONTNEED);
|
||||
#if defined(MADV_REMOVE)
|
||||
madvise(ptr, size_bytes, MADV_REMOVE);
|
||||
#elif defined(MADV_FREE)
|
||||
madvise(ptr, size_bytes, MADV_FREE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Allocates a bunch of memory (page aligned and page-sized)
|
||||
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
|
||||
verify(!mprotect(address, size_bytes, PROT_READ | PROT_WRITE));
|
||||
}
|
||||
|
||||
// Creates mappings to the underlying file including mirroring sections
|
||||
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
|
||||
for (unsigned i = 0; i < nummaps; i++) {
|
||||
// Ignore unmapped stuff, it is already reserved as PROT_NONE
|
||||
if (!vmem_maps[i].memsize)
|
||||
continue;
|
||||
|
||||
// Calculate the number of mirrors
|
||||
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
|
||||
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
|
||||
int protection = vmem_maps[i].allow_writes ? (PROT_READ | PROT_WRITE) : PROT_READ;
|
||||
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
|
||||
|
||||
for (unsigned j = 0; j < num_mirrors; j++) {
|
||||
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
|
||||
verify(!munmap(&virt_ram_base[offset], vmem_maps[i].memsize));
|
||||
verify(MAP_FAILED != mmap(&virt_ram_base[offset], vmem_maps[i].memsize, protection,
|
||||
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd, vmem_maps[i].memoffset));
|
||||
// ??? (mprotect(rv,size,prot)!=0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepares the code region for JIT operations, thus marking it as RWX
|
||||
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rwx) {
|
||||
// Try to map is as RWX, this fails apparently on OSX (and perhaps other systems?)
|
||||
if (mprotect(code_area, size, PROT_READ | PROT_WRITE | PROT_EXEC)) {
|
||||
// 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
|
||||
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.
|
||||
}
|
||||
|
||||
// Pointer location should be same:
|
||||
*code_area_rwx = code_area;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use two addr spaces: need to remap something twice, therefore use allocate_shared_filemem()
|
||||
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rw, uintptr_t *rx_offset) {
|
||||
shmem_fd2 = allocate_shared_filemem(size);
|
||||
if (shmem_fd2 < 0)
|
||||
return false;
|
||||
|
||||
// Need to unmap the section we are about to use (it might be already unmapped but nevertheless...)
|
||||
munmap(code_area, size);
|
||||
|
||||
// Map the RX bits on the code_area, for proximity, as usual.
|
||||
void *ptr_rx = mmap(code_area, size, PROT_READ | PROT_EXEC,
|
||||
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd2, 0);
|
||||
if (ptr_rx != code_area)
|
||||
return false;
|
||||
|
||||
// Now remap the same memory as RW in some location we don't really care at all.
|
||||
void *ptr_rw = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_NOSYNC, shmem_fd2, 0);
|
||||
|
||||
*code_area_rw = ptr_rw;
|
||||
*rx_offset = (char*)ptr_rx - (char*)ptr_rw;
|
||||
printf("Info: Using NO_RWX mode, rx ptr: %p, rw ptr: %p, offset: %lu\n", ptr_rx, ptr_rw, (unsigned long)*rx_offset);
|
||||
|
||||
return (ptr_rw != MAP_FAILED);
|
||||
}
|
||||
|
||||
// Some OSes restrict cache flushing, cause why not right? :D
|
||||
|
||||
#if HOST_CPU == CPU_ARM64
|
||||
|
||||
// Code borrowed from Dolphin https://github.com/dolphin-emu/dolphin
|
||||
static void Arm64_CacheFlush(void* start, void* end) {
|
||||
if (start == end)
|
||||
return;
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
|
||||
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
|
||||
#else
|
||||
// Don't rely on GCC's __clear_cache implementation, as it caches
|
||||
// icache/dcache cache line sizes, that can vary between cores on
|
||||
// big.LITTLE architectures.
|
||||
u64 addr, ctr_el0;
|
||||
static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
|
||||
size_t isize, dsize;
|
||||
|
||||
__asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
|
||||
isize = 4 << ((ctr_el0 >> 0) & 0xf);
|
||||
dsize = 4 << ((ctr_el0 >> 16) & 0xf);
|
||||
|
||||
// use the global minimum cache line size
|
||||
icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
|
||||
dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
|
||||
|
||||
addr = (u64)start & ~(u64)(dsize - 1);
|
||||
for (; addr < (u64)end; addr += dsize)
|
||||
// use "civac" instead of "cvau", as this is the suggested workaround for
|
||||
// Cortex-A53 errata 819472, 826319, 827319 and 824069.
|
||||
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
|
||||
__asm__ volatile("dsb ish" : : : "memory");
|
||||
|
||||
addr = (u64)start & ~(u64)(isize - 1);
|
||||
for (; addr < (u64)end; addr += isize)
|
||||
__asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
|
||||
|
||||
__asm__ volatile("dsb ish" : : : "memory");
|
||||
__asm__ volatile("isb" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end) {
|
||||
Arm64_CacheFlush(dcache_start, dcache_end);
|
||||
|
||||
// Dont risk it and flush and invalidate icache&dcache for both ranges just in case.
|
||||
if (icache_start != dcache_start)
|
||||
Arm64_CacheFlush(icache_start, icache_end);
|
||||
}
|
||||
|
||||
#endif // #if HOST_CPU == CPU_ARM64
|
||||
|
119
core/nullDC.cpp
119
core/nullDC.cpp
|
@ -22,6 +22,7 @@
|
|||
#include "imgread/common.h"
|
||||
#include "rend/gui.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "input/gamepad_device.h"
|
||||
|
||||
void FlushCache();
|
||||
void LoadCustom();
|
||||
|
@ -96,10 +97,6 @@ s32 plugins_Init()
|
|||
if (s32 rv = libGDR_Init())
|
||||
return rv;
|
||||
#endif
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (!naomi_cart_SelectFile())
|
||||
return rv_serror;
|
||||
#endif
|
||||
|
||||
if (s32 rv = libAICA_Init())
|
||||
return rv;
|
||||
|
@ -137,7 +134,7 @@ void LoadSpecialSettings()
|
|||
safemode_game = false;
|
||||
tr_poly_depth_mask_game = false;
|
||||
extra_depth_game = false;
|
||||
|
||||
|
||||
if (reios_windows_ce)
|
||||
{
|
||||
printf("Enabling Extra depth scaling for Windows CE games\n");
|
||||
|
@ -193,7 +190,7 @@ void LoadSpecialSettings()
|
|||
}
|
||||
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
printf("Game ID is [%s]\n", naomi_game_id);
|
||||
|
||||
|
||||
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
|
||||
{
|
||||
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
|
||||
|
@ -216,12 +213,14 @@ void LoadSpecialSettings()
|
|||
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 2;
|
||||
}
|
||||
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
|
||||
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|
||||
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
|
||||
{
|
||||
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 1;
|
||||
}
|
||||
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
|
||||
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|
||||
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
|
||||
{
|
||||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 3;
|
||||
|
@ -231,9 +230,11 @@ void LoadSpecialSettings()
|
|||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 4;
|
||||
}
|
||||
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
|
||||
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|
||||
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|
||||
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW
|
||||
{
|
||||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
printf("Enabling lightgun setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 5;
|
||||
}
|
||||
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
|
||||
|
@ -259,6 +260,7 @@ void dc_reset()
|
|||
}
|
||||
|
||||
static bool init_done;
|
||||
static bool reset_requested;
|
||||
|
||||
int reicast_init(int argc, char* argv[])
|
||||
{
|
||||
|
@ -312,10 +314,25 @@ int dc_start_game(const char *path)
|
|||
InitSettings();
|
||||
LoadSettings(false);
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
if (DiscSwap())
|
||||
LoadCustom();
|
||||
if (!settings.bios.UseReios)
|
||||
#endif
|
||||
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
|
||||
return -5;
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
if (path == NULL)
|
||||
{
|
||||
// Boot BIOS
|
||||
settings.imgread.LastImage[0] = 0;
|
||||
TermDrive();
|
||||
InitDrive();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DiscSwap())
|
||||
LoadCustom();
|
||||
}
|
||||
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
LoadRomFiles(get_readonly_data_path(DATA_PATH));
|
||||
if (!naomi_cart_SelectFile())
|
||||
return -6;
|
||||
LoadCustom();
|
||||
|
@ -333,7 +350,6 @@ int dc_start_game(const char *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
|
||||
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
|
||||
{
|
||||
#ifdef USE_REIOS
|
||||
|
@ -354,6 +370,11 @@ int dc_start_game(const char *path)
|
|||
if (plugins_Init())
|
||||
return -3;
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (!naomi_cart_SelectFile())
|
||||
return -6;
|
||||
#endif
|
||||
|
||||
LoadCustom();
|
||||
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
|
@ -414,9 +435,18 @@ void* dc_run(void*)
|
|||
Get_Sh4Interpreter(&sh4_cpu);
|
||||
printf("Using Interpreter\n");
|
||||
}
|
||||
sh4_cpu.Run();
|
||||
do {
|
||||
reset_requested = false;
|
||||
|
||||
sh4_cpu.Run();
|
||||
|
||||
SaveRomFiles(get_writable_data_path("/data/"));
|
||||
if (reset_requested)
|
||||
{
|
||||
dc_reset();
|
||||
}
|
||||
} while (reset_requested);
|
||||
|
||||
SaveRomFiles(get_writable_data_path("/data/"));
|
||||
TermAudio();
|
||||
|
||||
return NULL;
|
||||
|
@ -444,6 +474,13 @@ void dc_stop()
|
|||
emu_thread.WaitToEnd();
|
||||
}
|
||||
|
||||
// Called on the emulator thread for soft reset
|
||||
void dc_request_reset()
|
||||
{
|
||||
reset_requested = true;
|
||||
sh4_cpu.Stop();
|
||||
}
|
||||
|
||||
void dc_exit()
|
||||
{
|
||||
dc_stop();
|
||||
|
@ -452,7 +489,6 @@ void dc_exit()
|
|||
|
||||
void InitSettings()
|
||||
{
|
||||
settings.dreamcast.RTC = GetRTC_now();
|
||||
settings.dynarec.Enable = true;
|
||||
settings.dynarec.idleskip = true;
|
||||
settings.dynarec.unstable_opt = false;
|
||||
|
@ -462,9 +498,11 @@ void InitSettings()
|
|||
settings.dreamcast.broadcast = 4; // default
|
||||
settings.dreamcast.language = 6; // default
|
||||
settings.dreamcast.FullMMU = false;
|
||||
settings.dynarec.SmcCheckLevel = FullCheck;
|
||||
settings.aica.LimitFPS = true;
|
||||
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
|
||||
settings.aica.NoSound = false;
|
||||
settings.audio.backend = "auto";
|
||||
settings.rend.UseMipmaps = true;
|
||||
settings.rend.WideScreen = false;
|
||||
settings.rend.ShowFPS = false;
|
||||
|
@ -479,6 +517,10 @@ void InitSettings()
|
|||
settings.rend.CustomTextures = false;
|
||||
settings.rend.DumpTextures = false;
|
||||
settings.rend.ScreenScaling = 100;
|
||||
settings.rend.ScreenStretching = 100;
|
||||
settings.rend.Fog = true;
|
||||
settings.rend.FloatVMUs = false;
|
||||
settings.rend.Rotate90 = false;
|
||||
|
||||
settings.pvr.ta_skip = 0;
|
||||
settings.pvr.rend = 0;
|
||||
|
@ -525,11 +567,13 @@ void LoadSettings(bool game_specific)
|
|||
{
|
||||
const char *config_section = game_specific ? cfgGetGameId() : "config";
|
||||
const char *input_section = game_specific ? cfgGetGameId() : "input";
|
||||
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
|
||||
|
||||
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
|
||||
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
|
||||
settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
|
||||
settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode);
|
||||
settings.dynarec.SmcCheckLevel = (SmcCheckEnum)cfgLoadInt(config_section, "Dynarec.SmcCheckLevel", settings.dynarec.SmcCheckLevel);
|
||||
//disable_nvmem can't be loaded, because nvmem init is before cfg load
|
||||
settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
|
||||
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
|
||||
|
@ -539,6 +583,7 @@ void LoadSettings(bool game_specific)
|
|||
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
|
||||
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
|
||||
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
|
||||
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
|
||||
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
|
||||
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
|
||||
|
@ -560,6 +605,10 @@ void LoadSettings(bool game_specific)
|
|||
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
|
||||
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
|
||||
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
|
||||
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
|
||||
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
|
||||
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
|
||||
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
|
||||
|
||||
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
|
||||
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
|
||||
|
@ -624,9 +673,9 @@ void LoadSettings(bool game_specific)
|
|||
}
|
||||
/*
|
||||
//make sure values are valid
|
||||
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);
|
||||
settings.dreamcast.region = min(max(settings.dreamcast.region, 0),3);
|
||||
settings.dreamcast.broadcast= min(max(settings.dreamcast.broadcast,0),4);
|
||||
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);
|
||||
settings.dreamcast.region = min(max(settings.dreamcast.region, 0),3);
|
||||
settings.dreamcast.broadcast = min(max(settings.dreamcast.broadcast,0),4);
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -665,10 +714,33 @@ void SaveSettings()
|
|||
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
|
||||
if (!safemode_game || !settings.dynarec.safemode)
|
||||
cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode);
|
||||
cfgSaveInt("config", "Dynarec.SmcCheckLevel", (int)settings.dynarec.SmcCheckLevel);
|
||||
|
||||
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
|
||||
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
|
||||
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
|
||||
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
|
||||
|
||||
// Write backend specific settings
|
||||
// std::map<std::string, std::map<std::string, std::string>>
|
||||
for (std::map<std::string, std::map<std::string, std::string>>::iterator it = settings.audio.options.begin(); it != settings.audio.options.end(); ++it)
|
||||
{
|
||||
|
||||
std::pair<std::string, std::map<std::string, std::string>> p = (std::pair<std::string, std::map<std::string, std::string>>)*it;
|
||||
std::string section = p.first;
|
||||
std::map<std::string, std::string> options = p.second;
|
||||
|
||||
for (std::map<std::string, std::string>::iterator it2 = options.begin(); it2 != options.end(); ++it2)
|
||||
{
|
||||
std::pair<std::string, std::string> p2 = (std::pair<std::string, std::string>)*it2;
|
||||
std::string key = p2.first;
|
||||
std::string val = p2.second;
|
||||
|
||||
cfgSaveStr(section.c_str(), key.c_str(), val.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
|
||||
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
|
||||
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
|
||||
|
@ -681,6 +753,10 @@ void SaveSettings()
|
|||
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
|
||||
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
|
||||
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
|
||||
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
|
||||
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
|
||||
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
|
||||
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
|
||||
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
|
||||
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);
|
||||
|
||||
|
@ -709,6 +785,9 @@ void SaveSettings()
|
|||
paths += path;
|
||||
}
|
||||
cfgSaveStr("config", "Dreamcast.ContentPath", paths.c_str());
|
||||
|
||||
GamepadDevice::SaveMaplePorts();
|
||||
|
||||
#ifdef _ANDROID
|
||||
void SaveAndroidSettings();
|
||||
SaveAndroidSettings();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "oslib/audiobackend_alsa.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if USE_ALSA
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
static snd_pcm_t *handle;
|
||||
static bool pcm_blocking = true;
|
||||
|
@ -10,29 +11,63 @@ static snd_pcm_uframes_t period_size;
|
|||
// We're making these functions static - there's no need to pollute the global namespace
|
||||
static void alsa_init()
|
||||
{
|
||||
|
||||
long loops;
|
||||
int size;
|
||||
|
||||
snd_pcm_hw_params_t *params;
|
||||
unsigned int val;
|
||||
int dir=-1;
|
||||
|
||||
/* Open PCM device for playback. */
|
||||
int rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
string device = cfgLoadStr("alsa", "device", "");
|
||||
|
||||
if (rc<0)
|
||||
rc = snd_pcm_open(&handle, "plughw:0,0,0", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
int rc = -1;
|
||||
if (device == "" || device == "auto")
|
||||
{
|
||||
printf("ALSA: trying to determine audio device\n");
|
||||
|
||||
if (rc<0)
|
||||
rc = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
// trying default device
|
||||
device = "default";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
// "default" didn't work, try first device
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:0,0,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:0,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// first didn't work, try second
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:1,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
// try pulse audio backend
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "pulse";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
printf("ALSA: unable to automatically determine audio device.\n");
|
||||
}
|
||||
else {
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "unable to open PCM device: %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: unable to open PCM device %s: %s\n", device.c_str(), snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("ALSA: Successfully initialized \"%s\"\n", device.c_str());
|
||||
|
||||
/* Allocate a hardware parameters object. */
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
|
@ -40,7 +75,7 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_any(handle, params);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -50,7 +85,7 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -58,7 +93,7 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -66,7 +101,7 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_set_channels(handle, params, 2);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -75,7 +110,7 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -84,26 +119,31 @@ static void alsa_init()
|
|||
rc=snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, &dir);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ALSA: period size set to %ld\n", period_size);
|
||||
}
|
||||
|
||||
buffer_size = (44100 * 100 /* settings.omx.Audio_Latency */ / 1000 / period_size + 1) * period_size;
|
||||
rc=snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ALSA: buffer size set to %ld\n", buffer_size);
|
||||
}
|
||||
|
||||
/* Write the parameters to the driver */
|
||||
rc = snd_pcm_hw_params(handle, params);
|
||||
if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "Unable to set hw parameters: %s\n", snd_strerror(rc));
|
||||
fprintf(stderr, "ALSA: Unable to set hw parameters: %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -153,11 +193,84 @@ static void alsa_term()
|
|||
snd_pcm_close(handle);
|
||||
}
|
||||
|
||||
audiobackend_t audiobackend_alsa = {
|
||||
std::vector<std::string> alsa_get_devicelist()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
char **hints;
|
||||
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
|
||||
|
||||
// Error initializing ALSA
|
||||
if (err != 0)
|
||||
return result;
|
||||
|
||||
// special value to automatically detect on initialization
|
||||
result.push_back("auto");
|
||||
|
||||
char** n = hints;
|
||||
while (*n != NULL)
|
||||
{
|
||||
// Get the type (NULL/Input/Output)
|
||||
char *type = snd_device_name_get_hint(*n, "IOID");
|
||||
char *name = snd_device_name_get_hint(*n, "NAME");
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
// We only want output or special devices (like "default" or "pulse")
|
||||
// TODO Only those with type == NULL?
|
||||
if (type == NULL || strcmp(type, "Output") == 0)
|
||||
{
|
||||
// TODO Check if device works (however we need to hash the resulting list then)
|
||||
/*snd_pcm_t *handle;
|
||||
int rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
result.push_back(name);
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
*/
|
||||
|
||||
result.push_back(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (type != NULL)
|
||||
free(type);
|
||||
|
||||
if (name != NULL)
|
||||
free(name);
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
snd_device_name_free_hint((void**)hints);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static audio_option_t* alsa_audio_options(int* option_count)
|
||||
{
|
||||
*option_count = 1;
|
||||
static audio_option_t result[1];
|
||||
|
||||
result[0].cfg_name = "device";
|
||||
result[0].caption = "Device";
|
||||
result[0].type = list;
|
||||
result[0].list_callback = alsa_get_devicelist;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static audiobackend_t audiobackend_alsa = {
|
||||
"alsa", // Slug
|
||||
"Advanced Linux Sound Architecture", // Name
|
||||
&alsa_init,
|
||||
&alsa_push,
|
||||
&alsa_term
|
||||
&alsa_term,
|
||||
&alsa_audio_options
|
||||
};
|
||||
|
||||
static bool alsa = RegisterAudioBackend(&audiobackend_alsa);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_alsa;
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_android;
|
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
Simple Core Audio backend for osx (and maybe ios?)
|
||||
Based off various audio core samples and dolphin's code
|
||||
|
||||
|
||||
This is part of the Reicast project, please consult the
|
||||
LICENSE file for licensing & related information
|
||||
|
||||
|
||||
This could do with some locking logic to avoid
|
||||
race conditions, and some variable length buffer
|
||||
logic to support chunk sizes other than 512 bytes
|
||||
|
||||
|
||||
It does work on my macmini though
|
||||
*/
|
||||
|
||||
#include "oslib/audiobackend_coreaudio.h"
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
#include <atomic>
|
||||
|
@ -28,7 +28,7 @@ static u8 samples_temp[BUFSIZE];
|
|||
|
||||
static std::atomic<int> samples_wptr;
|
||||
static std::atomic<int> samples_rptr;
|
||||
static cResetEvent bufferEmpty(false, true);
|
||||
static cResetEvent bufferEmpty;
|
||||
|
||||
static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* ts,
|
||||
UInt32 bus, UInt32 frames, AudioBufferList* abl)
|
||||
|
@ -49,9 +49,9 @@ static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags,
|
|||
samples_rptr = (samples_rptr + buf_size) % BUFSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ static void coreaudio_init()
|
|||
AudioStreamBasicDescription format;
|
||||
AudioComponentDescription desc;
|
||||
AudioComponent component;
|
||||
|
||||
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
#if !defined(TARGET_IPHONE)
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
|
@ -75,12 +75,12 @@ static void coreaudio_init()
|
|||
desc.componentFlagsMask = 0;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
component = AudioComponentFindNext(nullptr, &desc);
|
||||
|
||||
|
||||
verify(component != nullptr);
|
||||
|
||||
|
||||
err = AudioComponentInstanceNew(component, &audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
FillOutASBDForLPCM(format, 44100,
|
||||
2, 16, 16, false, false, false);
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
|
@ -88,7 +88,7 @@ static void coreaudio_init()
|
|||
kAudioUnitScope_Input, 0, &format,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
callback_struct.inputProc = coreaudio_callback;
|
||||
callback_struct.inputProcRefCon = 0;
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
|
@ -96,24 +96,24 @@ static void coreaudio_init()
|
|||
kAudioUnitScope_Input, 0, &callback_struct,
|
||||
sizeof callback_struct);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
/*
|
||||
err = AudioUnitSetParameter(audioUnit,
|
||||
kHALOutputParam_Volume,
|
||||
kAudioUnitParameterFlag_Output, 0,
|
||||
1, 0);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
|
||||
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioOutputUnitStart(audioUnit);
|
||||
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
}
|
||||
|
||||
|
@ -134,23 +134,23 @@ static u32 coreaudio_push(void* frame, u32 samples, bool wait)
|
|||
samples_wptr = (samples_wptr + byte_size) % BUFSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void coreaudio_term()
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
|
||||
err = AudioOutputUnitStop(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioUnitUninitialize(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioComponentInstanceDispose(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,10 @@ audiobackend_t audiobackend_coreaudio = {
|
|||
"Core Audio", // Name
|
||||
&coreaudio_init,
|
||||
&coreaudio_push,
|
||||
&coreaudio_term
|
||||
&coreaudio_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool core = RegisterAudioBackend(&audiobackend_coreaudio);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_coreaudio;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_directsound.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
#include "oslib.h"
|
||||
#include <initguid.h>
|
||||
|
@ -19,31 +19,31 @@ static void directsound_init()
|
|||
verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(),DSSCL_PRIORITY));
|
||||
IDirectSoundBuffer* buffer_;
|
||||
|
||||
WAVEFORMATEX wfx;
|
||||
DSBUFFERDESC desc;
|
||||
WAVEFORMATEX wfx;
|
||||
DSBUFFERDESC desc;
|
||||
|
||||
// Set up WAV format structure.
|
||||
// Set up WAV format structure.
|
||||
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.nBlockAlign = 4;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 16;
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.nBlockAlign = 4;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 16;
|
||||
|
||||
// Set up DSBUFFERDESC structure.
|
||||
// Set up DSBUFFERDESC structure.
|
||||
|
||||
ds_ring_size=8192*wfx.nBlockAlign;
|
||||
|
||||
memset(&desc, 0, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||||
|
||||
desc.dwBufferBytes = ds_ring_size;
|
||||
desc.lpwfxFormat = &wfx;
|
||||
memset(&desc, 0, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||||
|
||||
desc.dwBufferBytes = ds_ring_size;
|
||||
desc.lpwfxFormat = &wfx;
|
||||
|
||||
|
||||
|
||||
|
||||
if (settings.aica.HW_mixing==0)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ static void directsound_init()
|
|||
|
||||
//Play the buffer !
|
||||
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,7 +159,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
|
|||
wait &= w;
|
||||
*/
|
||||
int ffs=1;
|
||||
|
||||
|
||||
/*
|
||||
while (directsound_IsAudioBufferedLots() && wait)
|
||||
if (ffs == 0)
|
||||
|
@ -175,7 +175,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
|
|||
static void directsound_term()
|
||||
{
|
||||
buffer->Stop();
|
||||
|
||||
|
||||
buffer->Release();
|
||||
dsound->Release();
|
||||
}
|
||||
|
@ -185,6 +185,9 @@ audiobackend_t audiobackend_directsound = {
|
|||
"Microsoft DirectSound", // Name
|
||||
&directsound_init,
|
||||
&directsound_push,
|
||||
&directsound_term
|
||||
&directsound_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool ds = RegisterAudioBackend(&audiobackend_directsound);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_directsound;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_libao.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_LIBAO
|
||||
|
||||
#include <ao/ao.h>
|
||||
|
@ -10,12 +10,12 @@ static void libao_init()
|
|||
{
|
||||
ao_initialize();
|
||||
memset(&aoformat, 0, sizeof(aoformat));
|
||||
|
||||
|
||||
aoformat.bits = 16;
|
||||
aoformat.channels = 2;
|
||||
aoformat.rate = 44100;
|
||||
aoformat.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
|
||||
aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output
|
||||
if (!aodevice)
|
||||
aodevice = ao_open_live(ao_driver_id("null"), &aoformat, NULL);
|
||||
|
@ -23,13 +23,13 @@ static void libao_init()
|
|||
|
||||
static u32 libao_push(void* frame, u32 samples, bool wait)
|
||||
{
|
||||
if (aodevice)
|
||||
if (aodevice)
|
||||
ao_play(aodevice, (char*)frame, samples * 4);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void libao_term()
|
||||
static void libao_term()
|
||||
{
|
||||
if (aodevice)
|
||||
{
|
||||
|
@ -43,7 +43,9 @@ audiobackend_t audiobackend_libao = {
|
|||
"libao", // Name
|
||||
&libao_init,
|
||||
&libao_push,
|
||||
&libao_term
|
||||
&libao_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool ao = RegisterAudioBackend(&audiobackend_libao);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_libao;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_omx.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if USE_OMX
|
||||
|
||||
#include <IL/OMX_Broadcom.h>
|
||||
|
@ -313,7 +313,9 @@ audiobackend_t audiobackend_omx = {
|
|||
"OpenMAX IL", // Name
|
||||
&omx_init,
|
||||
&omx_push,
|
||||
&omx_term
|
||||
&omx_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool omx = RegisterAudioBackend(&audiobackend_omx);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_omx;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_oss.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_OSS
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
@ -48,7 +48,9 @@ audiobackend_t audiobackend_oss = {
|
|||
"Open Sound System", // Name
|
||||
&oss_init,
|
||||
&oss_push,
|
||||
&oss_term
|
||||
&oss_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool oss = RegisterAudioBackend(&audiobackend_oss);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_oss;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_pulseaudio.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_PULSEAUDIO
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
@ -43,6 +43,9 @@ audiobackend_t audiobackend_pulseaudio = {
|
|||
"PulseAudio", // Name
|
||||
&pulseaudio_init,
|
||||
&pulseaudio_push,
|
||||
&pulseaudio_term
|
||||
&pulseaudio_term,
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool pulse = RegisterAudioBackend(&audiobackend_pulseaudio);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_pulseaudio;
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
#if defined(USE_SDL_AUDIO)
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include "oslib/audiostream.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
static SDL_AudioDeviceID audiodev;
|
||||
static bool needs_resampling;
|
||||
static cResetEvent read_wait;
|
||||
static cMutex stream_mutex;
|
||||
static struct {
|
||||
uint32_t prevs;
|
||||
uint32_t sample_buffer[2048];
|
||||
} audiobuf;
|
||||
static unsigned sample_count = 0;
|
||||
|
||||
// To easily access samples.
|
||||
union Sample { int16_t s[2]; uint32_t l; };
|
||||
|
||||
static float InterpolateCatmull4pt3oX(float x0, float x1, float x2, float x3, float t) {
|
||||
return 0.45 * ((2 * x1) + t * ((-x0 + x2) + t * ((2 * x0 - 5 * x1 + 4 * x2 - x3) + t * (-x0 + 3 * x1 - 3 * x2 + x3))));
|
||||
}
|
||||
|
||||
static void sdl2_audiocb(void* userdata, Uint8* stream, int len) {
|
||||
stream_mutex.Lock();
|
||||
// Wait until there's enough samples to feed the kraken
|
||||
unsigned oslen = len / sizeof(uint32_t);
|
||||
unsigned islen = needs_resampling ? oslen * 16 / 17 : oslen;
|
||||
unsigned minlen = needs_resampling ? islen + 2 : islen; // Resampler looks ahead by 2 samples.
|
||||
|
||||
if (sample_count < minlen) {
|
||||
// No data, just output a bit of silence for the underrun
|
||||
memset(stream, 0, len);
|
||||
stream_mutex.Unlock();
|
||||
read_wait.Set();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!needs_resampling) {
|
||||
// Just copy bytes for this case.
|
||||
memcpy(stream, &audiobuf.sample_buffer[0], len);
|
||||
}
|
||||
else {
|
||||
// 44.1KHz to 48KHz (actually 46.86KHz) resampling
|
||||
uint32_t *outbuf = (uint32_t*)stream;
|
||||
const float ra = 1.0f / 17;
|
||||
Sample *sbuf = (Sample*)&audiobuf.sample_buffer[0]; // [-1] stores the previous iteration last sample output
|
||||
for (int i = 0; i < islen/16; i++) {
|
||||
*outbuf++ = sbuf[i*16+ 0].l; // First sample stays at the same location.
|
||||
for (int k = 1; k < 17; k++) {
|
||||
Sample r;
|
||||
// Note we access offset -1 on first iteration, as to access prevs
|
||||
r.s[0] = InterpolateCatmull4pt3oX(sbuf[i*16+k-2].s[0], sbuf[i*16+k-1].s[0], sbuf[i*16+k].s[0], sbuf[i*16+k+1].s[0], 1 - ra*k);
|
||||
r.s[1] = InterpolateCatmull4pt3oX(sbuf[i*16+k-2].s[1], sbuf[i*16+k-1].s[1], sbuf[i*16+k].s[1], sbuf[i*16+k+1].s[1], 1 - ra*k);
|
||||
*outbuf++ = r.l;
|
||||
}
|
||||
}
|
||||
audiobuf.prevs = audiobuf.sample_buffer[islen-1];
|
||||
}
|
||||
|
||||
// Move samples in the buffer and consume them
|
||||
memmove(&audiobuf.sample_buffer[0], &audiobuf.sample_buffer[islen], (sample_count-islen)*sizeof(uint32_t));
|
||||
sample_count -= islen;
|
||||
|
||||
stream_mutex.Unlock();
|
||||
read_wait.Set();
|
||||
}
|
||||
|
||||
static void sdl2_audio_init() {
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO))
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
// Support 44.1KHz (native) but also upsampling to 48KHz
|
||||
SDL_AudioSpec wav_spec, out_spec;
|
||||
memset(&wav_spec, 0, sizeof(wav_spec));
|
||||
wav_spec.freq = 44100;
|
||||
wav_spec.format = AUDIO_S16;
|
||||
wav_spec.channels = 2;
|
||||
wav_spec.samples = 1024; // Must be power of two
|
||||
wav_spec.callback = sdl2_audiocb;
|
||||
|
||||
// Try 44.1KHz which should be faster since it's native.
|
||||
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
|
||||
if (!audiodev) {
|
||||
needs_resampling = true;
|
||||
wav_spec.freq = 48000;
|
||||
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
|
||||
verify(audiodev);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 sdl2_audio_push(void* frame, u32 samples, bool wait) {
|
||||
// Unpause the device shall it be paused.
|
||||
if (SDL_GetAudioDeviceStatus(audiodev) != SDL_AUDIO_PLAYING)
|
||||
SDL_PauseAudioDevice(audiodev, 0);
|
||||
|
||||
// If wait, then wait for the buffer to be smaller than a certain size.
|
||||
stream_mutex.Lock();
|
||||
if (wait) {
|
||||
while (sample_count + samples > sizeof(audiobuf.sample_buffer)/sizeof(audiobuf.sample_buffer[0])) {
|
||||
stream_mutex.Unlock();
|
||||
read_wait.Wait();
|
||||
read_wait.Reset();
|
||||
stream_mutex.Lock();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy as many samples as possible, drop any remaining (this should not happen usually)
|
||||
unsigned free_samples = sizeof(audiobuf.sample_buffer) / sizeof(audiobuf.sample_buffer[0]) - sample_count;
|
||||
unsigned tocopy = samples < free_samples ? samples : free_samples;
|
||||
memcpy(&audiobuf.sample_buffer[sample_count], frame, tocopy * sizeof(uint32_t));
|
||||
sample_count += tocopy;
|
||||
stream_mutex.Unlock();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sdl2_audio_term() {
|
||||
// Stop audio playback.
|
||||
SDL_PauseAudioDevice(audiodev, 1);
|
||||
read_wait.Set();
|
||||
}
|
||||
|
||||
audiobackend_t audiobackend_sdl2audio = {
|
||||
"sdl2", // Slug
|
||||
"Simple DirectMedia Layer 2 Audio", // Name
|
||||
&sdl2_audio_init,
|
||||
&sdl2_audio_push,
|
||||
&sdl2_audio_term
|
||||
};
|
||||
|
||||
static bool sdl2audiobe = RegisterAudioBackend(&audiobackend_sdl2audio);
|
||||
|
||||
#endif
|
||||
|
|
@ -2,14 +2,6 @@
|
|||
#include "cfg/cfg.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "audiostream.h"
|
||||
#include "oslib/audiobackend_directsound.h"
|
||||
#include "oslib/audiobackend_android.h"
|
||||
#include "oslib/audiobackend_alsa.h"
|
||||
#include "oslib/audiobackend_oss.h"
|
||||
#include "oslib/audiobackend_pulseaudio.h"
|
||||
#include "oslib/audiobackend_coreaudio.h"
|
||||
#include "oslib/audiobackend_omx.h"
|
||||
#include "oslib/audiobackend_libao.h"
|
||||
|
||||
struct SoundFrame { s16 l;s16 r; };
|
||||
#define SAMPLE_COUNT 512
|
||||
|
@ -25,16 +17,27 @@ u32 gen_samples=0;
|
|||
|
||||
double time_diff = 128/44100.0;
|
||||
double time_last;
|
||||
|
||||
#ifdef LOG_SOUND
|
||||
// TODO Only works on Windows!
|
||||
WaveWriter rawout("d:\\aica_out.wav");
|
||||
#endif
|
||||
|
||||
static bool audiobackends_registered = false;
|
||||
static unsigned int audiobackends_num_max = 1;
|
||||
static unsigned int audiobackends_num_registered = 0;
|
||||
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
||||
static audiobackend_t **audiobackends = NULL;
|
||||
static audiobackend_t *audiobackend_current = NULL;
|
||||
|
||||
u32 GetAudioBackendCount()
|
||||
{
|
||||
return audiobackends_num_registered;
|
||||
}
|
||||
|
||||
audiobackend_t* GetAudioBackend(int num)
|
||||
{
|
||||
return audiobackends[num];
|
||||
}
|
||||
|
||||
bool RegisterAudioBackend(audiobackend_t *backend)
|
||||
{
|
||||
/* This function announces the availability of an audio backend to reicast. */
|
||||
|
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
|||
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (backend->slug == "auto" || backend->slug == "none") {
|
||||
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// First call to RegisterAudioBackend(), create the backend structure;
|
||||
if (audiobackends == NULL)
|
||||
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
||||
|
||||
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
|
||||
if (audiobackends_num_registered == audiobackends_num_max)
|
||||
{
|
||||
|
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
|||
}
|
||||
audiobackends = new_ptr;
|
||||
}
|
||||
|
||||
audiobackends[audiobackends_num_registered] = backend;
|
||||
audiobackends_num_registered++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegisterAllAudioBackends() {
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
RegisterAudioBackend(&audiobackend_directsound);
|
||||
#endif
|
||||
#if ANDROID
|
||||
RegisterAudioBackend(&audiobackend_android);
|
||||
#endif
|
||||
#if USE_OMX
|
||||
RegisterAudioBackend(&audiobackend_omx);
|
||||
#endif
|
||||
#if USE_ALSA
|
||||
RegisterAudioBackend(&audiobackend_alsa);
|
||||
#endif
|
||||
#if USE_OSS
|
||||
RegisterAudioBackend(&audiobackend_oss);
|
||||
#endif
|
||||
#if USE_PULSEAUDIO
|
||||
RegisterAudioBackend(&audiobackend_pulseaudio);
|
||||
#endif
|
||||
#if USE_LIBAO
|
||||
RegisterAudioBackend(&audiobackend_libao);
|
||||
#endif
|
||||
#if HOST_OS == OS_DARWIN
|
||||
RegisterAudioBackend(&audiobackend_coreaudio);
|
||||
#endif
|
||||
audiobackends_registered = true;
|
||||
}
|
||||
|
||||
static audiobackend_t* GetAudioBackend(std::string slug)
|
||||
audiobackend_t* GetAudioBackend(std::string slug)
|
||||
{
|
||||
if (slug == "none")
|
||||
{
|
||||
printf("WARNING: Audio backend set to \"none\"!\n");
|
||||
}
|
||||
else if(audiobackends_num_registered > 0)
|
||||
else if (audiobackends_num_registered > 0)
|
||||
{
|
||||
if (slug == "auto")
|
||||
{
|
||||
|
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
u32 PushAudio(void* frame, u32 amt, bool wait) {
|
||||
u32 PushAudio(void* frame, u32 amt, bool wait)
|
||||
{
|
||||
if (audiobackend_current != NULL) {
|
||||
return audiobackend_current->push(frame, amt, wait);
|
||||
}
|
||||
|
@ -151,11 +134,13 @@ u32 asRingUsedCount()
|
|||
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
|
||||
//return sz<0?sz+RingBufferSampleCount:sz;
|
||||
}
|
||||
|
||||
u32 asRingFreeCount()
|
||||
{
|
||||
return RingBufferSampleCount-asRingUsedCount();
|
||||
}
|
||||
|
||||
extern double mspdf;
|
||||
void WriteSample(s16 r, s16 l)
|
||||
{
|
||||
const u32 ptr=(WritePtr+1)%RingBufferSampleCount;
|
||||
|
@ -165,7 +150,30 @@ void WriteSample(s16 r, s16 l)
|
|||
|
||||
if (WritePtr==(SAMPLE_COUNT-1))
|
||||
{
|
||||
PushAudio(RingBuffer,SAMPLE_COUNT,settings.aica.LimitFPS);
|
||||
bool do_wait = settings.aica.LimitFPS && (mspdf <= 11);
|
||||
|
||||
PushAudio(RingBuffer,SAMPLE_COUNT, do_wait);
|
||||
}
|
||||
}
|
||||
|
||||
static bool backends_sorted = false;
|
||||
void SortAudioBackends()
|
||||
{
|
||||
if (backends_sorted)
|
||||
return;
|
||||
|
||||
// Sort backends by slug
|
||||
for (int n = audiobackends_num_registered; n > 0; n--)
|
||||
{
|
||||
for (int i = 0; i < n-1; i++)
|
||||
{
|
||||
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
|
||||
{
|
||||
audiobackend_t* swap = audiobackends[i];
|
||||
audiobackends[i] = audiobackends[i+1];
|
||||
audiobackends[i+1] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,26 +184,24 @@ void InitAudio()
|
|||
return;
|
||||
}
|
||||
|
||||
cfgSaveInt("audio","disable",0);
|
||||
|
||||
if (!audiobackends_registered) {
|
||||
//FIXME: There might some nicer way to do this.
|
||||
RegisterAllAudioBackends();
|
||||
}
|
||||
cfgSaveInt("audio", "disable", 0);
|
||||
|
||||
if (audiobackend_current != NULL) {
|
||||
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
|
||||
SortAudioBackends();
|
||||
|
||||
string audiobackend_slug = settings.audio.backend;
|
||||
audiobackend_current = GetAudioBackend(audiobackend_slug);
|
||||
if (audiobackend_current == NULL) {
|
||||
printf("WARNING: Running without audio!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
audiobackend_current->init();
|
||||
audiobackend_current->init();
|
||||
}
|
||||
|
||||
void TermAudio()
|
||||
|
@ -204,5 +210,5 @@ void TermAudio()
|
|||
audiobackend_current->term();
|
||||
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
audiobackend_current = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include <tuple>
|
||||
|
||||
//Get used size in the ring buffer
|
||||
u32 asRingUsedCount();
|
||||
|
@ -10,6 +11,29 @@ u32 asRingFreeCount();
|
|||
bool asRingRead(u8* dst,u32 count=0);
|
||||
void UpdateBuff(u8* pos);
|
||||
|
||||
typedef std::vector<std::string> (*audio_option_callback_t)();
|
||||
enum audio_option_type
|
||||
{
|
||||
integer = 0
|
||||
, checkbox = 1
|
||||
, list = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
std::string cfg_name;
|
||||
std::string caption;
|
||||
audio_option_type type;
|
||||
|
||||
// type int_value (spin edit)
|
||||
int min_value;
|
||||
int max_value;
|
||||
|
||||
// type list edit (string/char*)
|
||||
audio_option_callback_t list_callback;
|
||||
} audio_option_t;
|
||||
|
||||
typedef audio_option_t* (*audio_options_func_t)(int* option_count);
|
||||
|
||||
typedef void (*audio_backend_init_func_t)();
|
||||
typedef u32 (*audio_backend_push_func_t)(void*, u32, bool);
|
||||
typedef void (*audio_backend_term_func_t)();
|
||||
|
@ -19,8 +43,14 @@ typedef struct {
|
|||
audio_backend_init_func_t init;
|
||||
audio_backend_push_func_t push;
|
||||
audio_backend_term_func_t term;
|
||||
audio_options_func_t get_options;
|
||||
} audiobackend_t;
|
||||
extern bool RegisterAudioBackend(audiobackend_t* backend);
|
||||
extern void InitAudio();
|
||||
extern u32 PushAudio(void* frame, u32 amt, bool wait);
|
||||
extern void TermAudio();
|
||||
|
||||
u32 GetAudioBackendCount();
|
||||
void SortAudioBackends();
|
||||
audiobackend_t* GetAudioBackend(int num);
|
||||
audiobackend_t* GetAudioBackend(std::string slug);
|
||||
|
|
|
@ -58,6 +58,7 @@ bkpt #0
|
|||
bkpt
|
||||
#endif
|
||||
ubfx r0,r3,#5,#19 @ get vram offset
|
||||
@ should be only 18 bits for 8MB VRAM but it wraps around on dc
|
||||
add r3,r1,#0x04000000 @ get vram ptr from r1, part 1
|
||||
add r3,#512 @ get ram ptr from r1, part 2
|
||||
add r3,r0,lsl #5 @ ram + offset
|
||||
|
@ -180,6 +181,7 @@ CSYM(no_update): @ next_pc _MUST_ be on r4 *R4 NOT R0 anymore*
|
|||
#if RAM_SIZE_MAX == 33554432
|
||||
sub r2,r8,#0x4100000
|
||||
ubfx r1,r4,#1,#24 @ 24+1 bits: 32 MB
|
||||
@ RAM wraps around so if actual RAM size is 16MB, we won't overflow
|
||||
#elif RAM_SIZE_MAX == 16777216
|
||||
sub r2,r8,#0x2100000
|
||||
ubfx r1,r4,#1,#23 @ 23+1 bits: 16 MB
|
||||
|
@ -241,7 +243,13 @@ HIDDEN(arm_dispatch)
|
|||
CSYM(arm_dispatch):
|
||||
ldrd r0,r1,[r8,#184] @load: Next PC, interrupt
|
||||
|
||||
#if ARAM_SIZE == 2*1024*1024
|
||||
ubfx r2,r0,#2,#19 @ assuming 2 MB address space max (21 bits)
|
||||
#elif ARAM_SIZE == 8*1024*1024
|
||||
ubfx r2,r0,#2,#21 @ assuming 8 MB address space max (23 bits)
|
||||
#else
|
||||
#error Unsupported AICA RAM size
|
||||
#endif
|
||||
cmp r1,#0
|
||||
bne arm_dofiq
|
||||
|
||||
|
|
|
@ -2082,7 +2082,7 @@ __default:
|
|||
}
|
||||
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
|
||||
{
|
||||
//printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
|
||||
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR();
|
||||
|
@ -2114,39 +2114,68 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
|
|||
reg.OpBegin(&block->oplist[0],0);
|
||||
|
||||
//scheduler
|
||||
if (force_checks)
|
||||
{
|
||||
s32 sz = block->sh4_code_size;
|
||||
u32 addr = block->addr;
|
||||
MOV32(r0,addr);
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
break;
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz > 2)
|
||||
case FastCheck: {
|
||||
MOV32(r0,block->addr);
|
||||
u32* ptr=(u32*)GetMemPtr(block->addr,4);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
u32* ptr=(u32*)GetMemPtr(addr,4);
|
||||
MOV32(r2,(u32)ptr);
|
||||
LDR(r2,r2,0);
|
||||
MOV32(r1,*ptr);
|
||||
CMP(r1,r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
addr += 4;
|
||||
sz -= 4;
|
||||
}
|
||||
else
|
||||
}
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz = block->sh4_code_size;
|
||||
u32 addr = block->addr;
|
||||
MOV32(r0,addr);
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
u16* ptr = (u16 *)GetMemPtr(addr, 2);
|
||||
MOV32(r2, (u32)ptr);
|
||||
LDRH(r2, r2, 0, AL);
|
||||
MOVW(r1, *ptr, AL);
|
||||
CMP(r1, r2);
|
||||
if (sz > 2)
|
||||
{
|
||||
u32* ptr=(u32*)GetMemPtr(addr,4);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
MOV32(r2,(u32)ptr);
|
||||
LDR(r2,r2,0);
|
||||
MOV32(r1,*ptr);
|
||||
CMP(r1,r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
addr += 2;
|
||||
sz -= 2;
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
}
|
||||
addr += 4;
|
||||
sz -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16* ptr = (u16 *)GetMemPtr(addr, 2);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
MOV32(r2, (u32)ptr);
|
||||
LDRH(r2, r2, 0, AL);
|
||||
MOVW(r1, *ptr, AL);
|
||||
CMP(r1, r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
}
|
||||
addr += 2;
|
||||
sz -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
}
|
||||
|
||||
u32 cyc=block->guest_cycles;
|
||||
|
|
|
@ -45,12 +45,11 @@ using namespace vixl::aarch64;
|
|||
extern "C" void no_update();
|
||||
extern "C" void intc_sched();
|
||||
extern "C" void ngen_blockcheckfail(u32 pc);
|
||||
|
||||
extern "C" void ngen_LinkBlock_Generic_stub();
|
||||
extern "C" void ngen_LinkBlock_cond_Branch_stub();
|
||||
extern "C" void ngen_LinkBlock_cond_Next_stub();
|
||||
|
||||
extern "C" void ngen_FailedToFindBlock_();
|
||||
extern void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
|
||||
|
||||
struct DynaRBI : RuntimeBlockInfo
|
||||
{
|
||||
|
@ -61,47 +60,6 @@ struct DynaRBI : RuntimeBlockInfo
|
|||
}
|
||||
};
|
||||
|
||||
// Code borrowed from Dolphin https://github.com/dolphin-emu/dolphin
|
||||
void Arm64CacheFlush(void* start, void* end)
|
||||
{
|
||||
if (start == end)
|
||||
return;
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
|
||||
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
|
||||
#else
|
||||
// Don't rely on GCC's __clear_cache implementation, as it caches
|
||||
// icache/dcache cache line sizes, that can vary between cores on
|
||||
// big.LITTLE architectures.
|
||||
u64 addr, ctr_el0;
|
||||
static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
|
||||
size_t isize, dsize;
|
||||
|
||||
__asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
|
||||
isize = 4 << ((ctr_el0 >> 0) & 0xf);
|
||||
dsize = 4 << ((ctr_el0 >> 16) & 0xf);
|
||||
|
||||
// use the global minimum cache line size
|
||||
icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
|
||||
dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
|
||||
|
||||
addr = (u64)start & ~(u64)(dsize - 1);
|
||||
for (; addr < (u64)end; addr += dsize)
|
||||
// use "civac" instead of "cvau", as this is the suggested workaround for
|
||||
// Cortex-A53 errata 819472, 826319, 827319 and 824069.
|
||||
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
|
||||
__asm__ volatile("dsb ish" : : : "memory");
|
||||
|
||||
addr = (u64)start & ~(u64)(isize - 1);
|
||||
for (; addr < (u64)end; addr += isize)
|
||||
__asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
|
||||
|
||||
__asm__ volatile("dsb ish" : : : "memory");
|
||||
__asm__ volatile("isb" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
double host_cpu_time;
|
||||
u64 guest_cpu_cycles;
|
||||
|
||||
|
@ -147,7 +105,7 @@ __asm__
|
|||
"ngen_LinkBlock_Shared_stub: \n\t"
|
||||
"mov x0, lr \n\t"
|
||||
"sub x0, x0, #4 \n\t" // go before the call
|
||||
"bl rdv_LinkBlock \n\t"
|
||||
"bl rdv_LinkBlock \n\t" // returns an RX addr
|
||||
"br x0 \n"
|
||||
|
||||
".hidden ngen_FailedToFindBlock_ \n\t"
|
||||
|
@ -348,15 +306,15 @@ public:
|
|||
return *ret_reg;
|
||||
}
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
//printf("REC-ARM64 compiling %08x\n", block->addr);
|
||||
#ifdef PROFILING
|
||||
SaveFramePointer();
|
||||
#endif
|
||||
this->block = block;
|
||||
if (force_checks)
|
||||
CheckBlock(block);
|
||||
|
||||
CheckBlock(smc_checks, block);
|
||||
|
||||
// run register allocator
|
||||
regalloc.DoAlloc(block);
|
||||
|
@ -617,31 +575,25 @@ public:
|
|||
break;
|
||||
|
||||
case shop_pref:
|
||||
Mov(w0, regalloc.MapRegister(op.rs1));
|
||||
if (op.flags != 0x1337)
|
||||
{
|
||||
Lsr(w1, regalloc.MapRegister(op.rs1), 26);
|
||||
Cmp(w1, 0x38);
|
||||
}
|
||||
Label not_sqw;
|
||||
B(¬_sqw, ne);
|
||||
Mov(w0, regalloc.MapRegister(op.rs1));
|
||||
|
||||
if (CCN_MMUCR.AT)
|
||||
{
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(&do_sqw_mmu));
|
||||
}
|
||||
else
|
||||
{
|
||||
Sub(x9, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, do_sqw_nommu));
|
||||
Ldr(x9, MemOperand(x9));
|
||||
Sub(x1, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, sq_buffer));
|
||||
}
|
||||
if (op.flags == 0x1337)
|
||||
if (CCN_MMUCR.AT)
|
||||
{
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(&do_sqw_mmu));
|
||||
}
|
||||
else
|
||||
{
|
||||
Sub(x9, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, do_sqw_nommu));
|
||||
Ldr(x9, MemOperand(x9));
|
||||
Sub(x1, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, sq_buffer));
|
||||
}
|
||||
Blr(x9);
|
||||
else
|
||||
{
|
||||
Label no_branch;
|
||||
B(&no_branch, ne);
|
||||
Blr(x9);
|
||||
Bind(&no_branch);
|
||||
Bind(¬_sqw);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1019,7 +971,7 @@ public:
|
|||
|
||||
Ldr(w29, sh4_context_mem_operand(&next_pc));
|
||||
|
||||
GenBranch(no_update);
|
||||
GenBranchRuntime(no_update);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1044,7 +996,12 @@ public:
|
|||
|
||||
emit_Skip(block->host_code_size);
|
||||
}
|
||||
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
|
||||
// Flush and invalidate caches
|
||||
vmem_platform_flush_cache(
|
||||
CC_RW2RX(GetBuffer()->GetStartAddress<void*>()), CC_RW2RX(GetBuffer()->GetEndAddress<void*>()),
|
||||
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
|
||||
|
||||
#if 0
|
||||
// if (rewrite)
|
||||
{
|
||||
|
@ -1066,10 +1023,13 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Runtime branches/calls need to be adjusted if rx space is different to rw space.
|
||||
// Therefore can't mix GenBranch with GenBranchRuntime!
|
||||
|
||||
template <typename R, typename... P>
|
||||
void GenCallRuntime(R (*function)(P...))
|
||||
{
|
||||
ptrdiff_t offset = reinterpret_cast<uintptr_t>(function) - GetBuffer()->GetStartAddress<uintptr_t>();
|
||||
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;
|
||||
|
@ -1077,6 +1037,17 @@ private:
|
|||
Bl(&function_label);
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void GenBranchRuntime(R (*target)(P...))
|
||||
{
|
||||
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);
|
||||
B(&target_label);
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void GenBranch(R (*code)(P...), Condition cond = al)
|
||||
{
|
||||
|
@ -1298,49 +1269,72 @@ private:
|
|||
verify (GetCursorAddress<Instruction *>() - start_instruction == code_size * kInstructionSize);
|
||||
}
|
||||
|
||||
void CheckBlock(RuntimeBlockInfo* block)
|
||||
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
|
||||
{
|
||||
s32 sz = block->sh4_code_size;
|
||||
|
||||
Label blockcheck_fail;
|
||||
Label blockcheck_success;
|
||||
|
||||
u8* ptr = GetMemPtr(block->addr, sz);
|
||||
if (ptr == NULL)
|
||||
// FIXME Can a block cross a RAM / non-RAM boundary??
|
||||
return;
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
return;
|
||||
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz >= 8)
|
||||
{
|
||||
Ldr(x10, MemOperand(x9, 8, PostIndex));
|
||||
Ldr(x11, *(u64*)ptr);
|
||||
Cmp(x10, x11);
|
||||
sz -= 8;
|
||||
ptr += 8;
|
||||
}
|
||||
else if (sz >= 4)
|
||||
{
|
||||
Ldr(w10, MemOperand(x9, 4, PostIndex));
|
||||
case FastCheck: {
|
||||
u8* ptr = GetMemPtr(block->addr, 4);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
Ldr(w10, MemOperand(x9));
|
||||
Ldr(w11, *(u32*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 4;
|
||||
ptr += 4;
|
||||
B(eq, &blockcheck_success);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ldrh(w10, MemOperand(x9, 2, PostIndex));
|
||||
Mov(w11, *(u16*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 2;
|
||||
ptr += 2;
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz = block->sh4_code_size;
|
||||
|
||||
u8* ptr = GetMemPtr(block->addr, sz);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz >= 8)
|
||||
{
|
||||
Ldr(x10, MemOperand(x9, 8, PostIndex));
|
||||
Ldr(x11, *(u64*)ptr);
|
||||
Cmp(x10, x11);
|
||||
sz -= 8;
|
||||
ptr += 8;
|
||||
}
|
||||
else if (sz >= 4)
|
||||
{
|
||||
Ldr(w10, MemOperand(x9, 4, PostIndex));
|
||||
Ldr(w11, *(u32*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 4;
|
||||
ptr += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ldrh(w10, MemOperand(x9, 2, PostIndex));
|
||||
Mov(w11, *(u16*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
B(ne, &blockcheck_fail);
|
||||
}
|
||||
B(&blockcheck_success);
|
||||
}
|
||||
B(ne, &blockcheck_fail);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
B(&blockcheck_success);
|
||||
|
||||
Bind(&blockcheck_fail);
|
||||
Ldr(w0, block->addr);
|
||||
|
@ -1403,20 +1397,23 @@ private:
|
|||
std::vector<const VRegister*> call_fregs;
|
||||
Arm64RegAlloc regalloc;
|
||||
RuntimeBlockInfo* block;
|
||||
const int write_memory_rewrite_size = 3; // same size (fast write) for any size: add, bfc, str
|
||||
#ifdef EXPLODE_SPANS
|
||||
const int read_memory_rewrite_size = 6; // worst case for u64: add, bfc, ldr, fmov, lsr, fmov
|
||||
// FIXME rewrite size per read/write size?
|
||||
const int write_memory_rewrite_size = 3;
|
||||
#else
|
||||
const int read_memory_rewrite_size = 4; // worst case for u64: add, bfc, ldr, str
|
||||
#endif
|
||||
};
|
||||
|
||||
static Arm64Assembler* compiler;
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
verify(emit_FreeSpace() >= 16 * 1024);
|
||||
|
||||
compiler = new Arm64Assembler();
|
||||
|
||||
compiler->ngen_Compile(block, force_checks, reset, staging, optimise);
|
||||
compiler->ngen_Compile(block, smc_checks, reset, staging, optimise);
|
||||
|
||||
delete compiler;
|
||||
compiler = NULL;
|
||||
|
@ -1445,13 +1442,14 @@ void ngen_CC_Finish(shil_opcode* op)
|
|||
bool ngen_Rewrite(unat& host_pc, unat, unat)
|
||||
{
|
||||
//printf("ngen_Rewrite pc %p\n", host_pc);
|
||||
RuntimeBlockInfo *block = bm_GetBlock((void *)host_pc);
|
||||
void *host_pc_rw = (void*)CC_RX2RW(host_pc);
|
||||
RuntimeBlockInfo *block = bm_GetBlock((void*)host_pc);
|
||||
if (block == NULL)
|
||||
{
|
||||
printf("ngen_Rewrite: Block at %p not found\n", (void *)host_pc);
|
||||
return false;
|
||||
}
|
||||
u32 *code_ptr = (u32*)host_pc;
|
||||
u32 *code_ptr = (u32*)host_pc_rw;
|
||||
auto it = block->memory_accesses.find(code_ptr);
|
||||
if (it == block->memory_accesses.end())
|
||||
{
|
||||
|
@ -1469,7 +1467,7 @@ bool ngen_Rewrite(unat& host_pc, unat, unat)
|
|||
assembler->GenWriteMemorySlow(op);
|
||||
assembler->Finalize(true);
|
||||
delete assembler;
|
||||
host_pc = (unat)(code_ptr - 2);
|
||||
host_pc = (unat)CC_RW2RX(code_ptr - 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "hw/sh4/dyna/ngen.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/sh4/dyna/regalloc.h"
|
||||
#include "emitter/x86_emitter.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
|
@ -1191,10 +1190,10 @@ public:
|
|||
|
||||
size_t opcode_index;
|
||||
opcodeExec** ptrsg;
|
||||
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
|
||||
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise) {
|
||||
|
||||
//we need an extra one for the end opcode and optionally one more for block check
|
||||
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (force_checks ? 1 : 0))(block->guest_cycles);
|
||||
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (smc_checks != NoCheck ? 1 : 0))(block->guest_cycles);
|
||||
|
||||
ptrsg = ptrs.ptrs;
|
||||
|
||||
|
@ -1208,9 +1207,16 @@ public:
|
|||
}
|
||||
|
||||
size_t i = 0;
|
||||
if (force_checks)
|
||||
if (smc_checks != NoCheck)
|
||||
{
|
||||
verify (smc_checks == FastCheck || smc_checks == FullCheck)
|
||||
opcodeExec* op;
|
||||
int check_size = block->sh4_code_size;
|
||||
|
||||
if (smc_checks == FastCheck) {
|
||||
check_size = 4;
|
||||
}
|
||||
|
||||
switch (block->sh4_code_size)
|
||||
{
|
||||
case 4:
|
||||
|
@ -1228,6 +1234,7 @@ public:
|
|||
}
|
||||
ptrs.ptrs[i++] = op;
|
||||
}
|
||||
|
||||
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
|
||||
opcode_index = i;
|
||||
shil_opcode& op = block->oplist[opnum];
|
||||
|
@ -1552,14 +1559,14 @@ public:
|
|||
|
||||
BlockCompiler* compiler;
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
verify(emit_FreeSpace() >= 16 * 1024);
|
||||
|
||||
compiler = new BlockCompiler();
|
||||
|
||||
|
||||
compiler->compile(block, force_checks, reset, staging, optimise);
|
||||
compiler->compile(block, smc_checks, reset, staging, optimise);
|
||||
|
||||
delete compiler;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue