Merge remote-tracking branch 'origin/master' into fh/wince-dynarec
This commit is contained in:
commit
c2c0215e1b
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@ workflows:
|
|||
- export_method: "$BITRISE_EXPORT_METHOD"
|
||||
- deploy-to-bitrise-io@1.3.19: {}
|
||||
- cache-push@2.1.1: {}
|
||||
after_run:
|
||||
- deploy-naomi
|
||||
app:
|
||||
envs:
|
||||
- opts:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
154
core/build.h
154
core/build.h
|
@ -129,10 +129,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
|
||||
|
@ -140,11 +148,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
|
||||
|
@ -154,6 +167,8 @@
|
|||
|
||||
//automatic
|
||||
|
||||
#ifndef CMAKE_BUILD
|
||||
|
||||
#if defined(_WIN32) && !defined(TARGET_WIN86) && !defined(TARGET_WIN64)
|
||||
#if !defined(_M_AMD64) && !defined(__x86_64__)
|
||||
#define TARGET_WIN86
|
||||
|
@ -235,6 +250,8 @@
|
|||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
|
||||
#endif // !CMAKE_BUILD
|
||||
|
||||
|
||||
#if defined(TARGET_NO_NIXPROF)
|
||||
#define FEAT_HAS_NIXPROF 0
|
||||
|
@ -304,3 +321,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) && HOST_OS == OS_WINDOWS)
|
||||
|
||||
#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,14 @@ 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();
|
||||
VREG = 0;
|
||||
ARMRST = 0;
|
||||
}
|
||||
|
||||
void aica_Term()
|
||||
|
@ -183,6 +183,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 +191,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 +227,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();
|
||||
|
|
|
@ -186,13 +186,7 @@ void dsp_init()
|
|||
dsp.RBP=0;
|
||||
dsp.regs.MDEC_CT=1;
|
||||
|
||||
|
||||
//os_MakeExecutable(dsp.DynCode,sizeof(dsp.DynCode));
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
DWORD old;
|
||||
VirtualProtect(dsp.DynCode, sizeof(dsp.DynCode), PAGE_EXECUTE_READWRITE, &old);
|
||||
#endif
|
||||
|
||||
mem_region_set_exec(dsp.DynCode, sizeof(dsp.DynCode));
|
||||
}
|
||||
void dsp_recompile();
|
||||
|
||||
|
|
|
@ -21,13 +21,12 @@
|
|||
|
||||
#if HOST_CPU == CPU_ARM64 && FEAT_DSPREC != DYNAREC_NONE
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include "dsp.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
#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 +53,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 +386,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:
|
||||
|
@ -522,7 +521,7 @@ void dsp_init()
|
|||
dsp.regs.MDEC_CT = 1;
|
||||
dsp.dyndirty = true;
|
||||
|
||||
if (mprotect(dsp.DynCode, sizeof(dsp.DynCode), PROT_EXEC | PROT_READ | PROT_WRITE))
|
||||
if (!mem_region_set_exec(dsp.DynCode, sizeof(dsp.DynCode)))
|
||||
{
|
||||
perror("Couldn’t mprotect DSP code");
|
||||
die("mprotect failed in arm64 dsp");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -69,12 +69,6 @@ bool Arm7Enabled=false;
|
|||
|
||||
u8 cpuBitsSet[256];
|
||||
|
||||
bool intState = false;
|
||||
bool stopState = false;
|
||||
bool holdState = false;
|
||||
|
||||
|
||||
|
||||
void CPUSwitchMode(int mode, bool saveState, bool breakLoop=true);
|
||||
extern "C" void CPUFiq();
|
||||
void CPUUpdateCPSR();
|
||||
|
@ -428,7 +422,7 @@ void arm_Run(u32 CycleCount) {
|
|||
}
|
||||
#else // FEAT_AREC != DYNAREC_NONE
|
||||
|
||||
#if HOST_OS == OS_LINUX || HOST_OS == OS_DARWIN
|
||||
#if HOST_OS == OS_DARWIN
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
|
@ -1563,10 +1557,6 @@ naked void arm_exit()
|
|||
*
|
||||
*/
|
||||
|
||||
//mprotect and stuff ..
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
void armEmit32(u32 emit32)
|
||||
{
|
||||
if (icPtr >= (ICache+ICacheSize-1024))
|
||||
|
@ -2189,25 +2179,12 @@ void armt_init()
|
|||
ICache = (u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
|
||||
#endif
|
||||
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
DWORD old;
|
||||
VirtualProtect(ICache,ICacheSize,PAGE_EXECUTE_READWRITE,&old);
|
||||
#elif HOST_OS == OS_LINUX || HOST_OS == OS_DARWIN
|
||||
|
||||
printf("\n\t ARM7_TCB addr: %p | from: %p | addr here: %p\n", ICache, ARM7_TCB, armt_init);
|
||||
|
||||
if (mprotect(ICache, ICacheSize, PROT_EXEC|PROT_READ|PROT_WRITE))
|
||||
{
|
||||
perror("\n\tError - Couldn’t mprotect ARM7_TCB!");
|
||||
verify(false);
|
||||
}
|
||||
mem_region_set_exec(ICache, ICacheSize);
|
||||
|
||||
#if TARGET_IPHONE
|
||||
memset((u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0),0xFF,ICacheSize);
|
||||
#else
|
||||
memset(ICache,0xFF,ICacheSize);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
icPtr=ICache;
|
||||
|
|
|
@ -21,7 +21,7 @@ struct MemChip
|
|||
this->mask=size-1;//must be power of 2
|
||||
this->write_protect_size = write_protect_size;
|
||||
}
|
||||
~MemChip() { delete[] data; }
|
||||
virtual ~MemChip() { delete[] data; }
|
||||
|
||||
virtual u8 Read8(u32 addr)
|
||||
{
|
||||
|
@ -118,14 +118,11 @@ struct MemChip
|
|||
|
||||
printf("Saved %s as %s\n\n",path,title.c_str());
|
||||
}
|
||||
virtual void Reset() {}
|
||||
};
|
||||
struct RomChip : MemChip
|
||||
{
|
||||
RomChip(u32 sz, u32 write_protect_size = 0) : MemChip(sz, write_protect_size) {}
|
||||
void Reset()
|
||||
{
|
||||
//nothing, its permanent read only ;p
|
||||
}
|
||||
void Write(u32 addr,u32 data,u32 sz)
|
||||
{
|
||||
die("Write to RomChip is not possible, address=%x, data=%x, size=%d");
|
||||
|
@ -135,10 +132,6 @@ struct SRamChip : MemChip
|
|||
{
|
||||
SRamChip(u32 sz, u32 write_protect_size = 0) : MemChip(sz, write_protect_size) {}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
//nothing, its battery backed up storage
|
||||
}
|
||||
void Write(u32 addr,u32 val,u32 sz)
|
||||
{
|
||||
addr&=mask;
|
||||
|
@ -234,7 +227,7 @@ struct DCFlashChip : MemChip
|
|||
};
|
||||
|
||||
FlashState state;
|
||||
void Reset()
|
||||
virtual void Reset() override
|
||||
{
|
||||
//reset the flash chip state
|
||||
state = FS_Normal;
|
||||
|
@ -378,19 +371,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)
|
||||
|
@ -321,6 +322,13 @@ u32 GetFAD(u8* data, bool msf)
|
|||
void libCore_gdrom_disc_change()
|
||||
{
|
||||
gd_setdisc();
|
||||
read_params = { 0 };
|
||||
set_mode_offset = 0;
|
||||
packet_cmd = { 0 };
|
||||
memset(&read_buff, 0, sizeof(read_buff));
|
||||
pio_buff = { gds_waitcmd, 0 };
|
||||
ata_cmd = { 0 };
|
||||
cdda = { 0 };
|
||||
}
|
||||
|
||||
//This handles the work of setting up the pio regs/state :)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ bool LoadRomFiles(const string& root)
|
|||
{
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
// Dreamcast absolutely needs a BIOS
|
||||
msgboxf("Unable to find bios in \n%s\nExiting...", MBX_ICONERROR, root.c_str());
|
||||
msgboxf("Unable to find bios in %s. Exiting...", MBX_ICONERROR, root.c_str());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
@ -85,7 +85,9 @@ bool LoadRomFiles(const string& root)
|
|||
if (settings.dreamcast.language <= 5)
|
||||
syscfg.lang = settings.dreamcast.language;
|
||||
|
||||
sys_nvmem.WriteBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
|
||||
if (sys_nvmem.WriteBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg) != 1)
|
||||
printf("Failed to save time and language to flash RAM\n");
|
||||
|
||||
#endif
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
|
@ -206,7 +208,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 +219,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 +306,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
|
||||
}
|
||||
|
@ -344,6 +350,10 @@ void sh4_area0_Init()
|
|||
void sh4_area0_Reset(bool Manual)
|
||||
{
|
||||
sb_Reset(Manual);
|
||||
sys_rom.Reset();
|
||||
#if defined(FLASH_SIZE) || defined(BBSRAM_SIZE)
|
||||
sys_nvmem.Reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void sh4_area0_Term()
|
||||
|
|
|
@ -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 (?)
|
||||
|
@ -622,9 +684,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)
|
||||
|
@ -1247,6 +1307,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;
|
||||
|
@ -1295,21 +1359,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
|
||||
|
@ -1335,6 +1391,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];
|
||||
|
@ -1361,20 +1424,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;
|
||||
|
||||
|
@ -2293,63 +2365,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;
|
||||
}
|
||||
|
@ -2373,34 +2438,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);
|
||||
|
@ -2473,8 +2554,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;
|
||||
|
@ -2522,7 +2603,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:
|
||||
|
@ -2546,7 +2631,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;
|
||||
|
@ -394,10 +393,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"
|
||||
|
@ -418,414 +414,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 vmem_fd = -1;
|
||||
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, vmem_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, vmem_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");
|
||||
vmem_fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink(path.c_str());
|
||||
verify(ftruncate(vmem_fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
|
||||
#elif !defined(_ANDROID)
|
||||
vmem_fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
|
||||
shm_unlink("/dcnzorz_mem");
|
||||
if (vmem_fd==-1)
|
||||
{
|
||||
vmem_fd = open("dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink("dcnzorz_mem");
|
||||
}
|
||||
|
||||
verify(ftruncate(vmem_fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
|
||||
#else
|
||||
|
||||
vmem_fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
|
||||
if (false)//this causes writebacks to flash -> slow and stuttery
|
||||
{
|
||||
vmem_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
|
||||
size_t 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: %p, aram: %p, vram: %p, ram: %p\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(vmem_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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -24,15 +24,14 @@ bool bios_loaded = false;
|
|||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#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 +245,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++)
|
||||
{
|
||||
|
@ -485,15 +484,9 @@ bool naomi_cart_LoadRom(char* file)
|
|||
RomCacheMapCount = (u32)files.size();
|
||||
RomCacheMap = new fd_t[files.size()]();
|
||||
|
||||
//Allocate space for the ram, so we are sure we have a segment of continius ram
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
RomPtr = (u8*)VirtualAlloc(0, RomSize, MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
RomPtr = (u8*)mmap(0, RomSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#endif
|
||||
|
||||
verify(RomPtr != 0);
|
||||
verify(RomPtr != (void*)-1);
|
||||
//Allocate space for the ram, so we are sure we have a segment of continuous ram
|
||||
RomPtr = (u8*)mem_region_reserve(NULL, RomSize);
|
||||
verify(RomPtr != NULL);
|
||||
|
||||
bool load_error = false;
|
||||
|
||||
|
@ -550,11 +543,7 @@ bool naomi_cart_LoadRom(char* file)
|
|||
}
|
||||
|
||||
//Release the segment we reserved so we can map the files there
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
verify(VirtualFree(RomPtr, 0, MEM_RELEASE));
|
||||
#else
|
||||
munmap(RomPtr, RomSize);
|
||||
#endif
|
||||
mem_region_release(RomPtr, RomSize);
|
||||
|
||||
if (load_error)
|
||||
{
|
||||
|
@ -574,23 +563,13 @@ bool naomi_cart_LoadRom(char* file)
|
|||
if (RomCacheMap[i] == INVALID_FD)
|
||||
{
|
||||
//printf("-Reserving ram at 0x%08X, size 0x%08X\n", fstart[i], fsize[i]);
|
||||
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
bool mapped = RomDest == VirtualAlloc(RomDest, fsize[i], MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
bool mapped = RomDest == (u8*)mmap(RomDest, RomSize, PROT_NONE, MAP_PRIVATE, 0, 0);
|
||||
#endif
|
||||
|
||||
bool mapped = RomDest == (u8 *)mem_region_reserve(RomDest, fsize[i]);
|
||||
verify(mapped);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("-Mapping \"%s\" at 0x%08X, size 0x%08X\n", files[i].c_str(), fstart[i], fsize[i]);
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
bool mapped = RomDest == MapViewOfFileEx(RomCacheMap[i], FILE_MAP_READ, 0, 0, fsize[i], RomDest);
|
||||
#else
|
||||
bool mapped = RomDest == mmap(RomDest, fsize[i], PROT_READ, MAP_PRIVATE, RomCacheMap[i], 0 );
|
||||
#endif
|
||||
bool mapped = RomDest == (u8 *)mem_region_map_file((void *)(uintptr_t)RomCacheMap[i], RomDest, fsize[i], 0, false);
|
||||
if (!mapped)
|
||||
{
|
||||
printf("-Mapping ROM FAILED: %s @ %08x size %x\n", files[i].c_str(), fstart[i], fsize[i]);
|
||||
|
@ -636,11 +615,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;
|
||||
}
|
||||
|
||||
|
@ -653,7 +632,8 @@ Cartridge::Cartridge(u32 size)
|
|||
|
||||
Cartridge::~Cartridge()
|
||||
{
|
||||
free(RomPtr);
|
||||
if (RomPtr != NULL)
|
||||
free(RomPtr);
|
||||
}
|
||||
|
||||
bool Cartridge::Read(u32 offset, u32 size, void* dst)
|
||||
|
@ -1036,3 +1016,11 @@ void M2Cartridge::Unserialize(void** data, unsigned int* total_size) {
|
|||
REICAST_US(naomi_cart_ram);
|
||||
NaomiCartridge::Unserialize(data, total_size);
|
||||
}
|
||||
|
||||
DecryptedCartridge::~DecryptedCartridge()
|
||||
{
|
||||
// TODO this won't work on windows -> need to unmap each file first
|
||||
mem_region_release(RomPtr, RomSize);
|
||||
// Avoid crash when freeing vmem
|
||||
RomPtr = NULL;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class DecryptedCartridge : public NaomiCartridge
|
|||
{
|
||||
public:
|
||||
DecryptedCartridge(u8 *rom_ptr, u32 size) : NaomiCartridge(size) { RomPtr = rom_ptr; }
|
||||
// FIXME Must do a munmap and close for each segment
|
||||
virtual ~DecryptedCartridge() override;
|
||||
};
|
||||
|
||||
class M2Cartridge : public NaomiCartridge
|
||||
|
@ -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
|
||||
static bool swap_pending;
|
||||
static bool do_swap;
|
||||
|
@ -91,16 +90,15 @@ static bool do_swap;
|
|||
int max_idx,max_mvo,max_op,max_pt,max_tr,max_vtx,max_modt, ovrn;
|
||||
|
||||
static bool render_called = false;
|
||||
u32 fb1_watch_addr_start;
|
||||
u32 fb1_watch_addr_end;
|
||||
u32 fb2_watch_addr_start;
|
||||
u32 fb2_watch_addr_end;
|
||||
u32 fb_watch_addr_start;
|
||||
u32 fb_watch_addr_end;
|
||||
bool fb_dirty;
|
||||
|
||||
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");
|
||||
|
@ -269,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
|
||||
{
|
||||
|
@ -389,7 +394,6 @@ void rend_term_renderer()
|
|||
delete fallback_renderer;
|
||||
fallback_renderer = NULL;
|
||||
}
|
||||
tactx_Term();
|
||||
}
|
||||
|
||||
void* rend_thread(void* p)
|
||||
|
@ -556,6 +560,7 @@ void rend_end_render()
|
|||
void rend_stop_renderer()
|
||||
{
|
||||
renderer_enabled = false;
|
||||
tactx_Term();
|
||||
}
|
||||
|
||||
void rend_vblank()
|
||||
|
@ -574,10 +579,8 @@ void rend_vblank()
|
|||
void check_framebuffer_write()
|
||||
{
|
||||
u32 fb_size = (FB_R_SIZE.fb_y_size + 1) * (FB_R_SIZE.fb_x_size + FB_R_SIZE.fb_modulus) * 4;
|
||||
fb1_watch_addr_start = FB_R_SOF1 & VRAM_MASK;
|
||||
fb1_watch_addr_end = fb1_watch_addr_start + fb_size;
|
||||
fb2_watch_addr_start = FB_R_SOF2 & VRAM_MASK;
|
||||
fb2_watch_addr_end = fb2_watch_addr_start + fb_size;
|
||||
fb_watch_addr_start = FB_R_SOF2 & VRAM_MASK;
|
||||
fb_watch_addr_end = fb_watch_addr_start + fb_size;
|
||||
}
|
||||
|
||||
void rend_cancel_emu_wait()
|
||||
|
|
|
@ -62,10 +62,8 @@ Renderer* rend_GL4();
|
|||
Renderer* rend_norend();
|
||||
Renderer* rend_softrend();
|
||||
|
||||
extern u32 fb1_watch_addr_start;
|
||||
extern u32 fb1_watch_addr_end;
|
||||
extern u32 fb2_watch_addr_start;
|
||||
extern u32 fb2_watch_addr_end;
|
||||
extern u32 fb_watch_addr_start;
|
||||
extern u32 fb_watch_addr_end;
|
||||
extern bool fb_dirty;
|
||||
|
||||
void check_framebuffer_write();
|
||||
|
|
|
@ -233,9 +233,7 @@ void DYNACALL pvr_write_area1_8(u32 addr,u8 data)
|
|||
void DYNACALL pvr_write_area1_16(u32 addr,u16 data)
|
||||
{
|
||||
u32 vaddr = addr & VRAM_MASK;
|
||||
if (!fb_dirty
|
||||
&& ((vaddr >= fb1_watch_addr_start && vaddr < fb1_watch_addr_end)
|
||||
|| (vaddr >= fb2_watch_addr_start && vaddr < fb2_watch_addr_end)))
|
||||
if (vaddr >= fb_watch_addr_start && vaddr < fb_watch_addr_end)
|
||||
{
|
||||
fb_dirty = true;
|
||||
}
|
||||
|
@ -244,9 +242,7 @@ void DYNACALL pvr_write_area1_16(u32 addr,u16 data)
|
|||
void DYNACALL pvr_write_area1_32(u32 addr,u32 data)
|
||||
{
|
||||
u32 vaddr = addr & VRAM_MASK;
|
||||
if (!fb_dirty
|
||||
&& ((vaddr >= fb1_watch_addr_start && vaddr < fb1_watch_addr_end)
|
||||
|| (vaddr >= fb2_watch_addr_start && vaddr < fb2_watch_addr_end)))
|
||||
if (vaddr >= fb_watch_addr_start && vaddr < fb_watch_addr_end)
|
||||
{
|
||||
fb_dirty = true;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -117,6 +119,20 @@ int spg_line_sched(int tag, int cycl, int jit)
|
|||
SPG_STATUS.vsync=in_vblank;
|
||||
SPG_STATUS.scanline=prv_cur_scanline;
|
||||
|
||||
switch (SPG_HBLANK_INT.hblank_int_mode)
|
||||
{
|
||||
case 0x0:
|
||||
if (prv_cur_scanline == SPG_HBLANK_INT.line_comp_val)
|
||||
asic_RaiseInterrupt(holly_HBLank);
|
||||
break;
|
||||
case 0x2:
|
||||
asic_RaiseInterrupt(holly_HBLank);
|
||||
break;
|
||||
default:
|
||||
die("Unimplemented HBLANK INT mode");
|
||||
break;
|
||||
}
|
||||
|
||||
//Vblank start -- really need to test the scanline values
|
||||
if (prv_cur_scanline==0)
|
||||
{
|
||||
|
@ -127,7 +143,6 @@ int spg_line_sched(int tag, int cycl, int jit)
|
|||
|
||||
//Vblank counter
|
||||
vblk_cnt++;
|
||||
asic_RaiseInterrupt(holly_HBLank);// -> This turned out to be HBlank btw , needs to be emulated ;(
|
||||
//TODO : rend_if_VBlank();
|
||||
rend_vblank();//notify for vblank :)
|
||||
|
||||
|
@ -174,7 +189,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);
|
||||
|
||||
|
|
|
@ -20,5 +20,3 @@ void DYNACALL ta_vtx_data32(void* data);
|
|||
void ta_vtx_data(u32* data, u32 size);
|
||||
|
||||
bool ta_parse_vdrc(TA_context* ctx);
|
||||
|
||||
#define TRIG_SORT 1
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -89,15 +89,16 @@ u32 bm_gc_luc,bm_gcf_luc;
|
|||
#define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
|
||||
|
||||
// addr must be a physical address
|
||||
// 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 rv;
|
||||
}
|
||||
|
||||
// addr must be a virtual address
|
||||
// This returns an executable address
|
||||
DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
|
@ -157,36 +158,41 @@ DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr)
|
|||
}
|
||||
|
||||
// addr must be a physical address
|
||||
// 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];
|
||||
}
|
||||
|
||||
|
@ -206,9 +212,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)
|
||||
|
@ -394,6 +399,8 @@ void bm_Rebuild()
|
|||
{
|
||||
return;
|
||||
|
||||
die("this is broken in multiple levels, including compile options");
|
||||
|
||||
void RASDASD();
|
||||
RASDASD();
|
||||
|
||||
|
@ -411,7 +418,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]);
|
||||
|
@ -427,9 +434,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;
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ void bm_WriteBlockMap(const string& file);
|
|||
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr);
|
||||
|
||||
extern "C" {
|
||||
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr);
|
||||
ATTR_USED DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr);
|
||||
}
|
||||
|
||||
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code);
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
#include "types.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#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/sh4/modules/mmu.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
|
@ -28,9 +22,7 @@
|
|||
#include "decoder.h"
|
||||
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
//uh uh
|
||||
|
||||
#if !defined(_WIN64)
|
||||
u8 SH4_TCB[CODE_SIZE + TEMP_CODE_SIZE + 4096]
|
||||
#if HOST_OS == OS_WINDOWS || FEAT_SHREC != DYNAREC_JIT
|
||||
;
|
||||
|
@ -41,10 +33,10 @@ u8 SH4_TCB[CODE_SIZE + TEMP_CODE_SIZE + 4096]
|
|||
#else
|
||||
#error SH4_TCB ALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
u8* CodeCache;
|
||||
u8* TempCodeCache;
|
||||
uintptr_t cc_rx_offset;
|
||||
|
||||
u32 LastAddr;
|
||||
u32 LastAddr_min;
|
||||
|
@ -101,6 +93,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);
|
||||
|
@ -141,34 +142,51 @@ u32 emit_FreeSpace()
|
|||
}
|
||||
|
||||
// pc must be a physical address
|
||||
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);
|
||||
|
@ -307,6 +325,8 @@ DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
|
|||
DynarecCodeEntryPtr code = rdv_CompilePC(0);
|
||||
if (code == NULL)
|
||||
code = bm_GetCodeByVAddr(next_pc);
|
||||
else
|
||||
code = (DynarecCodeEntryPtr)CC_RW2RX(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -361,7 +381,7 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 addr)
|
|||
next_pc = addr;
|
||||
recSh4_ClearCache();
|
||||
}
|
||||
return rdv_CompilePC(blockcheck_failures);
|
||||
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC(blockcheck_failures));
|
||||
}
|
||||
|
||||
//DynarecCodeEntryPtr rdv_FindCode()
|
||||
|
@ -375,21 +395,22 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 addr)
|
|||
|
||||
DynarecCodeEntryPtr rdv_FindOrCompile()
|
||||
{
|
||||
DynarecCodeEntryPtr rv=bm_GetCodeByVAddr(next_pc);
|
||||
if (rv==ngen_FailedToFindBlock)
|
||||
rv=rdv_CompilePC(0);
|
||||
DynarecCodeEntryPtr rv = bm_GetCodeByVAddr(next_pc); // Returns exec addr
|
||||
if (rv == ngen_FailedToFindBlock)
|
||||
rv = (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC(0)); // 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);
|
||||
|
@ -412,7 +433,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 = !mmu_enabled() && bm_GetBlock(code) == rbi;
|
||||
|
||||
|
@ -481,10 +502,6 @@ void recSh4_Reset(bool Manual)
|
|||
Sh4_int_Reset(Manual);
|
||||
}
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
void recSh4_Init()
|
||||
{
|
||||
printf("recSh4 Init\n");
|
||||
|
@ -502,57 +519,24 @@ 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 + TEMP_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 + TEMP_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 + TEMP_CODE_SIZE);
|
||||
CodeCache = (u8*)mmap(CodeCache, CODE_SIZE + TEMP_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 + TEMP_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 + TEMP_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 + TEMP_CODE_SIZE, (void**)&CodeCache, &cc_rx_offset));
|
||||
#else
|
||||
verify(vmem_platform_prepare_jit_block(candidate_ptr, CODE_SIZE + TEMP_CODE_SIZE, (void**)&CodeCache));
|
||||
#endif
|
||||
// Ensure the pointer returned is non-null
|
||||
verify(CodeCache != NULL);
|
||||
|
||||
#if TARGET_IPHONE
|
||||
memset((u8*)mmap(CodeCache, CODE_SIZE + TEMP_CODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0),0xFF,CODE_SIZE + TEMP_CODE_SIZE);
|
||||
#else
|
||||
memset(CodeCache,0xFF,CODE_SIZE + TEMP_CODE_SIZE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
memset(CodeCache, 0xFF, CODE_SIZE + TEMP_CODE_SIZE);
|
||||
TempCodeCache = CodeCache + CODE_SIZE;
|
||||
ngen_init();
|
||||
bm_Reset();
|
||||
}
|
||||
|
||||
void recSh4_Term()
|
||||
|
@ -580,4 +564,5 @@ void Get_Sh4Recompiler(sh4_if* rv)
|
|||
rv->IsCpuRunning = recSh4_IsCpuRunning;
|
||||
rv->ResetCache = recSh4_ClearCache;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FEAT_SHREC != DYNAREC_NONE
|
||||
|
|
|
@ -52,6 +52,20 @@
|
|||
#define TEMP_CODE_SIZE (1024*1024)
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
extern u8* CodeCache;
|
||||
|
@ -89,7 +103,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();
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
//Types
|
||||
|
||||
#define printf_smc(...) // printf
|
||||
|
||||
|
||||
u32 CCN_QACR_TR[2];
|
||||
|
||||
|
@ -83,13 +85,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;
|
||||
|
|
|
@ -317,7 +317,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);
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
string normalize_path_separator(string path)
|
||||
{
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
std::replace( path.begin(), path.end(), '/', '\\');
|
||||
#endif
|
||||
#if HOST_OS == OS_WINDOWS
|
||||
std::replace(path.begin(), path.end(), '/', '\\');
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
#if HOST_OS==OS_LINUX
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
//#include <curses.h>
|
||||
#include <fcntl.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
|
@ -408,7 +406,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();
|
||||
}
|
||||
|
|
|
@ -11,22 +11,16 @@
|
|||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
//#include <curses.h>
|
||||
#include <fcntl.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#if !defined(TARGET_BSD) && !defined(_ANDROID) && !defined(TARGET_IPHONE) && !defined(TARGET_NACL32) && !defined(TARGET_EMSCRIPTEN) && !defined(TARGET_OSX) && !defined(TARGET_OSX_X64)
|
||||
#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"
|
||||
#include "hw/mem/vmem32.h"
|
||||
|
@ -58,14 +52,13 @@ 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 + TEMP_CODE_SIZE));
|
||||
bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE + TEMP_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);
|
||||
|
@ -121,12 +114,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;
|
||||
|
@ -140,172 +130,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,322 @@
|
|||
|
||||
// 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
|
||||
|
||||
bool mem_region_lock(void *start, size_t len)
|
||||
{
|
||||
size_t inpage = (uintptr_t)start & PAGE_MASK;
|
||||
if (mprotect((u8*)start - inpage, len + inpage, PROT_READ))
|
||||
die("mprotect failed...");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mem_region_unlock(void *start, size_t len)
|
||||
{
|
||||
size_t inpage = (uintptr_t)start & PAGE_MASK;
|
||||
if (mprotect((u8*)start - inpage, len + inpage, PROT_READ | PROT_WRITE))
|
||||
// Add some way to see why it failed? gdb> info proc mappings
|
||||
die("mprotect failed...");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mem_region_set_exec(void *start, size_t len)
|
||||
{
|
||||
size_t inpage = (uintptr_t)start & PAGE_MASK;
|
||||
if (mprotect((u8*)start - inpage, len + inpage, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
die("mprotect failed...");
|
||||
return true;
|
||||
}
|
||||
|
||||
void *mem_region_reserve(void *start, size_t len)
|
||||
{
|
||||
void *p = mmap(start, len, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
bool mem_region_release(void *start, size_t len)
|
||||
{
|
||||
return munmap(start, len) == 0;
|
||||
}
|
||||
|
||||
void *mem_region_map_file(void *file_handle, void *dest, size_t len, size_t offset, bool readwrite)
|
||||
{
|
||||
int flags = MAP_SHARED | MAP_NOSYNC | (dest != NULL ? MAP_FIXED : 0);
|
||||
void *p = mmap(dest, len, PROT_READ | (readwrite ? PROT_WRITE : 0), flags, (int)(uintptr_t)file_handle, offset);
|
||||
if (p == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
bool mem_region_unmap_file(void *start, size_t len)
|
||||
{
|
||||
return mem_region_release(start, len);
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
int vmem_fd = -1;
|
||||
static int 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
|
||||
vmem_fd = allocate_shared_filemem(RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
|
||||
if (vmem_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 = mem_region_reserve(NULL, memsize);
|
||||
if (!first_ptr) {
|
||||
close(vmem_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).
|
||||
mem_region_unlock(sh4rcb_base_ptr, sizeof(Sh4RCB) - FPCB_SIZE);
|
||||
|
||||
return MemType512MB;
|
||||
}
|
||||
|
||||
// Just tries to wipe as much as possible in the relevant area.
|
||||
void vmem_platform_destroy() {
|
||||
mem_region_release(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(mem_region_unlock(address, size_bytes));
|
||||
}
|
||||
|
||||
// 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;
|
||||
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(mem_region_unmap_file(&virt_ram_base[offset], vmem_maps[i].memsize));
|
||||
verify(mem_region_map_file((void*)(uintptr_t)vmem_fd, &virt_ram_base[offset],
|
||||
vmem_maps[i].memsize, vmem_maps[i].memoffset, vmem_maps[i].allow_writes) != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (!mem_region_set_exec(code_area, size))
|
||||
{
|
||||
// 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
|
||||
|
128
core/nullDC.cpp
128
core/nullDC.cpp
|
@ -23,6 +23,7 @@
|
|||
#include "imgread/common.h"
|
||||
#include "rend/gui.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "input/gamepad_device.h"
|
||||
|
||||
void FlushCache();
|
||||
void LoadCustom();
|
||||
|
@ -99,10 +100,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;
|
||||
|
@ -142,7 +139,7 @@ void LoadSpecialSettings()
|
|||
extra_depth_game = false;
|
||||
full_mmu_game = false;
|
||||
disable_vmem32_game = false;
|
||||
|
||||
|
||||
if (reios_windows_ce)
|
||||
{
|
||||
printf("Enabling Full MMU and Extra depth scaling for Windows CE game\n");
|
||||
|
@ -218,7 +215,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);
|
||||
|
@ -241,12 +238,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;
|
||||
|
@ -256,9 +255,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))
|
||||
|
@ -284,6 +285,7 @@ void dc_reset()
|
|||
}
|
||||
|
||||
static bool init_done;
|
||||
static bool reset_requested;
|
||||
|
||||
int reicast_init(int argc, char* argv[])
|
||||
{
|
||||
|
@ -344,10 +346,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();
|
||||
|
@ -365,7 +382,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
|
||||
|
@ -386,6 +402,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
|
||||
|
@ -446,9 +467,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;
|
||||
|
@ -476,6 +506,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();
|
||||
|
@ -484,7 +521,6 @@ void dc_exit()
|
|||
|
||||
void InitSettings()
|
||||
{
|
||||
settings.dreamcast.RTC = GetRTC_now();
|
||||
settings.dynarec.Enable = true;
|
||||
settings.dynarec.idleskip = true;
|
||||
settings.dynarec.unstable_opt = false;
|
||||
|
@ -495,10 +531,12 @@ void InitSettings()
|
|||
settings.dreamcast.broadcast = 4; // default
|
||||
settings.dreamcast.language = 6; // default
|
||||
settings.dreamcast.FullMMU = false;
|
||||
settings.dynarec.SmcCheckLevel = FullCheck;
|
||||
settings.aica.DSPEnabled = false;
|
||||
settings.aica.LimitFPS = true;
|
||||
settings.aica.LimitFPS = LimitFPSEnabled;
|
||||
settings.aica.NoBatch = false;
|
||||
settings.aica.NoSound = false;
|
||||
settings.audio.backend = "auto";
|
||||
settings.rend.UseMipmaps = true;
|
||||
settings.rend.WideScreen = false;
|
||||
settings.rend.ShowFPS = false;
|
||||
|
@ -513,6 +551,11 @@ 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.rend.PerStripSorting = false;
|
||||
|
||||
settings.pvr.ta_skip = 0;
|
||||
settings.pvr.rend = 0;
|
||||
|
@ -559,21 +602,24 @@ 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.disable_vmem32 = cfgLoadBool(config_section, "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32);
|
||||
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);
|
||||
settings.dreamcast.broadcast = cfgLoadInt(config_section, "Dreamcast.Broadcast", settings.dreamcast.broadcast);
|
||||
settings.dreamcast.language = cfgLoadInt(config_section, "Dreamcast.Language", settings.dreamcast.language);
|
||||
settings.dreamcast.FullMMU = cfgLoadBool(config_section, "Dreamcast.FullMMU", settings.dreamcast.FullMMU);
|
||||
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
settings.aica.LimitFPS = (LimitFPSEnum)cfgLoadInt(config_section, "aica.LimitFPS", (int)settings.aica.LimitFPS);
|
||||
settings.aica.DSPEnabled = cfgLoadBool(config_section, "aica.DSPEnabled", settings.aica.DSPEnabled);
|
||||
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);
|
||||
|
@ -595,6 +641,11 @@ 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.rend.PerStripSorting = cfgLoadBool(config_section, "rend.PerStripSorting", settings.rend.PerStripSorting);
|
||||
|
||||
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
|
||||
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
|
||||
|
@ -659,9 +710,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);
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -701,12 +752,35 @@ 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);
|
||||
|
||||
if (!disable_vmem32_game || !settings.dynarec.disable_vmem32)
|
||||
cfgSaveBool("config", "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32);
|
||||
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
|
||||
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
cfgSaveInt("config", "aica.LimitFPS", (int)settings.aica.LimitFPS);
|
||||
cfgSaveBool("config", "aica.DSPEnabled", settings.aica.DSPEnabled);
|
||||
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)
|
||||
|
@ -719,8 +793,13 @@ 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);
|
||||
cfgSaveBool("config", "rend.PerStripSorting", settings.rend.PerStripSorting);
|
||||
|
||||
cfgSaveInt("config", "pvr.MaxThreads", settings.pvr.MaxThreads);
|
||||
cfgSaveBool("config", "pvr.SynchronousRendering", settings.pvr.SynchronousRender);
|
||||
|
@ -747,6 +826,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;
|
||||
}
|
||||
}
|
||||
|
@ -119,30 +159,13 @@ static u32 alsa_push(void* frame, u32 samples, bool wait)
|
|||
if (rc == -EPIPE)
|
||||
{
|
||||
/* EPIPE means underrun */
|
||||
fprintf(stderr, "ALSA: underrun occurred\n");
|
||||
snd_pcm_prepare(handle);
|
||||
// Write some silence then our samples
|
||||
const size_t silence_size = period_size * 4;
|
||||
void *silence = alloca(silence_size * 4);
|
||||
memset(silence, 0, silence_size * 4);
|
||||
rc = snd_pcm_writei(handle, silence, silence_size);
|
||||
if (rc < 0)
|
||||
fprintf(stderr, "ALSA: error from writei(silence): %s\n", snd_strerror(rc));
|
||||
else if (rc < silence_size)
|
||||
fprintf(stderr, "ALSA: short write from writei(silence): %d/%ld frames\n", rc, silence_size);
|
||||
rc = snd_pcm_writei(handle, frame, samples);
|
||||
if (rc < 0)
|
||||
fprintf(stderr, "ALSA: error from writei(again): %s\n", snd_strerror(rc));
|
||||
else if (rc < samples)
|
||||
fprintf(stderr, "ALSA: short write from writei(again): %d/%d frames\n", rc, samples);
|
||||
}
|
||||
else if (rc < 0)
|
||||
{
|
||||
fprintf(stderr, "ALSA: error from writei: %s\n", snd_strerror(rc));
|
||||
}
|
||||
else if (rc != samples)
|
||||
{
|
||||
fprintf(stderr, "ALSA: short write, wrote %d frames of %d\n", rc, samples);
|
||||
snd_pcm_writei(handle, silence, silence_size);
|
||||
snd_pcm_writei(handle, frame, samples);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -153,11 +176,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,31 @@ void WriteSample(s16 r, s16 l)
|
|||
|
||||
if (WritePtr==(SAMPLE_COUNT-1))
|
||||
{
|
||||
PushAudio(RingBuffer,SAMPLE_COUNT,settings.aica.LimitFPS);
|
||||
bool do_wait = settings.aica.LimitFPS == LimitFPSEnabled
|
||||
|| (settings.aica.LimitFPS == LimitFPSAuto && 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 +185,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 +211,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue