Merge remote-tracking branch 'origin/upstream-master'

This commit is contained in:
Flyinghead 2019-05-21 11:17:14 +02:00
commit d38e094ba0
328 changed files with 9678 additions and 13189 deletions

3
.gitignore vendored
View File

@ -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

313
CMakeLists.txt Normal file
View File

@ -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()

220
CMakeSettings.json Normal file
View File

@ -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"
}
]
}
]
}

View File

@ -1,19 +1,18 @@
[![Snap Status](https://build.snapcraft.io/badge/reicast/reicast-emulator.svg)](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
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/reicast/reicast-emulator/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@ -1,31 +1,50 @@
version: git-{branch}-{build}
image: Visual Studio 2017
environment:
matrix:
- EXTRA_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin\
LAUNCH_BUILD: mingw32-make platform=win32
LAUNCH_PATH: shell\linux\
configuration:
- RelWithDebInfo
- fast
platform:
- x64
before_build:
- cmd: >-
if "%CONFIGURATION%"=="RelWithDebInfo" (set BUILD_PATH=build)
if "%CONFIGURATION%"=="fast" (set BUILD_PATH=shell\linux)
set EXTRA_PATH=C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin\
set PATH=%EXTRA_PATH%;%PATH%
if not exist %BUILD_PATH% (mkdir %BUILD_PATH%)
if "%CONFIGURATION%"=="RelWithDebInfo" (cmake -B %BUILD_PATH% -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo)
cd %BUILD_PATH%
build_script:
- cmd: >-
set PATH=%EXTRA_PATH%;%PATH%
cd %LAUNCH_PATH%
%LAUNCH_BUILD%
- cmd: >-
if "%CONFIGURATION%"=="RelWithDebInfo" (msbuild reicast.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll")
if "%CONFIGURATION%"=="fast" (mingw32-make platform=win32)
after_build:
- cmd: cd ..\..
- cmd: mkdir artifacts
- cmd: move shell\linux\reicast.exe artifacts/reicast-win_x64-fast-%APPVEYOR_REPO_COMMIT%.exe
- cmd: copy %EXTRA_PATH%\libgcc_s_seh-1.dll artifacts
- cmd: copy %EXTRA_PATH%\libwinpthread-1.dll artifacts
- cmd: copy %EXTRA_PATH%\libgomp-1.dll artifacts
- cmd: >-
if "%CONFIGURATION%"=="RelWithDebInfo" (cd .. && set EXE_PATH=build\RelWithDebInfo\reicast.exe)
if "%CONFIGURATION%"=="fast" (cd ..\.. && set EXE_PATH=shell\linux\nosym-reicast.exe)
mkdir artifacts
move %EXE_PATH% artifacts\reicast-win_%PLATFORM%-%CONFIGURATION%-%APPVEYOR_REPO_COMMIT%.exe
if "%CONFIGURATION%"=="fast" (copy %EXTRA_PATH%\libgcc_s_seh-1.dll artifacts && copy %EXTRA_PATH%\libwinpthread-1.dll artifacts && copy %EXTRA_PATH%\libgomp-1.dll artifacts)
artifacts:
- path: artifacts
name: reicast-win_x64-fast-$(APPVEYOR_REPO_COMMIT)
name: reicast-win_$(PLATFORM)-$(CONFIGURATION)-$(APPVEYOR_REPO_COMMIT)
deploy:
- provider: S3
@ -35,5 +54,5 @@ deploy:
region: eu-west-1
bucket: reicast-builds-windows
folder: 'builds/heads/$(APPVEYOR_REPO_BRANCH)-$(APPVEYOR_REPO_COMMIT)'
artifact: reicast-win_x64-fast-$(APPVEYOR_REPO_COMMIT)
set_public: true
artifact: reicast-win_$(PLATFORM)-$(CONFIGURATION)-$(APPVEYOR_REPO_COMMIT)
set_public: true

1
core/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/version.h

View File

@ -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)

View File

@ -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;
}

View File

@ -127,10 +127,18 @@
#define DC_PLATFORM_AURORA 6 /* Needs to be done, Uses newer 300 mhz sh4 + 150 mhz pvr mbx SoC */
//HOST_OS
#define OS_WINDOWS 0x10000001
#define OS_LINUX 0x10000002
#define OS_DARWIN 0x10000003
#define OS_IOS 0x10000004
#define OS_ANDROID 0x10000005
#define OS_UWP 0x10000011
#define OS_NSW_HOS 0x80000001
#define OS_PS4_BSD 0x80000002
//HOST_CPU
#define CPU_X86 0x20000001
@ -138,11 +146,16 @@
#define CPU_MIPS 0x20000003
#define CPU_X64 0x20000004
#define CPU_GENERIC 0x20000005 //used for pnacl, emscripten, etc
#define CPU_ARM64 0x20000006
#define CPU_PPC 0x20000006
#define CPU_PPC64 0x20000007
#define CPU_ARM64 0x20000008
#define CPU_MIPS64 0x20000009
//BUILD_COMPILER
#define COMPILER_VC 0x30000001
#define COMPILER_GCC 0x30000002
#define COMPILER_VC 0x30000001
#define COMPILER_GCC 0x30000002
#define COMPILER_CLANG 0x30000003
#define COMPILER_INTEL 0x30000004
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
#define DYNAREC_NONE 0x40000001
@ -152,6 +165,8 @@
//automatic
#ifndef CMAKE_BUILD
#if defined(_WIN32) && !defined(TARGET_WIN86) && !defined(TARGET_WIN64)
#if !defined(_M_AMD64) && !defined(__x86_64__)
#define TARGET_WIN86
@ -233,6 +248,8 @@
#define FEAT_DSPREC DYNAREC_NONE
#endif
#endif // !CMAKE_BUILD
#if defined(TARGET_NO_NIXPROF)
#define FEAT_HAS_NIXPROF 0
@ -286,10 +303,6 @@
#define FEAT_HAS_SOFTREND BUILD_COMPILER == COMPILER_VC //GCC wants us to enable sse4 globaly to enable intrins
#endif
#define RAM_SIZE_MAX (32*1024*1024)
#define VRAM_SIZE_MAX (16*1024*1024)
#define ARAM_SIZE_MAX (8*1024*1024)
//Depricated build configs
#ifdef HOST_NO_REC
#error Dont use HOST_NO_REC
@ -298,3 +311,134 @@
#ifdef HOST_NO_AREC
#error Dont use HOST_NO_AREC
#endif
// Compiler Related
#define COMPILER_VC_OR_CLANG_WIN32 ((BUILD_COMPILER == COMPILER_VC) || (BUILD_COMPILER == COMPILER_CLANG) && defined(WIN32))
#if BUILD_COMPILER!=COMPILER_VC
#define ATTR_USED __attribute__((used))
#define ATTR_UNUSED __attribute__((used))
#else
#define ATTR_USED
#define ATTR_UNUSED
#endif
// Some restrictions on FEAT_NO_RWX_PAGES
#if defined(FEAT_NO_RWX_PAGES) && FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU != CPU_X64 && HOST_CPU != CPU_ARM64
#error "FEAT_NO_RWX_PAGES Only implemented for X64 and ARMv8"
#endif
#endif
// TARGET PLATFORM
#define RAM_SIZE_MAX (32*1024*1024)
#define VRAM_SIZE_MAX (16*1024*1024)
#define ARAM_SIZE_MAX (8*1024*1024)
#if (DC_PLATFORM==DC_PLATFORM_DREAMCAST)
#define BUILD_DREAMCAST 1
//DC : 16 mb ram, 8 mb vram, 2 mb aram, 2 mb bios, 128k flash
#define RAM_SIZE (16*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (2*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define FLASH_SIZE (128*1024)
#define ROM_PREFIX "dc_"
#define ROM_NAMES
#define NVR_OPTIONAL 0
#elif (DC_PLATFORM==DC_PLATFORM_DEV_UNIT)
#define BUILD_DEV_UNIT 1
//Devkit : 32 mb ram, 8? mb vram, 2? mb aram, 2? mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (2*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define FLASH_SIZE (128*1024)
#define ROM_PREFIX "hkt_"
#define ROM_NAMES
#define NVR_OPTIONAL 0
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI)
//Naomi : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (16*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define BBSRAM_SIZE (32*1024)
#define ROM_PREFIX "naomi_"
#define ROM_NAMES ";epr-21576d.bin"
#define NVR_OPTIONAL 1
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI2)
//Naomi2 : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (16*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define BBSRAM_SIZE (32*1024)
#define ROM_PREFIX "n2_"
#define ROM_NAMES
#define NVR_OPTIONAL 1
#elif (DC_PLATFORM==DC_PLATFORM_ATOMISWAVE)
#define BUILD_ATOMISWAVE 1
//Atomiswave : 16 mb ram, 8 mb vram, 8 mb aram, 128kb bios on flash, 128kb battery-backed ram
#define RAM_SIZE (16*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (128*1024)
#define BBSRAM_SIZE (128*1024)
#define ROM_PREFIX "aw_"
#define ROM_NAMES ";bios.ic23_l"
#define NVR_OPTIONAL 1
#else
#error invalid build config
#endif
#define RAM_MASK (RAM_SIZE-1)
#define VRAM_MASK (VRAM_SIZE-1)
#define ARAM_MASK (ARAM_SIZE-1)
#define BIOS_MASK (BIOS_SIZE-1)
#ifdef FLASH_SIZE
#define FLASH_MASK (FLASH_SIZE-1)
#endif
#ifdef BBSRAM_SIZE
#define BBSRAM_MASK (BBSRAM_SIZE-1)
#endif
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
#define AICA_CORE_CLOCK (GD_CLOCK*4/3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
#define ADAC_CLOCK (AICA_CORE_CLOCK/2) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK/2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
#define AICA_SDRAM_CLOCK (GD_CLOCK*2) //[67737600] GD-> PLL 2 -> SDRAM
#define SH4_MAIN_CLOCK (200*1000*1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
#define SH4_RAM_CLOCK (100*1000*1000) //[100000000] XTal(13.5) -> PLL (33.3) -> PLL 1:3 (100) , also suplied to HOLLY chip
#define G2_BUS_CLOCK (25*1000*1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
#if defined(GLES) && !defined(GLES3)
// Only use GL ES 2.0 API functions
#define GLES2
#endif

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

148
core/deps/dirent/dirent.c Normal file
View File

@ -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.
*/

50
core/deps/dirent/dirent.h Normal file
View File

@ -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

6
core/emitter/README.md Normal file
View File

@ -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.

View File

@ -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()

View File

@ -13,11 +13,12 @@
#include <time.h>
VArray2 aica_ram;
VLockedMemory aica_ram;
u32 VREG;//video reg =P
u32 ARMRST;//arm reset reg
u32 rtc_EN=0;
int dma_sched_id;
u32 RealTimeClock;
u32 GetRTC_now()
{
@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
switch( addr & 0xFF )
{
case 0:
return settings.dreamcast.RTC>>16;
return RealTimeClock>>16;
case 4:
return settings.dreamcast.RTC &0xFFFF;
return RealTimeClock &0xFFFF;
case 8:
return 0;
}
@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz)
case 0:
if (rtc_EN)
{
settings.dreamcast.RTC&=0xFFFF;
settings.dreamcast.RTC|=(data&0xFFFF)<<16;
RealTimeClock&=0xFFFF;
RealTimeClock|=(data&0xFFFF)<<16;
rtc_EN=0;
}
return;
case 4:
if (rtc_EN)
{
settings.dreamcast.RTC&=0xFFFF0000;
settings.dreamcast.RTC|= data&0xFFFF;
RealTimeClock&=0xFFFF0000;
RealTimeClock|= data&0xFFFF;
//TODO: Clean the internal timer ?
}
return;
@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
//Init/res/term
void aica_Init()
{
//mmnnn ? gotta fill it w/ something
RealTimeClock = GetRTC_now();
}
void aica_Reset(bool Manual)
{
if (!Manual)
{
aica_ram.Zero();
}
aica_Init();
}
void aica_Term()
@ -183,6 +181,7 @@ int dma_end_sched(int tag, int cycl, int jitt)
SB_ADST = 0x00000000;//dma done
SB_ADLEN = 0x00000000;
// indicate that dma is not happening, or has been paused
SB_ADSUSP |= 0x10;
asic_RaiseInterrupt(holly_SPU_DMA);
@ -190,7 +189,6 @@ int dma_end_sched(int tag, int cycl, int jitt)
return 0;
}
void Write_SB_ADST(u32 addr, u32 data)
{
//0x005F7800 SB_ADSTAG RW AICA:G2-DMA G2 start address
@ -227,14 +225,24 @@ void Write_SB_ADST(u32 addr, u32 data)
WriteMem32_nommu(dst+i,data);
}
*/
// idicate that dma is in progress
SB_ADSUSP &= ~0x10;
// Schedule the end of DMA transfer interrupt
int cycles = len * (SH4_MAIN_CLOCK / 2 / 25000000); // 16 bits @ 25 MHz
if (cycles < 4096)
dma_end_sched(0, 0, 0);
if (!settings.aica.OldSyncronousDma)
{
// Schedule the end of DMA transfer interrupt
int cycles = len * (SH4_MAIN_CLOCK / 2 / 25000000); // 16 bits @ 25 MHz
if (cycles < 4096)
dma_end_sched(0, 0, 0);
else
sh4_sched_request(dma_sched_id, cycles);
}
else
sh4_sched_request(dma_sched_id, cycles);
{
dma_end_sched(0, 0, 0);
}
}
}
}

View File

@ -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();

View File

@ -27,7 +27,7 @@
#include "deps/vixl/aarch64/macro-assembler-aarch64.h"
using namespace vixl::aarch64;
extern void Arm64CacheFlush(void* start, void* end);
extern void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
class DSPAssembler : public MacroAssembler
{
@ -54,9 +54,9 @@ public:
Stp(xzr, xzr, MemOperand(x0, 48));
Ret();
FinalizeCode();
#ifdef _ANDROID
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
#endif
vmem_platform_flush_cache(
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>(),
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
return;
}
@ -387,9 +387,9 @@ public:
#endif
FinalizeCode();
#ifdef _ANDROID
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
#endif
vmem_platform_flush_cache(
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>(),
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
}
private:

View File

@ -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;

View File

@ -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);\

View File

@ -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

View File

@ -378,19 +378,19 @@ struct DCFlashChip : MemChip
else if ((val & 0xff) == 0x30)
{
// sector erase
addr = max(addr, write_protect_size);
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0x3FFF));
memset(&data[addr&(~0x3FFF)],0xFF,0x4000);
#else
// AtomisWave's Macronix 29L001mc has 64k blocks
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0xFFFF));
u8 save[0x2000];
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
memset(&data[addr&(~0xFFFF)], 0xFF, 0x10000);
memcpy(data + 0x1a000, save, 0x2000);
if (addr >= write_protect_size)
{
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
u8 save[0x2000];
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
#endif
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0x3FFF));
memset(&data[addr&(~0x3FFF)],0xFF,0x4000);
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
memcpy(data + 0x1a000, save, 0x2000);
#endif
}
state = FS_Normal;
}
else

8
core/hw/gdrom/README.md Normal file
View File

@ -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

View File

@ -256,6 +256,7 @@ void gd_set_state(gd_states state)
void gd_setdisc()
{
cdda.playing = false;
DiscType newd = (DiscType)libGDR_GetDiscType();
switch(newd)

View File

@ -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)

View File

@ -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
}

View File

@ -206,7 +206,9 @@ T DYNACALL ReadMem_area0(u32 addr)
}
else if (likely((addr>= 0x005F8000) && (addr<=0x005F9FFF))) // :TA / PVR Core Reg.
{
if (sz != 4) return 0; // House of the Dead 2
if (sz != 4)
// House of the Dead 2
return 0;
return (T)pvr_ReadReg(addr);
}
}
@ -215,8 +217,10 @@ T DYNACALL ReadMem_area0(u32 addr)
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
#else
#elif defined(ENABLE_MODEM)
return (T)ModemReadMem_A0_006(addr, sz);
#else
return (T)0;
#endif
}
//map 0x0060 to 0x006F
@ -300,7 +304,7 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
libExtDevice_WriteMem_A0_006(addr, data, sz);
#else
#elif defined(ENABLE_MODEM)
ModemWriteMem_A0_006(addr, data, sz);
#endif
}

View File

@ -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()

View File

@ -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);

View File

@ -7,6 +7,7 @@
#include "hw/naomi/naomi.h"
#include "hw/naomi/naomi_cart.h"
#include "hw/pvr/spg.h"
#include "input/gamepad.h"
#include <time.h>
#include "deps/zlib/zlib.h"
@ -198,6 +199,35 @@ struct maple_base: maple_device
*/
struct maple_sega_controller: maple_base
{
virtual u32 get_capabilities() {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
}
virtual u32 transform_kcode(u32 kcode) {
return kcode;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
switch (index)
{
case 0:
return pjs.trigger[PJTI_R]; // Right trigger
case 1:
return pjs.trigger[PJTI_L]; // Left trigger
case 2:
return pjs.joy[PJAI_X1]; // Stick X
case 3:
return pjs.joy[PJAI_Y1]; // Stick Y
default:
return 0x80; // unused
}
}
virtual MapleDeviceType get_device_type()
{
return MDT_SegaController;
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
//struct data
//3*4
w32( 0xfe060f00);
w32( 0);
w32( 0);
w32(get_capabilities());
w32(0);
w32(0);
//1 area code
w8(0xFF);
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
//state data
//2 key code
w16(pjs.kcode);
w16(transform_kcode(pjs.kcode));
//triggers
//1 R
w8(pjs.trigger[PJTI_R]);
w8(get_analog_axis(0, pjs));
//1 L
w8(pjs.trigger[PJTI_L]);
w8(get_analog_axis(1, pjs));
//joyx
//1
w8(pjs.joy[PJAI_X1]);
w8(get_analog_axis(2, pjs));
//joyy
//1
w8(pjs.joy[PJAI_Y1]);
w8(get_analog_axis(3, pjs));
//not used
//1
w8(0x80);
w8(get_analog_axis(4, pjs));
//1
w8(0x80);
w8(get_analog_axis(5, pjs));
}
return MDRS_DataTransfer;
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
}
};
struct maple_atomiswave_controller: maple_sega_controller
{
virtual u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
}
virtual u32 transform_kcode(u32 kcode) override {
return kcode | AWAVE_TRIGGER_KEY;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
switch (index)
{
case 2:
return pjs.joy[PJAI_X1];
case 3:
return pjs.joy[PJAI_Y1];
case 4:
return pjs.joy[PJAI_X2];
case 5:
return pjs.joy[PJAI_Y2];
default:
return 0x80;
}
}
};
/*
Sega Dreamcast Visual Memory Unit
This is pretty much done (?)
@ -644,9 +706,7 @@ struct maple_sega_vmu: maple_base
}
}
config->SetImage(lcd_data_decoded);
#if !defined(TARGET_PANDORA) && HOST_OS != OS_DARWIN
push_vmu_screen(lcd_data_decoded);
#endif
push_vmu_screen(bus_id, bus_port, lcd_data_decoded);
#if 0
// Update LCD window
if (!dev->lcd.visible)
@ -791,7 +851,7 @@ struct maple_microphone: maple_base
switch (cmd)
{
case MDC_DeviceRequest:
LOGI("maple_microphone::dma MDC_DeviceRequest");
LOGI("maple_microphone::dma MDC_DeviceRequest\n");
//this was copied from the controller case with just the id and name replaced!
//caps
@ -826,7 +886,7 @@ struct maple_microphone: maple_base
case MDCF_GetCondition:
{
LOGI("maple_microphone::dma MDCF_GetCondition");
LOGI("maple_microphone::dma MDCF_GetCondition\n");
//this was copied from the controller case with just the id replaced!
//PlainJoystickState pjs;
@ -863,7 +923,7 @@ struct maple_microphone: maple_base
case MDC_DeviceReset:
//uhhh do nothing?
LOGI("maple_microphone::dma MDC_DeviceReset");
LOGI("maple_microphone::dma MDC_DeviceReset\n");
return MDRS_DeviceReply;
case MDCF_MICControl:
@ -932,7 +992,7 @@ struct maple_microphone: maple_base
LOGI("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword);
return MDRS_DeviceReply;
case MDRE_TransmitAgain:
LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain");
LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransmitAgain\n");
//apparently this doesnt matter
//wptr(micdata, SIZE_OF_MIC_DATA);
return MDRS_DeviceReply;//MDRS_DataTransfer;
@ -1269,6 +1329,10 @@ struct maple_mouse : maple_base
struct maple_lightgun : maple_base
{
virtual u32 transform_kcode(u32 kcode) {
return kcode | 0xFF01;
}
virtual MapleDeviceType get_device_type()
{
return MDT_LightGun;
@ -1317,21 +1381,13 @@ struct maple_lightgun : maple_base
PlainJoystickState pjs;
config->GetInput(&pjs);
// Also use the mouse buttons
if (!(mo_buttons & 4)) // Left button
pjs.kcode &= ~4; // A
if (!(mo_buttons & 2)) // Right button
pjs.kcode &= ~2; // B
if (!(mo_buttons & 8)) // Wheel button
pjs.kcode &= ~8; // Start
//caps
//4
w32(MFID_0_Input);
//state data
//2 key code
w16(pjs.kcode | 0xFF01);
w16(transform_kcode(pjs.kcode));
//not used
//2
@ -1357,6 +1413,13 @@ struct maple_lightgun : maple_base
}
};
struct atomiswave_lightgun : maple_lightgun
{
virtual u32 transform_kcode(u32 kcode) override {
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
}
};
extern u16 kcode[4];
extern s8 joyx[4],joyy[4];
extern u8 rt[4], lt[4];
@ -1383,20 +1446,29 @@ static u16 getRightTriggerAxis()
return rt[0] << 8;
}
NaomiInputMapping Naomi_Mapping = {
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
u32 naomi_button_mapping[] = {
NAOMI_SERVICE_KEY, // DC_BTN_C
NAOMI_BTN1_KEY, // DC_BTN_B
NAOMI_BTN0_KEY, // DC_BTN_A
NAOMI_START_KEY, // DC_BTN_START
NAOMI_UP_KEY, // DC_DPAD_UP
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
NAOMI_TEST_KEY, // DC_BTN_Z
NAOMI_BTN3_KEY, // DC_BTN_Y
NAOMI_BTN2_KEY, // DC_BTN_X
NAOMI_COIN_KEY, // DC_BTN_D
// DC_DPAD2_UP
// DC_DPAD2_DOWN
// DC_DPAD2_LEFT
// DC_DPAD2_RIGHT
};
/*
* Sega JVS I/O board
*/
bool coin_chute;
static bool old_coin_chute;
static int coin_count;
bool naomi_test_button = false;
static bool old_coin_chute[4];
static int coin_count[4];
struct maple_naomi_jamma;
@ -2315,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
{
JVS_STATUS1(); // report byte
LOGJVS("btns ");
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
// FIXME in-lst mapping
u8 buttons[8] = { 0 };
u32 keycode = ~kcode[0];
for (int i = 0; i < 16; i++)
if ((keycode & (1 << i)) != 0)
{
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
}
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
u16 buttons[4] = { 0 };
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
{
u8 *cur_btns = &buttons[(first_player + player) * 2];
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]);
JVS_OUT(cur_btns[0]);
if (buffer_in[cmdi + 2] == 2)
u32 keycode = ~kcode[first_player + player];
for (int i = 0; i < 16; i++)
{
LOGJVS("%02x ", cur_btns[1]);
JVS_OUT(cur_btns[1]);
if ((keycode & (1 << i)) != 0)
buttons[player] |= naomi_button_mapping[i];
}
}
LOGJVS("btns ");
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
{
u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
JVS_OUT(cur_btns >> 8);
if (buffer_in[cmdi + 2] == 2)
{
LOGJVS("%02x ", cur_btns & 0xFF);
JVS_OUT(cur_btns);
}
}
// for (int player = 0; player < jvs_request[channel][cmdi + 1]; player++)
// {
// u32 keycode = ~kcode[player];
// if (keycode & DC_BTN_C)
// keycode |= 0xFFff;
//
// if (jvs_request[channel][cmdi + 2] == 1)
// JVS_OUT(keycode);
// else
// w16(keycode);
// }
cmdi += 3;
}
break;
case 0x21: // Read coins
{
if (coin_chute && !old_coin_chute)
coin_count++;
old_coin_chute = coin_chute;
JVS_STATUS1(); // report byte
LOGJVS("coins ");
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
{
if (slot == 0)
bool coin_chute = false;
u32 keycode = ~kcode[first_player + slot];
for (int i = 0; i < 16 && !coin_chute; i++)
{
LOGJVS("0:%d ", coin_count);
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB
JVS_OUT(coin_count); // coin count LSB
}
else
{
LOGJVS("%d:0 ", slot);
JVS_OUT(0);
JVS_OUT(0);
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
coin_chute = true;
}
if (coin_chute && !old_coin_chute[first_player + slot])
coin_count[first_player + slot] += 1;
old_coin_chute[first_player + slot] = coin_chute;
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
// status (2 highest bits, 0: normal), coin count MSB
JVS_OUT((coin_count[first_player + slot] >> 8) & 0x3F);
// coin count LSB
JVS_OUT(coin_count[first_player + slot]);
}
cmdi += 2;
}
@ -2395,34 +2460,50 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
}
LOGJVS("x,y:%4x,%4x ", x, y);
JVS_OUT(x >> 8); // X, MSB
JVS_OUT(x); // X, LSB
JVS_OUT(x); // X, LSB
JVS_OUT(y >> 8); // Y, MSB
JVS_OUT(y); // Y, LSB
JVS_OUT(y); // Y, LSB
axis = 2;
}
int full_axis_count = 0;
int half_axis_count = 0;
for (; axis < buffer_in[cmdi + 1]; axis++)
{
// FIXME Need to know how many axes per player for proper mapping
u16 axis_value;
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL)
axis_value = Naomi_Mapping.axis[axis + first_player * 4]();
if (NaomiGameInputs != NULL
&& axis < ARRAY_SIZE(NaomiGameInputs->axes)
&& NaomiGameInputs->axes[axis].name != NULL
&& NaomiGameInputs->axes[axis].type == Half)
{
if (half_axis_count == 0)
axis_value = rt[first_player] << 8;
else if (half_axis_count == 1)
axis_value = lt[first_player] << 8;
else
axis_value = 0;
half_axis_count++;
}
else
{
switch (axis) {
switch (full_axis_count) {
case 0:
axis_value = (joyx[first_player + axis / 4] + 128) << 8;
axis_value = (joyx[first_player] + 128) << 8;
break;
case 1:
axis_value = (joyy[first_player + axis / 4] + 128) << 8;
break;
case 2:
axis_value = rt[first_player + axis / 4] << 8;
break;
case 3:
axis_value = lt[first_player + axis / 4] << 8;
axis_value = (joyy[first_player] + 128) << 8;
break;
// TODO right analog stick
// case 2:
// axis_value = (joyrx[first_player] + 128) << 8;
// break;
// case 3:
// axis_value = (joyry[first_player] + 128) << 8;
// break;
default:
axis_value = 128;
}
full_axis_count++;
}
LOGJVS("%d:%4x ", axis, axis_value);
JVS_OUT(axis_value >> 8);
@ -2495,8 +2576,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
break;
case 0x30: // substract coin
if (buffer_in[cmdi + 1] == 1)
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
JVS_STATUS1(); // report byte
cmdi += 4;
break;
@ -2544,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type)
{
case MDT_SegaController:
rv=new maple_sega_controller();
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_sega_controller();
#else
rv = new maple_atomiswave_controller();
#endif
break;
case MDT_Microphone:
@ -2568,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
break;
case MDT_LightGun:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_lightgun();
#else
rv = new atomiswave_lightgun();
#endif
break;
case MDT_NaomiJamma:

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -21,7 +21,6 @@ _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
//upper 8b of the address
void* _vmem_MemInfo_ptr[0x100];
void _vmem_get_ptrs(u32 sz,bool write,void*** vmap,void*** func)
{
*vmap=_vmem_MemInfo_ptr;
@ -385,10 +384,7 @@ void _vmem_reset()
verify(_vmem_register_handler(0,0,0,0,0,0)==0);
}
void _vmem_term()
{
}
void _vmem_term() {}
#include "hw/pvr/pvr_mem.h"
#include "hw/sh4/sh4_mem.h"
@ -409,414 +405,120 @@ void* malloc_pages(size_t size) {
#endif
}
bool _vmem_reserve_nonvmem()
{
virt_ram_base = 0;
p_sh4rcb=(Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)malloc_pages(RAM_SIZE);
vram.size=VRAM_SIZE;
vram.data=(u8*)malloc_pages(VRAM_SIZE);
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)malloc_pages(ARAM_SIZE);
return true;
}
void _vmem_bm_reset_nvmem();
// Resets the FPCB table (by either clearing it to the default val
// or by flushing it and making it fault on access again.
void _vmem_bm_reset() {
if (virt_ram_base) {
#if !defined(TARGET_NO_NVMEM)
_vmem_bm_reset_nvmem();
#endif
}
#ifndef TARGET_IPHONE
if (!virt_ram_base)
#endif
{
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, FPCB_SIZE);
}
// If we allocated it via vmem:
if (virt_ram_base)
vmem_platform_reset_mem(p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
else
// We allocated it via a regular malloc/new/whatever on the heap
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
}
static void _vmem_release_nonvmem()
{
free(p_sh4rcb);
free(vram.data);
free(aica_ram.data);
free(mem_b.data);
}
// This gets called whenever there is a pagefault, it is possible that it lands
// on the fpcb memory range, which is allocated on miss. Returning true tells the
// fault handler this was us, and that the page is resolved and can continue the execution.
bool BM_LockedWrite(u8* address) {
if (!virt_ram_base)
return false; // No vmem, therefore not us who caused this.
#if !defined(TARGET_NO_NVMEM)
uintptr_t ptrint = (uintptr_t)address;
uintptr_t start = (uintptr_t)p_sh4rcb->fpcb;
uintptr_t end = start + sizeof(p_sh4rcb->fpcb);
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
#if HOST_OS==OS_WINDOWS
#include <Windows.h>
HANDLE mem_handle;
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
rv= MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!rv)
return 0;
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!ptr) return 0;
}
return rv;
}
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=VirtualAlloc(&virt_ram_base[start],end-start,MEM_RESERVE,PAGE_NOACCESS);
if (ptr == 0)
return 0;
return ptr;
}
void* _nvmem_alloc_mem()
{
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
void* rv= (u8*)VirtualAlloc(0, 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX, MEM_RESERVE, PAGE_NOACCESS);
if (rv) VirtualFree(rv,0,MEM_RELEASE);
return rv;
}
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#endif
int ashmem_create_region(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
if (name) {
char buf[ASHMEM_NAME_LEN];
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
if (ret < 0)
goto error;
}
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
goto error;
return fd;
error:
close(fd);
return ret;
}
#endif
int fd;
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=mmap(&virt_ram_base[start], end-start, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
if (MAP_FAILED==ptr)
return 0;
return ptr;
}
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
printf("MAP %08X w/ %d\n",dst,offset);
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
u32 prot=PROT_READ|(w?PROT_WRITE:0);
rv= mmap(&virt_ram_base[dst], size, prot, MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==rv || rv!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP1 failed %d\n",errno);
return 0;
}
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=mmap(&virt_ram_base[dst], size, prot , MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==ptr || ptr!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP2 failed %d\n",errno);
return 0;
}
}
return rv;
}
void* _nvmem_alloc_mem()
{
#if HOST_OS == OS_DARWIN
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#elif !defined(_ANDROID)
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
if (fd==-1)
{
fd = open("dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("dcnzorz_mem");
}
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#else
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
if (false)//this causes writebacks to flash -> slow and stuttery
{
fd = open("/data/data/com.reicast.emulator/files/dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("/data/data/com.reicast.emulator/files/dcnzorz_mem");
}
#endif
u32 sz = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void* rv=mmap(0, sz, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
verify(rv != NULL);
munmap(rv,sz);
return (u8*)rv + 0x10000 - unat(rv)%0x10000;//align to 64 KB (Needed for linaro mmap not to extend to next region)
}
#endif
#define map_buffer(dsts,dste,offset,sz,w) {ptr=_nvmem_map_buffer(dsts,dste-dsts,offset,sz,w);if (!ptr) return false;}
#define unused_buffer(start,end) {ptr=_nvmem_unused_buffer(start,end);if (!ptr) return false;}
u32 pagecnt;
void _vmem_bm_reset_nvmem()
{
#if defined(TARGET_NO_NVMEM)
return;
#endif
#ifdef TARGET_IPHONE
//On iOS & nacl we allways allocate all of the mapping table
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_READ | PROT_WRITE);
return;
#endif
pagecnt=0;
#if HOST_OS==OS_WINDOWS
VirtualFree(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MEM_DECOMMIT);
#else
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_NONE);
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_DONTNEED);
#ifdef MADV_REMOVE
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_REMOVE);
#else
//OSX, IOS
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_FREE);
#endif
#endif
printf("Freeing fpcb\n");
}
bool BM_LockedWrite(u8* address)
{
if (!_nvmem_enabled())
return false;
#if FEAT_SHREC != DYNAREC_NONE
u32 addr=address-(u8*)p_sh4rcb->fpcb;
address=(u8*)p_sh4rcb->fpcb+ (addr&~PAGE_MASK);
if (addr<sizeof(p_sh4rcb->fpcb))
{
//printf("Allocated %d PAGES [%08X]\n",++pagecnt,addr);
#if HOST_OS==OS_WINDOWS
verify(VirtualAlloc(address,PAGE_SIZE,MEM_COMMIT,PAGE_READWRITE));
#else
mprotect (address, PAGE_SIZE, PROT_READ | PROT_WRITE);
#endif
bm_vmem_pagefill((void**)address,PAGE_SIZE);
if (ptrint >= start && ptrint < end) {
// Alloc the page then and initialize it to default values
void *aligned_addr = (void*)(ptrint & (~PAGE_MASK));
vmem_platform_ondemand_page(aligned_addr, PAGE_SIZE);
bm_vmem_pagefill((void**)aligned_addr, PAGE_SIZE);
return true;
}
#else
die("BM_LockedWrite and NO REC");
#endif
return false;
}
bool _vmem_reserve()
{
void* ptr=0;
bool _vmem_reserve() {
// TODO: Static assert?
verify((sizeof(Sh4RCB)%PAGE_SIZE)==0);
if (settings.dynarec.disable_nvmem)
return _vmem_reserve_nonvmem();
VMemType vmemstatus = MemTypeError;
virt_ram_base=(u8*)_nvmem_alloc_mem();
// Use vmem only if settings mandate so, and if we have proper exception handlers.
#ifndef TARGET_NO_EXCEPTIONS
if (!settings.dynarec.disable_nvmem)
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
#endif
if (virt_ram_base==0)
return _vmem_reserve_nonvmem();
p_sh4rcb=(Sh4RCB*)virt_ram_base;
// Fallback to statically allocated buffers, this results in slow-ops being generated.
if (vmemstatus == MemTypeError) {
printf("Warning! nvmem is DISABLED (due to failure or not being built-in\n");
virt_ram_base = 0;
// Map the sh4 context but protect access to Sh4RCB.fpcb[]
#if HOST_OS==OS_WINDOWS
//verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE));
verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE,PAGE_NOACCESS));
// Allocate it all and initialize it.
p_sh4rcb = (Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
verify(VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),MEM_COMMIT,PAGE_READWRITE));
#else
verify(p_sh4rcb==mmap(p_sh4rcb,sizeof(Sh4RCB),PROT_NONE,MAP_PRIVATE | MAP_ANON, -1, 0));
mprotect((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),PROT_READ|PROT_WRITE);
#endif
virt_ram_base+=sizeof(Sh4RCB);
mem_b.size = RAM_SIZE;
mem_b.data = (u8*)malloc_pages(RAM_SIZE);
//Area 0
//[0x00000000 ,0x00800000) -> unused
unused_buffer(0x00000000,0x00800000);
vram.size = VRAM_SIZE;
vram.data = (u8*)malloc_pages(VRAM_SIZE);
//I wonder, aica ram warps here ?.?
//I really should check teh docs before codin ;p
//[0x00800000,0x00A00000);
map_buffer(0x00800000,0x01000000,MAP_ARAM_START_OFFSET,ARAM_SIZE,false);
map_buffer(0x20000000,0x20000000+ARAM_SIZE,MAP_ARAM_START_OFFSET,ARAM_SIZE,true);
aica_ram.size = ARAM_SIZE;
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
}
else {
printf("Info: nvmem is enabled, with addr space of size %s\n", vmemstatus == MemType4GB ? "4GB" : "512MB");
printf("Info: p_sh4rcb: %p virt_ram_base: %p\n", p_sh4rcb, virt_ram_base);
// Map the different parts of the memory file into the new memory range we got.
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
const vmem_mapping mem_mappings[] = {
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica, wraps too
{0x20000000, 0x20000000+ARAM_SIZE, MAP_ARAM_START_OFFSET, ARAM_SIZE, true},
{0x01000000, 0x04000000, 0, 0, false}, // More unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], sizeof(mem_mappings) / sizeof(mem_mappings[0]));
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)ptr;
//[0x01000000 ,0x04000000) -> unused
unused_buffer(0x01000000,0x04000000);
// Point buffers to actual data pointers
aica_ram.size = ARAM_SIZE;
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writtable AICA addrspace
//Area 1
//[0x04000000,0x05000000) -> vram (16mb, warped on dc)
map_buffer(0x04000000,0x05000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
vram.size=VRAM_SIZE;
vram.data=(u8*)ptr;
vram.size = VRAM_SIZE;
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writtable and lockable)
//[0x05000000,0x06000000) -> unused (32b path)
unused_buffer(0x05000000,0x06000000);
//[0x06000000,0x07000000) -> vram mirror
map_buffer(0x06000000,0x07000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
//[0x07000000,0x08000000) -> unused (32b path) mirror
unused_buffer(0x07000000,0x08000000);
//Area 2
//[0x08000000,0x0C000000) -> unused
unused_buffer(0x08000000,0x0C000000);
//Area 3
//[0x0C000000,0x0D000000) -> main ram
//[0x0D000000,0x0E000000) -> main ram mirror
//[0x0E000000,0x0F000000) -> main ram mirror
//[0x0F000000,0x10000000) -> main ram mirror
map_buffer(0x0C000000,0x10000000,MAP_RAM_START_OFFSET,RAM_SIZE,true);
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)ptr;
//Area 4
//Area 5
//Area 6
//Area 7
//all -> Unused
//[0x10000000,0x20000000) -> unused
unused_buffer(0x10000000,0x20000000);
printf("vmem reserve: base: %08X, aram: %08x, vram: %08X, ram: %08X\n",virt_ram_base,aica_ram.data,vram.data,mem_b.data);
mem_b.size = RAM_SIZE;
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
}
// Clear out memory
aica_ram.Zero();
vram.Zero();
mem_b.Zero();
printf("Mem alloc successful!\n");
return virt_ram_base!=0;
return true;
}
void _vmem_release()
{
if (!_nvmem_enabled())
_vmem_release_nonvmem();
else
{
if (virt_ram_base != NULL)
{
#if HOST_OS == OS_WINDOWS
VirtualFree(virt_ram_base, 0, MEM_RELEASE);
#else
munmap(virt_ram_base, 0x20000000);
#endif
virt_ram_base = NULL;
}
#if HOST_OS != OS_WINDOWS
close(fd);
#endif
#define freedefptr(x) \
if (x) { free(x); x = NULL; }
void _vmem_release() {
if (virt_ram_base)
vmem_platform_destroy();
else {
freedefptr(p_sh4rcb);
freedefptr(vram.data);
freedefptr(aica_ram.data);
freedefptr(mem_b.data);
}
}
#else
bool _vmem_reserve()
{
return _vmem_reserve_nonvmem();
}
void _vmem_release()
{
_vmem_release_nonvmem();
}
#endif

View File

@ -1,6 +1,41 @@
#pragma once
#include "types.h"
enum VMemType {
MemType4GB,
MemType512MB,
MemTypeError
};
struct vmem_mapping {
u32 start_address, end_address;
unsigned memoffset, memsize;
bool allow_writes;
};
// Platform specific vmemory API
// To initialize (maybe) the vmem subsystem
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
// To reset the on-demand allocated pages.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
// To handle a fault&allocate an ondemand page.
void vmem_platform_ondemand_page(void *address, unsigned size_bytes);
// To create the mappings in the address space.
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps);
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy();
// Given a block of data in the .text section, prepares it for JIT action.
// both code_area and size are page aligned. Returns success.
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rwx);
// Same as above but uses two address spaces one with RX and RW protections.
// Note: this function doesnt have to be implemented, it's a fallback for the above one.
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rw, uintptr_t *rx_offset);
// This might not need an implementation (ie x86/64 cpus).
void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
// Note: if you want to disable vmem magic in any given platform, implement the
// above functions as empty functions and make vmem_platform_init return MemTypeError.
//Typedef's
//ReadMem
typedef u8 DYNACALL _vmem_ReadMem8FP(u32 Address);
@ -70,4 +105,4 @@ static inline bool _nvmem_enabled() {
return virt_ram_base != 0;
}
void _vmem_bm_reset();
void _vmem_bm_reset();

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -28,11 +28,11 @@ bool bios_loaded = false;
#include <errno.h>
#endif
fd_t* RomCacheMap;
fd_t* RomCacheMap = NULL;
u32 RomCacheMapCount;
char naomi_game_id[33];
InputDescriptors *naomi_game_inputs;
InputDescriptors *NaomiGameInputs;
u8 *naomi_default_eeprom;
extern RomChip sys_rom;
@ -246,7 +246,7 @@ static bool naomi_cart_LoadZip(char *filename)
break;
}
CurrentCartridge->SetKey(game->key);
naomi_game_inputs = game->inputs;
NaomiGameInputs = game->inputs;
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
{
@ -636,11 +636,11 @@ bool naomi_cart_SelectFile()
if (!naomi_cart_LoadRom(SelectedFile))
{
printf("Cannot load %s: error %d\n", SelectedFile, errno);
cfgSetVirtual("config", "image", "");
return false;
}
cfgSaveStr("emu", "gamefile", SelectedFile);
return true;
}

View File

@ -110,6 +110,6 @@ struct InputDescriptors
AxisDescriptor axes[8];
};
extern InputDescriptors *naomi_game_inputs;
extern InputDescriptors *NaomiGameInputs;
#endif //NAOMI_CART_H

View File

@ -82,8 +82,7 @@ bool renderer_enabled = true; // Signals the renderer thread to exit
bool renderer_changed = false; // Signals the renderer thread to switch renderer
#if !defined(TARGET_NO_THREADS)
cResetEvent rs(false,true);
cResetEvent re(false,true);
cResetEvent rs, re;
#endif
int max_idx,max_mvo,max_op,max_pt,max_tr,max_vtx,max_modt, ovrn;
@ -99,6 +98,7 @@ TA_context* _pvrrc;
void SetREP(TA_context* cntx);
void killtex();
bool render_output_framebuffer();
static void rend_create_renderer();
void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
FILE* fw = fopen(file, "wb");
@ -267,6 +267,13 @@ bool rend_frame(TA_context* ctx, bool draw_osd) {
bool rend_single_frame()
{
if (renderer_changed)
{
renderer_changed = false;
rend_term_renderer();
rend_create_renderer();
rend_init_renderer();
}
//wait render start only if no frame pending
do
{
@ -363,6 +370,7 @@ void rend_init_renderer()
}
printf("Selected renderer initialization failed. Falling back to default renderer.\n");
renderer = fallback_renderer;
fallback_renderer = NULL; // avoid double-free
}
}
@ -378,7 +386,6 @@ void rend_term_renderer()
delete fallback_renderer;
fallback_renderer = NULL;
}
tactx_Term();
}
void* rend_thread(void* p)
@ -392,13 +399,6 @@ void* rend_thread(void* p)
{
if (rend_single_frame())
renderer->Present();
if (renderer_changed)
{
renderer_changed = false;
rend_term_renderer();
rend_create_renderer();
rend_init_renderer();
}
}
rend_term_renderer();
@ -539,6 +539,7 @@ void rend_end_render()
void rend_stop_renderer()
{
renderer_enabled = false;
tactx_Term();
}
void rend_vblank()

View File

@ -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

View File

@ -88,6 +88,8 @@ double full_rps;
static u32 lightgun_line = 0xffff;
static u32 lightgun_hpos;
double mspdf;
u32 fskip=0;
//called from sh4 context , should update pvr/ta state and everything else
int spg_line_sched(int tag, int cycl, int jit)
@ -174,7 +176,7 @@ int spg_line_sched(int tag, int cycl, int jit)
}
double frames_done=spd_cpu/2;
double mspdf=1/frames_done*1000;
mspdf=1/frames_done*1000;
full_rps=(spd_fps+fskip/ts);

View File

@ -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;

View File

@ -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;

View File

@ -86,49 +86,55 @@ u32 bm_gc_luc,bm_gcf_luc;
#define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
// This returns an executable address
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
{
//rdv_FailedToFindBlock_pc=addr;
DynarecCodeEntryPtr rv=(DynarecCodeEntryPtr)FPCA(addr);
DynarecCodeEntryPtr rv = (DynarecCodeEntryPtr)FPCA(addr);
return (DynarecCodeEntryPtr)rv;
}
// This returns an executable address
DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr)
{
return (DynarecCodeEntryPtr)bm_GetCode(addr);
}
// This returns an executable address
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr)
{
DynarecCodeEntryPtr cde=bm_GetCode(addr);
DynarecCodeEntryPtr cde = bm_GetCode(addr); // Returns RX ptr
if (cde==ngen_FailedToFindBlock)
if (cde == ngen_FailedToFindBlock)
return 0;
else
return bm_GetBlock((void*)cde);
return bm_GetBlock((void*)cde); // Returns RX pointer
}
// This takes a RX address and returns the info block ptr (RW space)
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code)
{
blkmap_t::iterator iter=blkmap.find((RuntimeBlockInfo*)dynarec_code);
if (iter!=blkmap.end())
void *dynarecrw = CC_RX2RW(dynarec_code);
blkmap_t::iterator iter = blkmap.find((RuntimeBlockInfo*)dynarecrw);
if (iter != blkmap.end())
{
verify((*iter)->contains_code((u8*)dynarec_code));
verify((*iter)->contains_code((u8*)dynarecrw));
return *iter;
}
else
{
printf("bm_GetBlock(%p) failed ..\n",dynarec_code);
printf("bm_GetBlock(%p) failed ..\n", dynarec_code);
return 0;
}
}
// Takes RX pointer and returns a RW pointer
RuntimeBlockInfo* bm_GetStaleBlock(void* dynarec_code)
{
void *dynarecrw = CC_RX2RW(dynarec_code);
for(u32 i=0;i<del_blocks.size();i++)
{
if (del_blocks[i]->contains_code((u8*)dynarec_code))
if (del_blocks[i]->contains_code((u8*)dynarecrw))
return del_blocks[i];
}
@ -145,9 +151,8 @@ void bm_AddBlock(RuntimeBlockInfo* blk)
}
blkmap.insert(blk);
verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock);
FPCA(blk->addr)=blk->code;
FPCA(blk->addr) = (DynarecCodeEntryPtr)CC_RW2RX(blk->code);
#ifdef DYNA_OPROF
if (oprofHandle)
@ -304,6 +309,8 @@ void bm_Rebuild()
{
return;
die("this is broken in multiple levels, including compile options");
void RASDASD();
RASDASD();
@ -321,7 +328,7 @@ void bm_Rebuild()
//constprop(all_blocks[i]);
//#endif
}
ngen_Compile(all_blocks[i],false,false,all_blocks[i]->staging_runs>0,do_opts);
ngen_Compile(all_blocks[i],NoCheck,false,all_blocks[i]->staging_runs>0,do_opts);
blkmap.insert(all_blocks[i]);
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);
@ -337,9 +344,9 @@ void bm_Rebuild()
rebuild_counter=30;
}
void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ)
void bm_vmem_pagefill(void** ptr, u32 size_bytes)
{
for (size_t i=0; i<PAGE_SZ/sizeof(ptr[0]); i++)
for (size_t i=0; i < size_bytes / sizeof(ptr[0]); i++)
{
ptr[i]=(void*)ngen_FailedToFindBlock;
}

View File

@ -86,7 +86,7 @@ void bm_WriteBlockMap(const string& file);
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr);
extern "C" {
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
ATTR_USED DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
}
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code);

View File

@ -1,18 +1,12 @@
#include "types.h"
#if HOST_OS==OS_WINDOWS
#include <windows.h>
#elif HOST_OS==OS_LINUX
#include <unistd.h>
#include <sys/mman.h>
#endif
#include "../sh4_interpreter.h"
#include "../sh4_opcode_list.h"
#include "../sh4_core.h"
#include "../sh4_if.h"
#include "hw/sh4/sh4_interrupts.h"
#include "hw/mem/_vmem.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/pvr/pvr_mem.h"
#include "hw/aica/aica_if.h"
@ -26,9 +20,7 @@
#include "decoder.h"
#if FEAT_SHREC != DYNAREC_NONE
//uh uh
#if !defined(_WIN64)
u8 SH4_TCB[CODE_SIZE+4096]
#if HOST_OS == OS_WINDOWS || FEAT_SHREC != DYNAREC_JIT
;
@ -39,10 +31,9 @@ u8 SH4_TCB[CODE_SIZE+4096]
#else
#error SH4_TCB ALLOC
#endif
#endif
u8* CodeCache;
uintptr_t cc_rx_offset;
u32 LastAddr;
u32 LastAddr_min;
@ -86,6 +77,15 @@ void recSh4_Run()
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx);
printf("cntx // fpcb offset: %td // pc offset: %td // pc %08X\n",(u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb,sh4rcb.cntx.pc);
if (!settings.dynarec.safemode)
printf("Warning: Dynarec safe mode is off\n");
if (settings.dynarec.unstable_opt)
printf("Warning: Unstable optimizations is on\n");
if (settings.dynarec.SmcCheckLevel != FullCheck)
printf("Warning: SMC check mode is %d\n", settings.dynarec.SmcCheckLevel);
verify(rcb_noffs(&next_pc)==-184);
ngen_mainloop(sh4_dyna_rcb);
@ -119,34 +119,51 @@ u32 emit_FreeSpace()
}
bool DoCheck(u32 pc)
SmcCheckEnum DoCheck(u32 pc)
{
if (IsOnRam(pc))
{
if (!settings.dynarec.unstable_opt)
return true;
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
switch (settings.dynarec.SmcCheckLevel) {
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
// Heuristic-elimintaed FastChecks
case NoCheck: {
if (IsOnRam(pc))
{
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
return true;
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
default:
return false;
return FastCheck;
default:
return NoCheck;
}
}
return NoCheck;
}
break;
// Fast Check everything
case FastCheck:
return FastCheck;
// Full Check everything
case FullCheck:
return FullCheck;
default:
die("Unhandled settings.dynarec.SmcCheckLevel");
return FullCheck;
}
return false;
}
void AnalyseBlock(RuntimeBlockInfo* blk);
@ -249,7 +266,7 @@ DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
//printf("rdv_FailedToFindBlock ~ %08X\n",pc);
next_pc=pc;
return rdv_CompilePC();
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC());
}
static void ngen_FailedToFindBlock_internal() {
@ -288,35 +305,27 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 pc)
{
next_pc=pc;
recSh4_ClearCache();
return rdv_CompilePC();
}
DynarecCodeEntryPtr rdv_FindCode()
{
DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
if (rv==ngen_FailedToFindBlock)
return 0;
return rv;
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC());
}
DynarecCodeEntryPtr rdv_FindOrCompile()
{
DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
if (rv==ngen_FailedToFindBlock)
rv=rdv_CompilePC();
DynarecCodeEntryPtr rv = bm_GetCode(next_pc); // Returns exec addr
if (rv == ngen_FailedToFindBlock)
rv = (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC()); // Returns rw addr
return rv;
}
void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
{
RuntimeBlockInfo* rbi=bm_GetBlock(code);
// code is the RX addr to return after, however bm_GetBlock returns RW
RuntimeBlockInfo* rbi = bm_GetBlock(code);
if (!rbi)
{
printf("Stale block ..");
rbi=bm_GetStaleBlock(code);
rbi = bm_GetStaleBlock(code);
}
verify(rbi != NULL);
@ -339,7 +348,7 @@ void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
next_pc=rbi->NextBlock;
}
DynarecCodeEntryPtr rv=rdv_FindOrCompile();
DynarecCodeEntryPtr rv = rdv_FindOrCompile(); // Returns rx ptr
bool do_link=bm_GetBlock(code)==rbi;
@ -429,56 +438,23 @@ void recSh4_Init()
if (_nvmem_enabled()) {
verify(mem_b.data==((u8*)p_sh4rcb->sq_buffer+512+0x0C000000));
}
#if defined(_WIN64)
#ifdef _MSC_VER
for (int i = 10; i < 1300; i++) {
// Prepare some pointer to the pre-allocated code cache:
void *candidate_ptr = (void*)(((unat)SH4_TCB + 4095) & ~4095);
//align to next page ..
u8* ptr = (u8*)recSh4_Init - i * 1024 * 1024;
CodeCache = (u8*)VirtualAlloc(ptr, CODE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);//; (u8*)(((unat)SH4_TCB+4095)& ~4095);
if (CodeCache)
break;
}
#else
CodeCache = (u8*)VirtualAlloc(NULL, CODE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#endif
verify(CodeCache != NULL);
#else
CodeCache = (u8*)(((unat)SH4_TCB+4095)& ~4095);
#endif
#if HOST_OS == OS_DARWIN
munmap(CodeCache, CODE_SIZE);
CodeCache = (u8*)mmap(CodeCache, CODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
#endif
#if HOST_OS == OS_WINDOWS
DWORD old;
VirtualProtect(CodeCache,CODE_SIZE,PAGE_EXECUTE_READWRITE,&old);
#elif HOST_OS == OS_LINUX || HOST_OS == OS_DARWIN
printf("\n\t CodeCache addr: %p | from: %p | addr here: %p\n", CodeCache, CodeCache, recSh4_Init);
#if FEAT_SHREC == DYNAREC_JIT
if (mprotect(CodeCache, CODE_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC))
{
perror("\n\tError,Couldnt mprotect CodeCache!");
die("Couldnt mprotect CodeCache");
}
// Call the platform-specific magic to make the pages RWX
CodeCache = NULL;
#ifdef FEAT_NO_RWX_PAGES
verify(vmem_platform_prepare_jit_block(candidate_ptr, CODE_SIZE, (void**)&CodeCache, &cc_rx_offset));
#else
verify(vmem_platform_prepare_jit_block(candidate_ptr, CODE_SIZE, (void**)&CodeCache));
#endif
// Ensure the pointer returned is non-null
verify(CodeCache != NULL);
#if TARGET_IPHONE
memset((u8*)mmap(CodeCache, CODE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0),0xFF,CODE_SIZE);
#else
memset(CodeCache,0xFF,CODE_SIZE);
#endif
#endif
memset(CodeCache, 0xFF, CODE_SIZE);
ngen_init();
bm_Reset();
}
void recSh4_Term()
@ -506,4 +482,5 @@ void Get_Sh4Recompiler(sh4_if* rv)
rv->IsCpuRunning = recSh4_IsCpuRunning;
rv->ResetCache = recSh4_ClearCache;
}
#endif
#endif // FEAT_SHREC != DYNAREC_NONE

View File

@ -48,6 +48,19 @@
#define CODE_SIZE (10*1024*1024)
// When NO_RWX is enabled there's two address-spaces, one executable and
// one writtable. The emitter and most of the code in rec-* will work with
// the RW pointer. However the fpcb table and other pointers during execution
// (ie. exceptions) are RX pointers. These two macros convert between them by
// sub/add the pointer offset. CodeCache will point to the RW pointer for simplicity.
#ifdef FEAT_NO_RWX_PAGES
extern uintptr_t cc_rx_offset;
#define CC_RW2RX(ptr) (void*)(((uintptr_t)(ptr)) + cc_rx_offset)
#define CC_RX2RW(ptr) (void*)(((uintptr_t)(ptr)) - cc_rx_offset)
#else
#define CC_RW2RX(ptr) (ptr)
#define CC_RX2RW(ptr) (ptr)
#endif
//alternative emit ptr, set to 0 to use the main buffer
extern u32* emit_ptr;
@ -85,7 +98,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
void ngen_init();
//Called to compile a block
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise);
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise);
//Called when blocks are reseted
void ngen_ResetBlocks();

View File

@ -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

View File

@ -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--;
}
}

View File

@ -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();

View File

@ -12,6 +12,8 @@
//Types
#define printf_smc(...) // printf
u32 CCN_QACR_TR[2];
@ -72,13 +74,18 @@ void CCN_CCR_write(u32 addr, u32 value)
temp.reg_data=value;
//what is 0xAC13DBF8 from ?
if (temp.ICI && curr_pc!=0xAC13DBF8)
{
//printf("Sh4: i-cache invalidation %08X\n",curr_pc);
// Shikigami No Shiro II sets ICI frequently
// Any reason to flush the dynarec cache for this?
//sh4_cpu.ResetCache();
if (temp.ICI) {
printf_smc("Sh4: i-cache invalidation %08X\n",curr_pc);
if (settings.dynarec.SmcCheckLevel != FullCheck) {
//TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
//which game is 0xAC13DBF8 from ?
if (curr_pc != 0xAC13DBF8)
{
printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
sh4_cpu.ResetCache();
}
}
}
temp.ICI=0;

View File

@ -314,7 +314,7 @@ struct Sh4RCB
Sh4Context cntx;
};
extern Sh4RCB* p_sh4rcb;
extern "C" Sh4RCB* p_sh4rcb;
extern u8* sh4_dyna_rcb;
INLINE u32 sh4_sr_GetFull()

View File

@ -61,6 +61,7 @@ void ExecuteDelayslot_RTE();
extern "C" {
int UpdateSystem();
__attribute__((used)) int UpdateSystem_INTC();
ATTR_USED int UpdateSystem_INTC();
}

View File

@ -17,7 +17,7 @@
//main system mem
VArray2 mem_b;
VLockedMemory mem_b;
void _vmem_init();
void _vmem_reset();

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -3,10 +3,22 @@
#include <sstream>
#include <algorithm>
// On windows, transform / to \\
string normalize_path_separator(string path)
{
#if HOST_OS == OS_WINDOWS
std::replace(path.begin(), path.end(), '/', '\\');
#endif
return path;
}
// given file/name.ext or file\name.ext returns file/ or file\, depending on the platform
// given name.ext returns ./ or .\, depending on the platform
string OS_dirname(string file)
{
file = normalize_path_separator(file);
#if HOST_OS == OS_WINDOWS
const char sep = '\\';
#else
@ -25,19 +37,6 @@ string OS_dirname(string file)
return file.substr(0, last_slash + 1);
}
// On windows, transform / to \\
// On linux, transform \\ to /
string normalize_path_separator(string path)
{
#if HOST_OS == OS_WINDOWS
std::replace( path.begin(), path.end(), '/', '\\');
#else
std::replace( path.begin(), path.end(), '\\', '/');
#endif
return path;
}
#if 0 // TODO: Move this to some tests, make it platform agnostic
namespace {
struct OS_dirname_Test {

View File

@ -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

View File

@ -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,
};

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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";
}

View File

@ -408,7 +408,6 @@ int main(int argc, wchar* argv[])
#endif
int get_mic_data(u8* buffer) { return 0; }
int push_vmu_screen(u8* buffer) { return 0; }
void os_DebugBreak()
{

View File

@ -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

View File

@ -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();
}

View File

@ -23,10 +23,6 @@
#include <sys/personality.h>
#include <dlfcn.h>
#endif
#if HOST_OS == OS_DARWIN
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#include <unistd.h>
#include "hw/sh4/dyna/blockmanager.h"
@ -57,19 +53,14 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
}
#endif
#if !defined(TARGET_NO_EXCEPTIONS)
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
{
rei_host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
bool dyna_cde = ((unat)ctx.pc>(unat)CodeCache) && ((unat)ctx.pc<(unat)(CodeCache + CODE_SIZE));
bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE));
//ucontext_t* ctx=(ucontext_t*)ctxr;
//printf("mprot hit @ ptr 0x%08X @@ code: %08X, %d\n",si->si_addr,ctx->uc_mcontext.arm_pc,dyna_cde);
if (VramLockedWrite((u8*)si->si_addr) || BM_LockedWrite((u8*)si->si_addr))
return;
#if FEAT_SHREC == DYNAREC_JIT
@ -108,12 +99,9 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
signal(SIGSEGV, SIG_DFL);
}
}
#endif
#endif
void install_fault_handler (void)
void install_fault_handler(void)
{
#if !defined(TARGET_NO_EXCEPTIONS)
struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = fault_handler;
@ -127,172 +115,14 @@ void install_fault_handler (void)
act.sa_sigaction = sigill_handler;
sigaction(SIGILL, &act, &segv_oact);
#endif
#endif
}
#if !defined(TARGET_NO_THREADS)
//Thread class
cThread::cThread(ThreadEntryFP* function,void* prm)
{
Entry=function;
param=prm;
}
void cThread::Start()
{
pthread_create( (pthread_t*)&hThread, NULL, Entry, param);
}
void cThread::WaitToEnd()
{
pthread_join((pthread_t)hThread,0);
}
//End thread class
#endif
//cResetEvent Calss
cResetEvent::cResetEvent(bool State,bool Auto)
{
//sem_init((sem_t*)hEvent, 0, State?1:0);
verify(State==false&&Auto==true);
pthread_mutex_init(&mutx, NULL);
pthread_cond_init(&cond, NULL);
}
cResetEvent::~cResetEvent()
{
//Destroy the event object ?
}
void cResetEvent::Set()//Signal
{
pthread_mutex_lock( &mutx );
state=true;
pthread_cond_signal( &cond);
pthread_mutex_unlock( &mutx );
}
void cResetEvent::Reset()//reset
{
pthread_mutex_lock( &mutx );
state=false;
pthread_mutex_unlock( &mutx );
}
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
struct timespec ts;
#if HOST_OS == OS_DARWIN
// OSX doesn't have clock_gettime.
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
ts.tv_sec += msec / 1000;
ts.tv_nsec += (msec % 1000) * 1000000;
while (ts.tv_nsec > 1000000000)
{
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
pthread_cond_timedwait( &cond, &mutx, &ts );
}
bool rc = state;
state=false;
pthread_mutex_unlock( &mutx );
return rc;
}
void cResetEvent::Wait()//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
pthread_cond_wait( &cond, &mutx );
}
state=false;
pthread_mutex_unlock( &mutx );
}
//End AutoResetEvent
#else // !defined(TARGET_NO_EXCEPTIONS)
// No exceptions/nvmem dummy handlers.
void install_fault_handler(void) {}
#endif // !defined(TARGET_NO_EXCEPTIONS)
#include <errno.h>
void VArray2::LockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ );
if (rv!=0)
{
printf("mprotect(%8s,%08X,R) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: LockRegion\n");
#endif
}
void print_mem_addr()
{
FILE *ifp, *ofp;
char outputFilename[] = "/data/data/com.reicast.emulator/files/mem_alloc.txt";
ifp = fopen("/proc/self/maps", "r");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file /proc/self/maps!\n");
exit(1);
}
ofp = fopen(outputFilename, "w");
if (ofp == NULL) {
fprintf(stderr, "Can't open output file %s!\n",
outputFilename);
#if HOST_OS == OS_LINUX
ofp = stderr;
#else
exit(1);
#endif
}
char line [ 512 ];
while (fgets(line, sizeof line, ifp) != NULL) {
fprintf(ofp, "%s", line);
}
fclose(ifp);
if (ofp != stderr)
fclose(ofp);
}
void VArray2::UnLockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ | PROT_WRITE);
if (rv!=0)
{
print_mem_addr();
printf("mprotect(%8p,%08X,RW) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: UnLockRegion\n");
#endif
}
double os_GetSeconds()
{
timeval a;

View File

@ -1,3 +1,5 @@
#pragma once
#include "types.h"

277
core/linux/posix_vmem.cpp Normal file
View File

@ -0,0 +1,277 @@
// Implementation of the vmem related function for POSIX-like platforms.
// There's some minimal amount of platform specific hacks to support
// Android and OSX since they are slightly different in some areas.
// This implements the VLockedMemory interface, as defined in _vmem.h
// The implementation allows it to be empty (that is, to not lock memory).
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "hw/mem/_vmem.h"
#include "stdclass.h"
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#undef PAGE_MASK
#define PAGE_MASK (PAGE_SIZE-1)
#else
#define PAGE_SIZE 4096
#define PAGE_MASK (PAGE_SIZE-1)
#endif
// Android specific ashmem-device stuff for creating shared memory regions
int ashmem_create_region(const char *name, size_t size) {
int fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) {
close(fd);
return -1;
}
return fd;
}
#endif // #ifdef _ANDROID
void VLockedMemory::LockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ)) {
die("mprotect failed ..\n");
}
}
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ|PROT_WRITE)) {
// Add some way to see why it failed? gdb> info proc mappings
die("mprotect failed ..\n");
}
}
// Allocates memory via a fd on shmem/ahmem or even a file on disk
static int allocate_shared_filemem(unsigned size) {
int fd = -1;
#if defined(_ANDROID)
// Use Android's specific shmem stuff.
fd = ashmem_create_region(0, size);
#else
#if HOST_OS != OS_DARWIN
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR, S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
#endif
// if shmem does not work (or using OSX) fallback to a regular file on disk
if (fd < 0) {
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
}
// If we can't open the file, fallback to slow mem.
if (fd < 0)
return -1;
// Finally make the file as big as we need!
if (ftruncate(fd, size)) {
// Can't get as much memory as needed, fallback.
close(fd);
return -1;
}
#endif
return fd;
}
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
// The function supports allocating 512MB or 4GB addr spaces.
static int shmem_fd = -1, shmem_fd2 = -1;
// vmem_base_addr points to an address space of 512MB (or 4GB) that can be used for fast memory ops.
// In negative offsets of the pointer (up to FPCB size, usually 65/129MB) the context and jump table
// can be found. If the platform init returns error, the user is responsible for initializing the
// memory using a fallback (that is, regular mallocs and falling back to slow memory JIT).
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
// Firt let's try to allocate the shm-backed memory
shmem_fd = allocate_shared_filemem(RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
if (shmem_fd < 0)
return MemTypeError;
// Now try to allocate a contiguous piece of memory.
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void *first_ptr = mmap(0, memsize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (!first_ptr) {
close(shmem_fd);
return MemTypeError;
}
// Align pointer to 64KB too, some Linaro bug (no idea but let's just be safe I guess).
uintptr_t ptrint = (uintptr_t)first_ptr;
ptrint = (ptrint + 0x10000 - 1) & (~0xffff);
*sh4rcb_addr = (void*)ptrint;
*vmem_base_addr = (void*)(ptrint + sizeof(Sh4RCB));
void *sh4rcb_base_ptr = (void*)(ptrint + FPCB_SIZE);
// Now map the memory for the SH4 context, do not include FPCB on purpose (paged on demand).
mprotect(sh4rcb_base_ptr, sizeof(Sh4RCB) - FPCB_SIZE, PROT_READ | PROT_WRITE);
return MemType512MB;
}
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy() {
munmap(virt_ram_base, 0x20000000);
}
// Resets a chunk of memory by deleting its data and setting its protection back.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
// Mark them as non accessible.
mprotect(ptr, size_bytes, PROT_NONE);
// Tell the kernel to flush'em all (FIXME: perhaps unmap+mmap 'd be better?)
madvise(ptr, size_bytes, MADV_DONTNEED);
#if defined(MADV_REMOVE)
madvise(ptr, size_bytes, MADV_REMOVE);
#elif defined(MADV_FREE)
madvise(ptr, size_bytes, MADV_FREE);
#endif
}
// Allocates a bunch of memory (page aligned and page-sized)
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
verify(!mprotect(address, size_bytes, PROT_READ | PROT_WRITE));
}
// Creates mappings to the underlying file including mirroring sections
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
for (unsigned i = 0; i < nummaps; i++) {
// Ignore unmapped stuff, it is already reserved as PROT_NONE
if (!vmem_maps[i].memsize)
continue;
// Calculate the number of mirrors
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
int protection = vmem_maps[i].allow_writes ? (PROT_READ | PROT_WRITE) : PROT_READ;
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
for (unsigned j = 0; j < num_mirrors; j++) {
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
verify(!munmap(&virt_ram_base[offset], vmem_maps[i].memsize));
verify(MAP_FAILED != mmap(&virt_ram_base[offset], vmem_maps[i].memsize, protection,
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd, vmem_maps[i].memoffset));
// ??? (mprotect(rv,size,prot)!=0)
}
}
}
// Prepares the code region for JIT operations, thus marking it as RWX
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rwx) {
// Try to map is as RWX, this fails apparently on OSX (and perhaps other systems?)
if (mprotect(code_area, size, PROT_READ | PROT_WRITE | PROT_EXEC)) {
// Well it failed, use another approach, unmap the memory area and remap it back.
// Seems it works well on Darwin according to reicast code :P
munmap(code_area, size);
void *ret_ptr = mmap(code_area, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
// Ensure it's the area we requested
if (ret_ptr != code_area)
return false; // Couldn't remap it? Perhaps RWX is disabled? This should never happen in any supported Unix platform.
}
// Pointer location should be same:
*code_area_rwx = code_area;
return true;
}
// Use two addr spaces: need to remap something twice, therefore use allocate_shared_filemem()
bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code_area_rw, uintptr_t *rx_offset) {
shmem_fd2 = allocate_shared_filemem(size);
if (shmem_fd2 < 0)
return false;
// Need to unmap the section we are about to use (it might be already unmapped but nevertheless...)
munmap(code_area, size);
// Map the RX bits on the code_area, for proximity, as usual.
void *ptr_rx = mmap(code_area, size, PROT_READ | PROT_EXEC,
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd2, 0);
if (ptr_rx != code_area)
return false;
// Now remap the same memory as RW in some location we don't really care at all.
void *ptr_rw = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_NOSYNC, shmem_fd2, 0);
*code_area_rw = ptr_rw;
*rx_offset = (char*)ptr_rx - (char*)ptr_rw;
printf("Info: Using NO_RWX mode, rx ptr: %p, rw ptr: %p, offset: %lu\n", ptr_rx, ptr_rw, (unsigned long)*rx_offset);
return (ptr_rw != MAP_FAILED);
}
// Some OSes restrict cache flushing, cause why not right? :D
#if HOST_CPU == CPU_ARM64
// Code borrowed from Dolphin https://github.com/dolphin-emu/dolphin
static void Arm64_CacheFlush(void* start, void* end) {
if (start == end)
return;
#if HOST_OS == OS_DARWIN
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
#else
// Don't rely on GCC's __clear_cache implementation, as it caches
// icache/dcache cache line sizes, that can vary between cores on
// big.LITTLE architectures.
u64 addr, ctr_el0;
static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
size_t isize, dsize;
__asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
isize = 4 << ((ctr_el0 >> 0) & 0xf);
dsize = 4 << ((ctr_el0 >> 16) & 0xf);
// use the global minimum cache line size
icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
addr = (u64)start & ~(u64)(dsize - 1);
for (; addr < (u64)end; addr += dsize)
// use "civac" instead of "cvau", as this is the suggested workaround for
// Cortex-A53 errata 819472, 826319, 827319 and 824069.
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
__asm__ volatile("dsb ish" : : : "memory");
addr = (u64)start & ~(u64)(isize - 1);
for (; addr < (u64)end; addr += isize)
__asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
__asm__ volatile("dsb ish" : : : "memory");
__asm__ volatile("isb" : : : "memory");
#endif
}
void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end) {
Arm64_CacheFlush(dcache_start, dcache_end);
// Dont risk it and flush and invalidate icache&dcache for both ranges just in case.
if (icache_start != dcache_start)
Arm64_CacheFlush(icache_start, icache_end);
}
#endif // #if HOST_CPU == CPU_ARM64

View File

@ -22,6 +22,7 @@
#include "imgread/common.h"
#include "rend/gui.h"
#include "profiler/profiler.h"
#include "input/gamepad_device.h"
void FlushCache();
void LoadCustom();
@ -96,10 +97,6 @@ s32 plugins_Init()
if (s32 rv = libGDR_Init())
return rv;
#endif
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (!naomi_cart_SelectFile())
return rv_serror;
#endif
if (s32 rv = libAICA_Init())
return rv;
@ -137,7 +134,7 @@ void LoadSpecialSettings()
safemode_game = false;
tr_poly_depth_mask_game = false;
extra_depth_game = false;
if (reios_windows_ce)
{
printf("Enabling Extra depth scaling for Windows CE games\n");
@ -193,7 +190,7 @@ void LoadSpecialSettings()
}
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Game ID is [%s]\n", naomi_game_id);
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
{
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
@ -216,12 +213,14 @@ void LoadSpecialSettings()
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
settings.input.JammaSetup = 2;
}
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
{
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 1;
}
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 3;
@ -231,9 +230,11 @@ void LoadSpecialSettings()
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 4;
}
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
printf("Enabling lightgun setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 5;
}
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
@ -259,6 +260,7 @@ void dc_reset()
}
static bool init_done;
static bool reset_requested;
int reicast_init(int argc, char* argv[])
{
@ -312,10 +314,25 @@ int dc_start_game(const char *path)
InitSettings();
LoadSettings(false);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (DiscSwap())
LoadCustom();
if (!settings.bios.UseReios)
#endif
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
return -5;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (path == NULL)
{
// Boot BIOS
settings.imgread.LastImage[0] = 0;
TermDrive();
InitDrive();
}
else
{
if (DiscSwap())
LoadCustom();
}
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
LoadRomFiles(get_readonly_data_path(DATA_PATH));
if (!naomi_cart_SelectFile())
return -6;
LoadCustom();
@ -333,7 +350,6 @@ int dc_start_game(const char *path)
return 0;
}
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
{
#ifdef USE_REIOS
@ -354,6 +370,11 @@ int dc_start_game(const char *path)
if (plugins_Init())
return -3;
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (!naomi_cart_SelectFile())
return -6;
#endif
LoadCustom();
#if FEAT_SHREC != DYNAREC_NONE
@ -414,9 +435,18 @@ void* dc_run(void*)
Get_Sh4Interpreter(&sh4_cpu);
printf("Using Interpreter\n");
}
sh4_cpu.Run();
do {
reset_requested = false;
sh4_cpu.Run();
SaveRomFiles(get_writable_data_path("/data/"));
if (reset_requested)
{
dc_reset();
}
} while (reset_requested);
SaveRomFiles(get_writable_data_path("/data/"));
TermAudio();
return NULL;
@ -444,6 +474,13 @@ void dc_stop()
emu_thread.WaitToEnd();
}
// Called on the emulator thread for soft reset
void dc_request_reset()
{
reset_requested = true;
sh4_cpu.Stop();
}
void dc_exit()
{
dc_stop();
@ -452,7 +489,6 @@ void dc_exit()
void InitSettings()
{
settings.dreamcast.RTC = GetRTC_now();
settings.dynarec.Enable = true;
settings.dynarec.idleskip = true;
settings.dynarec.unstable_opt = false;
@ -462,9 +498,11 @@ void InitSettings()
settings.dreamcast.broadcast = 4; // default
settings.dreamcast.language = 6; // default
settings.dreamcast.FullMMU = false;
settings.dynarec.SmcCheckLevel = FullCheck;
settings.aica.LimitFPS = true;
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
settings.aica.NoSound = false;
settings.audio.backend = "auto";
settings.rend.UseMipmaps = true;
settings.rend.WideScreen = false;
settings.rend.ShowFPS = false;
@ -479,6 +517,10 @@ void InitSettings()
settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false;
settings.rend.ScreenScaling = 100;
settings.rend.ScreenStretching = 100;
settings.rend.Fog = true;
settings.rend.FloatVMUs = false;
settings.rend.Rotate90 = false;
settings.pvr.ta_skip = 0;
settings.pvr.rend = 0;
@ -525,11 +567,13 @@ void LoadSettings(bool game_specific)
{
const char *config_section = game_specific ? cfgGetGameId() : "config";
const char *input_section = game_specific ? cfgGetGameId() : "input";
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode);
settings.dynarec.SmcCheckLevel = (SmcCheckEnum)cfgLoadInt(config_section, "Dynarec.SmcCheckLevel", settings.dynarec.SmcCheckLevel);
//disable_nvmem can't be loaded, because nvmem init is before cfg load
settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
@ -539,6 +583,7 @@ void LoadSettings(bool game_specific)
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
@ -560,6 +605,10 @@ void LoadSettings(bool game_specific)
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
@ -624,9 +673,9 @@ void LoadSettings(bool game_specific)
}
/*
//make sure values are valid
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);
settings.dreamcast.region = min(max(settings.dreamcast.region, 0),3);
settings.dreamcast.broadcast= min(max(settings.dreamcast.broadcast,0),4);
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);
settings.dreamcast.region = min(max(settings.dreamcast.region, 0),3);
settings.dreamcast.broadcast = min(max(settings.dreamcast.broadcast,0),4);
*/
}
@ -665,10 +714,33 @@ void SaveSettings()
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
if (!safemode_game || !settings.dynarec.safemode)
cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode);
cfgSaveInt("config", "Dynarec.SmcCheckLevel", (int)settings.dynarec.SmcCheckLevel);
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
// Write backend specific settings
// std::map<std::string, std::map<std::string, std::string>>
for (std::map<std::string, std::map<std::string, std::string>>::iterator it = settings.audio.options.begin(); it != settings.audio.options.end(); ++it)
{
std::pair<std::string, std::map<std::string, std::string>> p = (std::pair<std::string, std::map<std::string, std::string>>)*it;
std::string section = p.first;
std::map<std::string, std::string> options = p.second;
for (std::map<std::string, std::string>::iterator it2 = options.begin(); it2 != options.end(); ++it2)
{
std::pair<std::string, std::string> p2 = (std::pair<std::string, std::string>)*it2;
std::string key = p2.first;
std::string val = p2.second;
cfgSaveStr(section.c_str(), key.c_str(), val.c_str());
}
}
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
@ -681,6 +753,10 @@ void SaveSettings()
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);
@ -709,6 +785,9 @@ void SaveSettings()
paths += path;
}
cfgSaveStr("config", "Dreamcast.ContentPath", paths.c_str());
GamepadDevice::SaveMaplePorts();
#ifdef _ANDROID
void SaveAndroidSettings();
SaveAndroidSettings();

View File

@ -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(&params);
@ -40,7 +75,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_any(handle, params);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
return;
}
@ -50,7 +85,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
return;
}
@ -58,7 +93,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
return;
}
@ -66,7 +101,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_channels(handle, params, 2);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
return;
}
@ -75,7 +110,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
return;
}
@ -84,26 +119,31 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, &dir);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
return;
}
else
{
printf("ALSA: period size set to %ld\n", period_size);
}
buffer_size = (44100 * 100 /* settings.omx.Audio_Latency */ / 1000 / period_size + 1) * period_size;
rc=snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
return;
}
else
{
printf("ALSA: buffer size set to %ld\n", buffer_size);
}
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0)
{
fprintf(stderr, "Unable to set hw parameters: %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Unable to set hw parameters: %s\n", snd_strerror(rc));
return;
}
}
@ -153,11 +193,84 @@ static void alsa_term()
snd_pcm_close(handle);
}
audiobackend_t audiobackend_alsa = {
std::vector<std::string> alsa_get_devicelist()
{
std::vector<std::string> result;
char **hints;
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
// Error initializing ALSA
if (err != 0)
return result;
// special value to automatically detect on initialization
result.push_back("auto");
char** n = hints;
while (*n != NULL)
{
// Get the type (NULL/Input/Output)
char *type = snd_device_name_get_hint(*n, "IOID");
char *name = snd_device_name_get_hint(*n, "NAME");
if (name != NULL)
{
// We only want output or special devices (like "default" or "pulse")
// TODO Only those with type == NULL?
if (type == NULL || strcmp(type, "Output") == 0)
{
// TODO Check if device works (however we need to hash the resulting list then)
/*snd_pcm_t *handle;
int rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, 0);
if (rc == 0)
{
result.push_back(name);
snd_pcm_close(handle);
}
*/
result.push_back(name);
}
}
if (type != NULL)
free(type);
if (name != NULL)
free(name);
n++;
}
snd_device_name_free_hint((void**)hints);
return result;
}
static audio_option_t* alsa_audio_options(int* option_count)
{
*option_count = 1;
static audio_option_t result[1];
result[0].cfg_name = "device";
result[0].caption = "Device";
result[0].type = list;
result[0].list_callback = alsa_get_devicelist;
return result;
}
static audiobackend_t audiobackend_alsa = {
"alsa", // Slug
"Advanced Linux Sound Architecture", // Name
&alsa_init,
&alsa_push,
&alsa_term
&alsa_term,
&alsa_audio_options
};
static bool alsa = RegisterAudioBackend(&audiobackend_alsa);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_alsa;

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_android;

View File

@ -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

View File

@ -1,5 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_coreaudio;

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_directsound;

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_libao;

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_omx;

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_oss;

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_pulseaudio;

View File

@ -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

View File

@ -2,14 +2,6 @@
#include "cfg/cfg.h"
#include "oslib/oslib.h"
#include "audiostream.h"
#include "oslib/audiobackend_directsound.h"
#include "oslib/audiobackend_android.h"
#include "oslib/audiobackend_alsa.h"
#include "oslib/audiobackend_oss.h"
#include "oslib/audiobackend_pulseaudio.h"
#include "oslib/audiobackend_coreaudio.h"
#include "oslib/audiobackend_omx.h"
#include "oslib/audiobackend_libao.h"
struct SoundFrame { s16 l;s16 r; };
#define SAMPLE_COUNT 512
@ -25,16 +17,27 @@ u32 gen_samples=0;
double time_diff = 128/44100.0;
double time_last;
#ifdef LOG_SOUND
// TODO Only works on Windows!
WaveWriter rawout("d:\\aica_out.wav");
#endif
static bool audiobackends_registered = false;
static unsigned int audiobackends_num_max = 1;
static unsigned int audiobackends_num_registered = 0;
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
static audiobackend_t **audiobackends = NULL;
static audiobackend_t *audiobackend_current = NULL;
u32 GetAudioBackendCount()
{
return audiobackends_num_registered;
}
audiobackend_t* GetAudioBackend(int num)
{
return audiobackends[num];
}
bool RegisterAudioBackend(audiobackend_t *backend)
{
/* This function announces the availability of an audio backend to reicast. */
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
return false;
}
if (backend->slug == "auto" || backend->slug == "none") {
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
return false;
}
// First call to RegisterAudioBackend(), create the backend structure;
if (audiobackends == NULL)
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
if (audiobackends_num_registered == audiobackends_num_max)
{
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
}
audiobackends = new_ptr;
}
audiobackends[audiobackends_num_registered] = backend;
audiobackends_num_registered++;
return true;
}
void RegisterAllAudioBackends() {
#if HOST_OS==OS_WINDOWS
RegisterAudioBackend(&audiobackend_directsound);
#endif
#if ANDROID
RegisterAudioBackend(&audiobackend_android);
#endif
#if USE_OMX
RegisterAudioBackend(&audiobackend_omx);
#endif
#if USE_ALSA
RegisterAudioBackend(&audiobackend_alsa);
#endif
#if USE_OSS
RegisterAudioBackend(&audiobackend_oss);
#endif
#if USE_PULSEAUDIO
RegisterAudioBackend(&audiobackend_pulseaudio);
#endif
#if USE_LIBAO
RegisterAudioBackend(&audiobackend_libao);
#endif
#if HOST_OS == OS_DARWIN
RegisterAudioBackend(&audiobackend_coreaudio);
#endif
audiobackends_registered = true;
}
static audiobackend_t* GetAudioBackend(std::string slug)
audiobackend_t* GetAudioBackend(std::string slug)
{
if (slug == "none")
{
printf("WARNING: Audio backend set to \"none\"!\n");
}
else if(audiobackends_num_registered > 0)
else if (audiobackends_num_registered > 0)
{
if (slug == "auto")
{
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
return NULL;
}
u32 PushAudio(void* frame, u32 amt, bool wait) {
u32 PushAudio(void* frame, u32 amt, bool wait)
{
if (audiobackend_current != NULL) {
return audiobackend_current->push(frame, amt, wait);
}
@ -151,11 +134,13 @@ u32 asRingUsedCount()
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
//return sz<0?sz+RingBufferSampleCount:sz;
}
u32 asRingFreeCount()
{
return RingBufferSampleCount-asRingUsedCount();
}
extern double mspdf;
void WriteSample(s16 r, s16 l)
{
const u32 ptr=(WritePtr+1)%RingBufferSampleCount;
@ -165,7 +150,30 @@ void WriteSample(s16 r, s16 l)
if (WritePtr==(SAMPLE_COUNT-1))
{
PushAudio(RingBuffer,SAMPLE_COUNT,settings.aica.LimitFPS);
bool do_wait = settings.aica.LimitFPS && (mspdf <= 11);
PushAudio(RingBuffer,SAMPLE_COUNT, do_wait);
}
}
static bool backends_sorted = false;
void SortAudioBackends()
{
if (backends_sorted)
return;
// Sort backends by slug
for (int n = audiobackends_num_registered; n > 0; n--)
{
for (int i = 0; i < n-1; i++)
{
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
{
audiobackend_t* swap = audiobackends[i];
audiobackends[i] = audiobackends[i+1];
audiobackends[i+1] = swap;
}
}
}
}
@ -176,26 +184,24 @@ void InitAudio()
return;
}
cfgSaveInt("audio","disable",0);
if (!audiobackends_registered) {
//FIXME: There might some nicer way to do this.
RegisterAllAudioBackends();
}
cfgSaveInt("audio", "disable", 0);
if (audiobackend_current != NULL) {
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
return;
}
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
SortAudioBackends();
string audiobackend_slug = settings.audio.backend;
audiobackend_current = GetAudioBackend(audiobackend_slug);
if (audiobackend_current == NULL) {
printf("WARNING: Running without audio!\n");
return;
}
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current->init();
audiobackend_current->init();
}
void TermAudio()
@ -204,5 +210,5 @@ void TermAudio()
audiobackend_current->term();
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current = NULL;
}
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "types.h"
#include <tuple>
//Get used size in the ring buffer
u32 asRingUsedCount();
@ -10,6 +11,29 @@ u32 asRingFreeCount();
bool asRingRead(u8* dst,u32 count=0);
void UpdateBuff(u8* pos);
typedef std::vector<std::string> (*audio_option_callback_t)();
enum audio_option_type
{
integer = 0
, checkbox = 1
, list = 2
};
typedef struct {
std::string cfg_name;
std::string caption;
audio_option_type type;
// type int_value (spin edit)
int min_value;
int max_value;
// type list edit (string/char*)
audio_option_callback_t list_callback;
} audio_option_t;
typedef audio_option_t* (*audio_options_func_t)(int* option_count);
typedef void (*audio_backend_init_func_t)();
typedef u32 (*audio_backend_push_func_t)(void*, u32, bool);
typedef void (*audio_backend_term_func_t)();
@ -19,8 +43,14 @@ typedef struct {
audio_backend_init_func_t init;
audio_backend_push_func_t push;
audio_backend_term_func_t term;
audio_options_func_t get_options;
} audiobackend_t;
extern bool RegisterAudioBackend(audiobackend_t* backend);
extern void InitAudio();
extern u32 PushAudio(void* frame, u32 amt, bool wait);
extern void TermAudio();
u32 GetAudioBackendCount();
void SortAudioBackends();
audiobackend_t* GetAudioBackend(int num);
audiobackend_t* GetAudioBackend(std::string slug);

View File

@ -58,6 +58,7 @@ bkpt #0
bkpt
#endif
ubfx r0,r3,#5,#19 @ get vram offset
@ should be only 18 bits for 8MB VRAM but it wraps around on dc
add r3,r1,#0x04000000 @ get vram ptr from r1, part 1
add r3,#512 @ get ram ptr from r1, part 2
add r3,r0,lsl #5 @ ram + offset
@ -180,6 +181,7 @@ CSYM(no_update): @ next_pc _MUST_ be on r4 *R4 NOT R0 anymore*
#if RAM_SIZE_MAX == 33554432
sub r2,r8,#0x4100000
ubfx r1,r4,#1,#24 @ 24+1 bits: 32 MB
@ RAM wraps around so if actual RAM size is 16MB, we won't overflow
#elif RAM_SIZE_MAX == 16777216
sub r2,r8,#0x2100000
ubfx r1,r4,#1,#23 @ 23+1 bits: 16 MB
@ -241,7 +243,13 @@ HIDDEN(arm_dispatch)
CSYM(arm_dispatch):
ldrd r0,r1,[r8,#184] @load: Next PC, interrupt
#if ARAM_SIZE == 2*1024*1024
ubfx r2,r0,#2,#19 @ assuming 2 MB address space max (21 bits)
#elif ARAM_SIZE == 8*1024*1024
ubfx r2,r0,#2,#21 @ assuming 8 MB address space max (23 bits)
#else
#error Unsupported AICA RAM size
#endif
cmp r1,#0
bne arm_dofiq

View File

@ -2082,7 +2082,7 @@ __default:
}
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
{
//printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR();
@ -2114,39 +2114,68 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
reg.OpBegin(&block->oplist[0],0);
//scheduler
if (force_checks)
{
s32 sz = block->sh4_code_size;
u32 addr = block->addr;
MOV32(r0,addr);
switch (smc_checks) {
case NoCheck:
break;
while (sz > 0)
{
if (sz > 2)
case FastCheck: {
MOV32(r0,block->addr);
u32* ptr=(u32*)GetMemPtr(block->addr,4);
if (ptr != NULL)
{
u32* ptr=(u32*)GetMemPtr(addr,4);
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
addr += 4;
sz -= 4;
}
else
}
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u32 addr = block->addr;
MOV32(r0,addr);
while (sz > 0)
{
u16* ptr = (u16 *)GetMemPtr(addr, 2);
MOV32(r2, (u32)ptr);
LDRH(r2, r2, 0, AL);
MOVW(r1, *ptr, AL);
CMP(r1, r2);
if (sz > 2)
{
u32* ptr=(u32*)GetMemPtr(addr,4);
if (ptr != NULL)
{
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
addr += 2;
sz -= 2;
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
addr += 4;
sz -= 4;
}
else
{
u16* ptr = (u16 *)GetMemPtr(addr, 2);
if (ptr != NULL)
{
MOV32(r2, (u32)ptr);
LDRH(r2, r2, 0, AL);
MOVW(r1, *ptr, AL);
CMP(r1, r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
addr += 2;
sz -= 2;
}
}
}
break;
default: {
die("unhandled smc_checks");
}
}
u32 cyc=block->guest_cycles;

View File

@ -45,12 +45,11 @@ using namespace vixl::aarch64;
extern "C" void no_update();
extern "C" void intc_sched();
extern "C" void ngen_blockcheckfail(u32 pc);
extern "C" void ngen_LinkBlock_Generic_stub();
extern "C" void ngen_LinkBlock_cond_Branch_stub();
extern "C" void ngen_LinkBlock_cond_Next_stub();
extern "C" void ngen_FailedToFindBlock_();
extern void vmem_platform_flush_cache(void *icache_start, void *icache_end, void *dcache_start, void *dcache_end);
struct DynaRBI : RuntimeBlockInfo
{
@ -61,47 +60,6 @@ struct DynaRBI : RuntimeBlockInfo
}
};
// Code borrowed from Dolphin https://github.com/dolphin-emu/dolphin
void Arm64CacheFlush(void* start, void* end)
{
if (start == end)
return;
#if HOST_OS == OS_DARWIN
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
#else
// Don't rely on GCC's __clear_cache implementation, as it caches
// icache/dcache cache line sizes, that can vary between cores on
// big.LITTLE architectures.
u64 addr, ctr_el0;
static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
size_t isize, dsize;
__asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
isize = 4 << ((ctr_el0 >> 0) & 0xf);
dsize = 4 << ((ctr_el0 >> 16) & 0xf);
// use the global minimum cache line size
icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
addr = (u64)start & ~(u64)(dsize - 1);
for (; addr < (u64)end; addr += dsize)
// use "civac" instead of "cvau", as this is the suggested workaround for
// Cortex-A53 errata 819472, 826319, 827319 and 824069.
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
__asm__ volatile("dsb ish" : : : "memory");
addr = (u64)start & ~(u64)(isize - 1);
for (; addr < (u64)end; addr += isize)
__asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
__asm__ volatile("dsb ish" : : : "memory");
__asm__ volatile("isb" : : : "memory");
#endif
}
double host_cpu_time;
u64 guest_cpu_cycles;
@ -147,7 +105,7 @@ __asm__
"ngen_LinkBlock_Shared_stub: \n\t"
"mov x0, lr \n\t"
"sub x0, x0, #4 \n\t" // go before the call
"bl rdv_LinkBlock \n\t"
"bl rdv_LinkBlock \n\t" // returns an RX addr
"br x0 \n"
".hidden ngen_FailedToFindBlock_ \n\t"
@ -348,15 +306,15 @@ public:
return *ret_reg;
}
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
//printf("REC-ARM64 compiling %08x\n", block->addr);
#ifdef PROFILING
SaveFramePointer();
#endif
this->block = block;
if (force_checks)
CheckBlock(block);
CheckBlock(smc_checks, block);
// run register allocator
regalloc.DoAlloc(block);
@ -617,31 +575,25 @@ public:
break;
case shop_pref:
Mov(w0, regalloc.MapRegister(op.rs1));
if (op.flags != 0x1337)
{
Lsr(w1, regalloc.MapRegister(op.rs1), 26);
Cmp(w1, 0x38);
}
Label not_sqw;
B(&not_sqw, ne);
Mov(w0, regalloc.MapRegister(op.rs1));
if (CCN_MMUCR.AT)
{
Ldr(x9, reinterpret_cast<uintptr_t>(&do_sqw_mmu));
}
else
{
Sub(x9, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, do_sqw_nommu));
Ldr(x9, MemOperand(x9));
Sub(x1, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, sq_buffer));
}
if (op.flags == 0x1337)
if (CCN_MMUCR.AT)
{
Ldr(x9, reinterpret_cast<uintptr_t>(&do_sqw_mmu));
}
else
{
Sub(x9, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, do_sqw_nommu));
Ldr(x9, MemOperand(x9));
Sub(x1, x28, offsetof(Sh4RCB, cntx) - offsetof(Sh4RCB, sq_buffer));
}
Blr(x9);
else
{
Label no_branch;
B(&no_branch, ne);
Blr(x9);
Bind(&no_branch);
Bind(&not_sqw);
}
break;
@ -1019,7 +971,7 @@ public:
Ldr(w29, sh4_context_mem_operand(&next_pc));
GenBranch(no_update);
GenBranchRuntime(no_update);
break;
default:
@ -1044,7 +996,12 @@ public:
emit_Skip(block->host_code_size);
}
Arm64CacheFlush(GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
// Flush and invalidate caches
vmem_platform_flush_cache(
CC_RW2RX(GetBuffer()->GetStartAddress<void*>()), CC_RW2RX(GetBuffer()->GetEndAddress<void*>()),
GetBuffer()->GetStartAddress<void*>(), GetBuffer()->GetEndAddress<void*>());
#if 0
// if (rewrite)
{
@ -1066,10 +1023,13 @@ public:
}
private:
// Runtime branches/calls need to be adjusted if rx space is different to rw space.
// Therefore can't mix GenBranch with GenBranchRuntime!
template <typename R, typename... P>
void GenCallRuntime(R (*function)(P...))
{
ptrdiff_t offset = reinterpret_cast<uintptr_t>(function) - GetBuffer()->GetStartAddress<uintptr_t>();
ptrdiff_t offset = reinterpret_cast<uintptr_t>(function) - reinterpret_cast<uintptr_t>(CC_RW2RX(GetBuffer()->GetStartAddress<void*>()));
verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024);
verify((offset & 3) == 0);
Label function_label;
@ -1077,6 +1037,17 @@ private:
Bl(&function_label);
}
template <typename R, typename... P>
void GenBranchRuntime(R (*target)(P...))
{
ptrdiff_t offset = reinterpret_cast<uintptr_t>(target) - reinterpret_cast<uintptr_t>(CC_RW2RX(GetBuffer()->GetStartAddress<void*>()));
verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024);
verify((offset & 3) == 0);
Label target_label;
BindToOffset(&target_label, offset);
B(&target_label);
}
template <typename R, typename... P>
void GenBranch(R (*code)(P...), Condition cond = al)
{
@ -1298,49 +1269,72 @@ private:
verify (GetCursorAddress<Instruction *>() - start_instruction == code_size * kInstructionSize);
}
void CheckBlock(RuntimeBlockInfo* block)
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
{
s32 sz = block->sh4_code_size;
Label blockcheck_fail;
Label blockcheck_success;
u8* ptr = GetMemPtr(block->addr, sz);
if (ptr == NULL)
// FIXME Can a block cross a RAM / non-RAM boundary??
return;
switch (smc_checks) {
case NoCheck:
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
while (sz > 0)
{
if (sz >= 8)
{
Ldr(x10, MemOperand(x9, 8, PostIndex));
Ldr(x11, *(u64*)ptr);
Cmp(x10, x11);
sz -= 8;
ptr += 8;
}
else if (sz >= 4)
{
Ldr(w10, MemOperand(x9, 4, PostIndex));
case FastCheck: {
u8* ptr = GetMemPtr(block->addr, 4);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
Ldr(w10, MemOperand(x9));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
sz -= 4;
ptr += 4;
B(eq, &blockcheck_success);
}
else
{
Ldrh(w10, MemOperand(x9, 2, PostIndex));
Mov(w11, *(u16*)ptr);
Cmp(w10, w11);
sz -= 2;
ptr += 2;
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u8* ptr = GetMemPtr(block->addr, sz);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
while (sz > 0)
{
if (sz >= 8)
{
Ldr(x10, MemOperand(x9, 8, PostIndex));
Ldr(x11, *(u64*)ptr);
Cmp(x10, x11);
sz -= 8;
ptr += 8;
}
else if (sz >= 4)
{
Ldr(w10, MemOperand(x9, 4, PostIndex));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
sz -= 4;
ptr += 4;
}
else
{
Ldrh(w10, MemOperand(x9, 2, PostIndex));
Mov(w11, *(u16*)ptr);
Cmp(w10, w11);
sz -= 2;
ptr += 2;
}
B(ne, &blockcheck_fail);
}
B(&blockcheck_success);
}
B(ne, &blockcheck_fail);
break;
default:
die("unhandled smc_checks");
}
B(&blockcheck_success);
Bind(&blockcheck_fail);
Ldr(w0, block->addr);
@ -1403,20 +1397,23 @@ private:
std::vector<const VRegister*> call_fregs;
Arm64RegAlloc regalloc;
RuntimeBlockInfo* block;
const int write_memory_rewrite_size = 3; // same size (fast write) for any size: add, bfc, str
#ifdef EXPLODE_SPANS
const int read_memory_rewrite_size = 6; // worst case for u64: add, bfc, ldr, fmov, lsr, fmov
// FIXME rewrite size per read/write size?
const int write_memory_rewrite_size = 3;
#else
const int read_memory_rewrite_size = 4; // worst case for u64: add, bfc, ldr, str
#endif
};
static Arm64Assembler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new Arm64Assembler();
compiler->ngen_Compile(block, force_checks, reset, staging, optimise);
compiler->ngen_Compile(block, smc_checks, reset, staging, optimise);
delete compiler;
compiler = NULL;
@ -1445,13 +1442,14 @@ void ngen_CC_Finish(shil_opcode* op)
bool ngen_Rewrite(unat& host_pc, unat, unat)
{
//printf("ngen_Rewrite pc %p\n", host_pc);
RuntimeBlockInfo *block = bm_GetBlock((void *)host_pc);
void *host_pc_rw = (void*)CC_RX2RW(host_pc);
RuntimeBlockInfo *block = bm_GetBlock((void*)host_pc);
if (block == NULL)
{
printf("ngen_Rewrite: Block at %p not found\n", (void *)host_pc);
return false;
}
u32 *code_ptr = (u32*)host_pc;
u32 *code_ptr = (u32*)host_pc_rw;
auto it = block->memory_accesses.find(code_ptr);
if (it == block->memory_accesses.end())
{
@ -1469,7 +1467,7 @@ bool ngen_Rewrite(unat& host_pc, unat, unat)
assembler->GenWriteMemorySlow(op);
assembler->Finalize(true);
delete assembler;
host_pc = (unat)(code_ptr - 2);
host_pc = (unat)CC_RW2RX(code_ptr - 2);
return true;
}

View File

@ -13,7 +13,6 @@
#include "hw/sh4/dyna/ngen.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/sh4/dyna/regalloc.h"
#include "emitter/x86_emitter.h"
#include "profiler/profiler.h"
#include "oslib/oslib.h"
@ -1191,10 +1190,10 @@ public:
size_t opcode_index;
opcodeExec** ptrsg;
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise) {
//we need an extra one for the end opcode and optionally one more for block check
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (force_checks ? 1 : 0))(block->guest_cycles);
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (smc_checks != NoCheck ? 1 : 0))(block->guest_cycles);
ptrsg = ptrs.ptrs;
@ -1208,9 +1207,16 @@ public:
}
size_t i = 0;
if (force_checks)
if (smc_checks != NoCheck)
{
verify (smc_checks == FastCheck || smc_checks == FullCheck)
opcodeExec* op;
int check_size = block->sh4_code_size;
if (smc_checks == FastCheck) {
check_size = 4;
}
switch (block->sh4_code_size)
{
case 4:
@ -1228,6 +1234,7 @@ public:
}
ptrs.ptrs[i++] = op;
}
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
opcode_index = i;
shil_opcode& op = block->oplist[opnum];
@ -1552,14 +1559,14 @@ public:
BlockCompiler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise);
compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler;
}

Some files were not shown because too many files have changed in this diff Show More