aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--CMakeLists.txt20
-rw-r--r--README.md2
-rw-r--r--dist/citra.desktop14
-rw-r--r--dist/citra.svg80
-rw-r--r--dist/citra.xml59
m---------externals/nihstro0
-rw-r--r--src/citra/citra.cpp4
-rw-r--r--src/citra/config.cpp8
-rw-r--r--src/citra/default_ini.h7
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp4
-rw-r--r--src/citra_qt/bootmanager.cpp104
-rw-r--r--src/citra_qt/bootmanager.h69
-rw-r--r--src/citra_qt/config.cpp13
-rw-r--r--src/citra_qt/debugger/callstack.cpp5
-rw-r--r--src/citra_qt/debugger/disassembler.cpp89
-rw-r--r--src/citra_qt/debugger/disassembler.h9
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints_p.h2
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp4
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp4
-rw-r--r--src/citra_qt/debugger/profiler.cpp4
-rw-r--r--src/citra_qt/debugger/profiler.h2
-rw-r--r--src/citra_qt/debugger/ramview.cpp3
-rw-r--r--src/citra_qt/debugger/registers.cpp33
-rw-r--r--src/citra_qt/debugger/registers.h4
-rw-r--r--src/citra_qt/main.cpp132
-rw-r--r--src/citra_qt/main.h23
-rw-r--r--src/citra_qt/main.ui3
-rw-r--r--src/citra_qt/util/spinbox.cpp3
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/assert.h1
-rw-r--r--src/common/bit_field.h2
-rw-r--r--src/common/break_points.cpp5
-rw-r--r--src/common/break_points.h6
-rw-r--r--src/common/chunk_file.h3
-rw-r--r--src/common/common.h120
-rw-r--r--src/common/common_funcs.h75
-rw-r--r--src/common/common_paths.h3
-rw-r--r--src/common/common_types.h35
-rw-r--r--src/common/concurrent_ring_buffer.h2
-rw-r--r--src/common/emu_window.cpp22
-rw-r--r--src/common/emu_window.h11
-rw-r--r--src/common/file_util.cpp54
-rw-r--r--src/common/file_util.h2
-rw-r--r--src/common/hash.cpp521
-rw-r--r--src/common/hash.h17
-rw-r--r--src/common/linear_disk_cache.h2
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/logging/log.h2
-rw-r--r--src/common/logging/text_formatter.cpp1
-rw-r--r--src/common/math_util.cpp211
-rw-r--r--src/common/math_util.h174
-rw-r--r--src/common/mem_arena.cpp389
-rw-r--r--src/common/mem_arena.h70
-rw-r--r--src/common/memory_util.cpp5
-rw-r--r--src/common/misc.cpp4
-rw-r--r--src/common/platform.h65
-rw-r--r--src/common/profiler.cpp4
-rw-r--r--src/common/string_util.cpp137
-rw-r--r--src/common/string_util.h10
-rw-r--r--src/common/symbols.h4
-rw-r--r--src/common/thread.h82
-rw-r--r--src/common/thread_queue_list.h20
-rw-r--r--src/common/thunk.h2
-rw-r--r--src/common/timer.cpp4
-rw-r--r--src/common/timer.h2
-rw-r--r--src/core/CMakeLists.txt66
-rw-r--r--src/core/arm/arm_interface.h16
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp25
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp308
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.h41
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp8
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.h4
-rw-r--r--src/core/arm/interpreter/armcopro.cpp142
-rw-r--r--src/core/arm/interpreter/arminit.cpp97
-rw-r--r--src/core/arm/interpreter/armsupp.cpp428
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h129
-rw-r--r--src/core/arm/skyeye_common/armdefs.h97
-rw-r--r--src/core/arm/skyeye_common/armemu.h21
-rw-r--r--src/core/arm/skyeye_common/armmmu.h4
-rw-r--r--src/core/arm/skyeye_common/armos.h54
-rw-r--r--src/core/arm/skyeye_common/skyeye_defs.h38
-rw-r--r--src/core/arm/skyeye_common/vfp/asm_vfp.h14
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp632
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h24
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h120
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp35
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp82
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp102
-rw-r--r--src/core/core.cpp5
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/core_timing.cpp10
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/file_sys/archive_backend.cpp127
-rw-r--r--src/core/file_sys/archive_backend.h147
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp1
-rw-r--r--src/core/file_sys/archive_romfs.cpp1
-rw-r--r--src/core/file_sys/archive_savedata.cpp6
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp1
-rw-r--r--src/core/file_sys/archive_sdmc.cpp1
-rw-r--r--src/core/file_sys/directory_backend.h3
-rw-r--r--src/core/file_sys/disk_archive.cpp1
-rw-r--r--src/core/file_sys/disk_archive.h4
-rw-r--r--src/core/file_sys/file_backend.h2
-rw-r--r--src/core/file_sys/ivfc_archive.cpp1
-rw-r--r--src/core/file_sys/ivfc_archive.h2
-rw-r--r--src/core/hle/config_mem.cpp58
-rw-r--r--src/core/hle/config_mem.h38
-rw-r--r--src/core/hle/function_wrappers.h13
-rw-r--r--src/core/hle/hle.cpp55
-rw-r--r--src/core/hle/hle.h28
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp7
-rw-r--r--src/core/hle/kernel/event.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/kernel/kernel.h33
-rw-r--r--src/core/hle/kernel/mutex.cpp12
-rw-r--r--src/core/hle/kernel/process.cpp98
-rw-r--r--src/core/hle/kernel/process.h98
-rw-r--r--src/core/hle/kernel/semaphore.cpp2
-rw-r--r--src/core/hle/kernel/session.h12
-rw-r--r--src/core/hle/kernel/shared_memory.cpp33
-rw-r--r--src/core/hle/kernel/shared_memory.h25
-rw-r--r--src/core/hle/kernel/thread.cpp131
-rw-r--r--src/core/hle/kernel/thread.h65
-rw-r--r--src/core/hle/kernel/timer.cpp8
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/am_sys.cpp2
-rw-r--r--src/core/hle/service/apt/apt.cpp92
-rw-r--r--src/core/hle/service/apt/apt.h49
-rw-r--r--src/core/hle/service/apt/apt_a.cpp6
-rw-r--r--src/core/hle/service/apt/apt_s.cpp3
-rw-r--r--src/core/hle/service/apt/apt_u.cpp1
-rw-r--r--src/core/hle/service/cfg/cfg.cpp18
-rw-r--r--src/core/hle/service/cfg/cfg.h4
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp2
-rw-r--r--src/core/hle/service/dsp_dsp.cpp61
-rw-r--r--src/core/hle/service/err_f.cpp2
-rw-r--r--src/core/hle/service/fs/archive.cpp11
-rw-r--r--src/core/hle/service/fs/archive.h16
-rw-r--r--src/core/hle/service/fs/fs_user.cpp85
-rw-r--r--src/core/hle/service/gsp_gpu.cpp44
-rw-r--r--src/core/hle/service/hid/hid.cpp36
-rw-r--r--src/core/hle/service/hid/hid.h6
-rw-r--r--src/core/hle/service/ir/ir.cpp52
-rw-r--r--src/core/hle/service/ir/ir.h30
-rw-r--r--src/core/hle/service/ir/ir_rst.cpp24
-rw-r--r--src/core/hle/service/ir/ir_rst.h (renamed from src/core/hle/service/ir_rst.h)13
-rw-r--r--src/core/hle/service/ir/ir_u.cpp (renamed from src/core/hle/service/ir_u.cpp)17
-rw-r--r--src/core/hle/service/ir/ir_u.h22
-rw-r--r--src/core/hle/service/ir/ir_user.cpp34
-rw-r--r--src/core/hle/service/ir/ir_user.h22
-rw-r--r--src/core/hle/service/ir_rst.cpp27
-rw-r--r--src/core/hle/service/ldr_ro.cpp2
-rw-r--r--src/core/hle/service/nim_u.cpp48
-rw-r--r--src/core/hle/service/nim_u.h (renamed from src/core/hle/service/ir_u.h)8
-rw-r--r--src/core/hle/service/ns_s.cpp2
-rw-r--r--src/core/hle/service/nwm_uds.cpp113
-rw-r--r--src/core/hle/service/nwm_uds.h2
-rw-r--r--src/core/hle/service/ptm/ptm.cpp64
-rw-r--r--src/core/hle/service/ptm/ptm.h46
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp8
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp75
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp64
-rw-r--r--src/core/hle/service/service.cpp70
-rw-r--r--src/core/hle/service/service.h57
-rw-r--r--src/core/hle/service/soc_u.cpp1
-rw-r--r--src/core/hle/service/srv.cpp2
-rw-r--r--src/core/hle/service/y2r_u.cpp4
-rw-r--r--src/core/hle/shared_page.cpp60
-rw-r--r--src/core/hle/shared_page.h38
-rw-r--r--src/core/hle/svc.cpp131
-rw-r--r--src/core/hle/svc.h2
-rw-r--r--src/core/hw/gpu.cpp24
-rw-r--r--src/core/hw/gpu.h4
-rw-r--r--src/core/hw/hw.cpp3
-rw-r--r--src/core/hw/lcd.cpp4
-rw-r--r--src/core/hw/lcd.h3
-rw-r--r--src/core/loader/3dsx.cpp16
-rw-r--r--src/core/loader/3dsx.h8
-rw-r--r--src/core/loader/elf.cpp17
-rw-r--r--src/core/loader/elf.h8
-rw-r--r--src/core/loader/loader.cpp50
-rw-r--r--src/core/loader/loader.h11
-rw-r--r--src/core/loader/ncch.cpp62
-rw-r--r--src/core/loader/ncch.h58
-rw-r--r--src/core/mem_map.cpp196
-rw-r--r--src/core/mem_map.h171
-rw-r--r--src/core/mem_map_funcs.cpp294
-rw-r--r--src/core/memory.cpp202
-rw-r--r--src/core/memory.h129
-rw-r--r--src/core/memory_setup.h29
-rw-r--r--src/core/settings.h5
-rw-r--r--src/core/system.cpp12
-rw-r--r--src/core/system.h21
-rw-r--r--src/video_core/color.h2
-rw-r--r--src/video_core/command_processor.cpp100
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp15
-rw-r--r--src/video_core/pica.h152
-rw-r--r--src/video_core/rasterizer.cpp70
-rw-r--r--src/video_core/renderer_base.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp14
-rw-r--r--src/video_core/utils.h6
-rw-r--r--src/video_core/vertex_shader.cpp66
-rw-r--r--src/video_core/vertex_shader.h1
-rw-r--r--src/video_core/video_core.cpp2
-rw-r--r--src/video_core/video_core.h1
208 files changed, 4357 insertions, 5221 deletions
diff --git a/.gitmodules b/.gitmodules
index a9e0a5c1..598e4c64 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,9 +1,9 @@
-[submodule "externals/inih/inih"]
+[submodule "inih"]
path = externals/inih/inih
url = https://github.com/svn2github/inih
-[submodule "externals/boost"]
+[submodule "boost"]
path = externals/boost
url = https://github.com/citra-emu/ext-boost.git
-[submodule "externals/nihstro"]
+[submodule "nihstro"]
path = externals/nihstro
url = https://github.com/neobrain/nihstro.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5cae66de..fc742317 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,8 +8,11 @@ if (NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -pthread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
else()
- # Silence deprecation warnings
- add_definitions(/D_CRT_SECURE_NO_WARNINGS)
+ # Silence "deprecation" warnings
+ add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE)
+ # Avoid windows.h junk
+ add_definitions(/DNOMINMAX)
+
# set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE)
@@ -197,3 +200,16 @@ if(ENABLE_QT)
add_subdirectory(externals/qhexedit)
endif()
add_subdirectory(src)
+
+# Install freedesktop.org metadata files, following those specifications:
+# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
+# http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+# http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.desktop"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.svg"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pixmaps")
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.xml"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
+endif()
diff --git a/README.md b/README.md
index 40a380f5..af65f2b0 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Citra Emulator
Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and OS X. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward.
-Citra is licensed under the GPLv2. Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project.
+Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project.
For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/?channels=citra).
diff --git a/dist/citra.desktop b/dist/citra.desktop
new file mode 100644
index 00000000..1300d62c
--- /dev/null
+++ b/dist/citra.desktop
@@ -0,0 +1,14 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Citra
+GenericName=3DS Emulator
+GenericName[fr]=Émulateur 3DS
+Comment=Nintendo 3DS video game console emulator
+Comment[fr]=Émulateur de console de jeu Nintendo 3DS
+Icon=citra
+TryExec=citra-qt
+Exec=citra-qt %f
+Categories=Game;Emulator;Qt;
+MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi;
+Keywords=3DS;Nintendo;
diff --git a/dist/citra.svg b/dist/citra.svg
new file mode 100644
index 00000000..7b299cd8
--- /dev/null
+++ b/dist/citra.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 Citra Emulator Project
+ Licensed under GPLv2 or any later version
+ Refer to the license.txt file included.
+-->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 341.071 338.846">
+ <radialGradient id="a" cx="170.5356" cy="167.271" r="170.5332" gradientTransform="matrix(1 0 0 0.9935 0 3.2396)" gradientUnits="userSpaceOnUse">
+ <stop offset="0.5193" stop-color="#FFFFFF" stop-opacity="0.1"/>
+ <stop offset="0.9415" stop-color="#000000" stop-opacity="0.5"/>
+ <stop offset="1" stop-color="#1A1818" stop-opacity="0"/>
+ </radialGradient>
+ <ellipse fill="url(#a)" cx="170.535" cy="169.423" rx="170.535" ry="169.423"/>
+ <circle fill="#D16F17" cx="170.536" cy="167.885" r="161.557"/>
+ <linearGradient id="b" gradientUnits="userSpaceOnUse" x1="234.4458" y1="33.5771" x2="97.5655" y2="321.2358">
+ <stop offset="0" stop-color="#FFF8BD"/>
+ <stop offset="1" stop-color="#F6DCAE"/>
+ </linearGradient>
+ <circle fill="url(#b)" cx="170.536" cy="167.885" r="155.295"/>
+ <g>
+ <linearGradient id="c" gradientUnits="userSpaceOnUse" x1="332.436" y1="91.7446" x2="111.1593" y2="342.0988">
+ <stop offset="0" stop-color="#F7A076"/>
+ <stop offset="0.4455" stop-color="#F3816C"/>
+ <stop offset="1" stop-color="#F06878"/>
+ </linearGradient>
+ <path fill="url(#c)" stroke="#F06564" stroke-miterlimit="10" d="M309.704,123.138
+ c-5.9-7.802-128.517,44.681-128.517,44.681S303.803,221.01,309.704,212.5C322.434,194.142,323.182,140.957,309.704,123.138z"/>
+ <linearGradient id="d" gradientUnits="userSpaceOnUse" x1="285.5845" y1="50.3345" x2="64.3074" y2="300.6891">
+ <stop offset="0" stop-color="#9DC63B"/>
+ <stop offset="1" stop-color="#9BC183"/>
+ </linearGradient>
+ <path fill="url(#d)" stroke="#72AA42" stroke-miterlimit="10" d="M300.518,100.96c-3.98-21.983-41.059-60.12-63.189-63.188
+ c-9.688-1.345-59.28,122.469-59.28,122.469S302.364,111.149,300.518,100.96z"/>
+ <linearGradient id="e" gradientUnits="userSpaceOnUse" x1="229.4995" y1="0.7637" x2="8.2231" y2="251.1176">
+ <stop offset="0" stop-color="#D5DE26"/>
+ <stop offset="1" stop-color="#C5D94B"/>
+ </linearGradient>
+ <path fill="url(#e)" stroke="#BECD30" stroke-miterlimit="10" d="M215.151,28.584c-18.357-12.73-71.543-13.478-89.362,0.001
+ c-7.801,5.899,44.682,128.516,44.682,128.516S223.663,34.484,215.151,28.584z"/>
+ <linearGradient id="f" gradientUnits="userSpaceOnUse" x1="219.3823" y1="-8.1782" x2="-1.8941" y2="242.1756">
+ <stop offset="0" stop-color="#F2D200"/>
+ <stop offset="1" stop-color="#FDEF52"/>
+ </linearGradient>
+ <path fill="url(#f)" stroke="#E1BE29" stroke-miterlimit="10" d="M162.893,160.239c0,0-49.092-124.315-59.281-122.469
+ c-21.982,3.979-60.12,41.058-63.188,63.189C39.078,110.646,162.893,160.239,162.893,160.239z"/>
+ <linearGradient id="g" gradientUnits="userSpaceOnUse" x1="226.0718" y1="-2.2656" x2="4.7951" y2="248.0886">
+ <stop offset="0" stop-color="#FFCD10"/>
+ <stop offset="1" stop-color="#F29634"/>
+ </linearGradient>
+ <path fill="url(#g)" stroke="#F79421" stroke-miterlimit="10" d="M31.236,123.136c-12.73,18.357-13.479,71.543,0,89.362
+ c5.898,7.801,128.516-44.682,128.516-44.682S37.135,114.625,31.236,123.136z"/>
+ <linearGradient id="h" gradientUnits="userSpaceOnUse" x1="272.9214" y1="39.144" x2="51.6446" y2="289.4984">
+ <stop offset="0" stop-color="#F79F1C"/>
+ <stop offset="0.4455" stop-color="#F08021"/>
+ <stop offset="1" stop-color="#ED693C"/>
+ </linearGradient>
+ <path fill="url(#h)" stroke="#F16622" stroke-miterlimit="10" d="M40.422,234.676c3.979,21.982,41.057,60.12,63.188,63.188
+ c9.687,1.346,59.279-122.468,59.279-122.468S38.574,224.487,40.422,234.676z"/>
+ <linearGradient id="i" gradientUnits="userSpaceOnUse" x1="329.0083" y1="88.7129" x2="107.7311" y2="339.0677">
+ <stop offset="0" stop-color="#E47C26"/>
+ <stop offset="0.4455" stop-color="#DF5B27"/>
+ <stop offset="1" stop-color="#DD3A3A"/>
+ </linearGradient>
+ <path fill="url(#i)" stroke="#E03827" stroke-miterlimit="10" d="M125.787,307.051c18.357,12.73,71.543,13.48,89.362,0
+ c7.801-5.898-44.681-128.515-44.681-128.515S117.275,301.153,125.787,307.051z"/>
+ <linearGradient id="j" gradientUnits="userSpaceOnUse" x1="339.1245" y1="97.6562" x2="117.8478" y2="348.0104">
+ <stop offset="0" stop-color="#F3783C"/>
+ <stop offset="0.4455" stop-color="#EF5339"/>
+ <stop offset="1" stop-color="#ED294A"/>
+ </linearGradient>
+ <path fill="url(#j)" stroke="#ED2836" stroke-miterlimit="10" d="M178.047,175.398c0,0,49.09,124.315,59.28,122.467
+ c21.982-3.979,60.121-41.057,63.189-63.188C301.86,224.991,178.047,175.398,178.047,175.398z"/>
+ </g>
+ <linearGradient id="k" gradientUnits="userSpaceOnUse" x1="170.5352" y1="6.3281" x2="170.5351" y2="329.4424">
+ <stop offset="0" stop-color="#FFFFFF" stop-opacity="0.2"/>
+ <stop offset="0.4504" stop-color="#908E8E" stop-opacity="0.05"/>
+ <stop offset="1" stop-color="#030003" stop-opacity="0.2"/>
+ </linearGradient>
+ <circle fill="url(#k)" cx="170.536" cy="167.885" r="161.557"/>
+</svg>
diff --git a/dist/citra.xml b/dist/citra.xml
new file mode 100644
index 00000000..bcb9acd8
--- /dev/null
+++ b/dist/citra.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-ctr-3dsx">
+ <comment>3DS homebrew executable</comment>
+ <comment xml:lang="fr">Exécutable 3DS homebrew</comment>
+ <acronym>3DSX</acronym>
+ <icon name="citra"/>
+ <glob pattern="*.3dsx"/>
+ <magic><match value="3DSX" type="string" offset="0"/></magic>
+ </mime-type>
+
+ <mime-type type="application/x-ctr-cci">
+ <comment>3DS cartridge image</comment>
+ <comment xml:lang="fr">Image de cartouche 3DS</comment>
+ <acronym>CCI</acronym>
+ <expanded-acronym>CTR Cart Image</expanded-acronym>
+ <icon name="citra"/>
+ <glob pattern="*.cci"/>
+ <glob pattern="*.3ds"/>
+ <magic><match value="NCSD" type="string" offset="256"/></magic>
+ </mime-type>
+
+ <mime-type type="application/x-ctr-cxi">
+ <comment>3DS executable</comment>
+ <comment xml:lang="fr">Exécutable 3DS</comment>
+ <acronym>CXI</acronym>
+ <expanded-acronym>CTR eXecutable Image</expanded-acronym>
+ <icon name="citra"/>
+ <glob pattern="*.cxi"/>
+ <magic><match value="NCCH" type="string" offset="256"/></magic>
+ </mime-type>
+
+ <mime-type type="application/x-ctr-cia">
+ <comment>3DS importable archive</comment>
+ <comment xml:lang="fr">Archive importable 3DS</comment>
+ <acronym>CIA</acronym>
+ <expanded-acronym>CTR Importable Archive</expanded-acronym>
+ <icon name="citra"/>
+ <glob pattern="*.cia"/>
+ </mime-type>
+
+ <mime-type type="application/x-ctr-smdh">
+ <comment>3DS icon</comment>
+ <comment xml:lang="fr">Icône 3DS</comment>
+ <acronym>SMDH</acronym>
+ <expanded-acronym>System Menu Data Header</expanded-acronym>
+ <glob pattern="*.smdh"/>
+ <magic><match value="SMDH" type="string" offset="0"/></magic>
+ </mime-type>
+
+ <mime-type type="application/x-ctr-cbmd">
+ <comment>3DS banner</comment>
+ <comment xml:lang="fr">Bannière 3DS</comment>
+ <acronym>CBMD</acronym>
+ <expanded-acronym>CTR Banner Model Data</expanded-acronym>
+ <glob pattern="*.cbmd"/>
+ <magic><match value="CBMD" type="string" offset="0"/></magic>
+ </mime-type>
+</mime-info>
diff --git a/externals/nihstro b/externals/nihstro
-Subproject 4a78588b308564f7ebae193e0ae00d9a0d5741d
+Subproject 81f1804a43f625e3a1a20752c0db70a41341038
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 2c6ced92..1d7e7f27 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -4,7 +4,7 @@
#include <thread>
-#include "common/common.h"
+#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
@@ -19,7 +19,7 @@
#include "citra/emu_window/emu_window_glfw.h"
/// Application entry point
-int __cdecl main(int argc, char **argv) {
+int main(int argc, char **argv) {
std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
Log::Filter log_filter(Log::Level::Debug);
Log::SetFilter(&log_filter);
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index e9f3dfd5..ab564559 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -5,7 +5,10 @@
#include <GLFW/glfw3.h>
#include "citra/default_ini.h"
+
#include "common/file_util.h"
+#include "common/logging/log.h"
+
#include "core/settings.h"
#include "core/core.h"
@@ -66,6 +69,11 @@ void Config::ReadValues() {
Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 30);
Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0);
+ // Renderer
+ Settings::values.bg_red = (float)glfw_config->GetReal("Renderer", "bg_red", 1.0);
+ Settings::values.bg_green = (float)glfw_config->GetReal("Renderer", "bg_green", 1.0);
+ Settings::values.bg_blue = (float)glfw_config->GetReal("Renderer", "bg_blue", 1.0);
+
// Data Storage
Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index fc02a3ce..1dd97192 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -41,6 +41,13 @@ gpu_refresh_rate =
# 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc.
frame_skip =
+[Renderer]
+# The clear color for the renderer. What shows up on the sides of the bottom screen.
+# Must be in range of 0.0-1.0. Defaults to 1.0 for all.
+bg_red =
+bg_blue =
+bg_green =
+
[Data Storage]
# Whether to create a virtual SD card.
# 1 (default): Yes, 0: No
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 997e3bc7..341b48d2 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -4,7 +4,7 @@
#include <GLFW/glfw3.h>
-#include "common/common.h"
+#include "common/logging/log.h"
#include "video_core/video_core.h"
@@ -31,7 +31,7 @@ void EmuWindow_GLFW::OnMouseButtonEvent(GLFWwindow* win, int button, int action,
}
void EmuWindow_GLFW::OnCursorPosEvent(GLFWwindow* win, double x, double y) {
- GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(x), static_cast<unsigned>(y));
+ GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(std::max(x, 0.0)), static_cast<unsigned>(std::max(y, 0.0)));
}
/// Called by GLFW when a key event occurs
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index b81bd616..d3df289f 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -8,8 +8,8 @@
#include <QWindow>
#endif
-#include "common/common.h"
#include "bootmanager.h"
+#include "main.h"
#include "core/core.h"
#include "core/settings.h"
@@ -27,43 +27,33 @@
#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
EmuThread::EmuThread(GRenderWindow* render_window) :
- filename(""), exec_cpu_step(false), cpu_running(false),
- stop_run(false), render_window(render_window)
-{
-}
+ exec_step(false), running(false), stop_run(false), render_window(render_window) {
-void EmuThread::SetFilename(std::string filename)
-{
- this->filename = filename;
+ connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
}
-void EmuThread::run()
-{
+void EmuThread::run() {
stop_run = false;
// holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the
// next execution step
bool was_active = false;
- while (!stop_run)
- {
- if (cpu_running)
- {
+ while (!stop_run) {
+ if (running) {
if (!was_active)
emit DebugModeLeft();
Core::RunLoop();
- was_active = cpu_running || exec_cpu_step;
- if (!was_active)
+ was_active = running || exec_step;
+ if (!was_active && !stop_run)
emit DebugModeEntered();
- }
- else if (exec_cpu_step)
- {
+ } else if (exec_step) {
if (!was_active)
emit DebugModeLeft();
- exec_cpu_step = false;
+ exec_step = false;
Core::SingleStep();
emit DebugModeEntered();
yieldCurrentThread();
@@ -71,47 +61,10 @@ void EmuThread::run()
was_active = false;
}
}
- render_window->moveContext();
-
- Core::Stop();
-}
-
-void EmuThread::Stop()
-{
- if (!isRunning())
- {
- LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
- return;
- }
- stop_run = true;
- // Release emu threads from any breakpoints, so that this doesn't hang forever.
- Pica::g_debug_context->ClearBreakpoints();
-
- //core::g_state = core::SYS_DIE;
-
- // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
- wait(1000);
- if (isRunning())
- {
- LOG_WARNING(Frontend, "EmuThread still running, terminating...");
- quit();
-
- // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
- // queued... This should be fixed.
- wait(50000);
- if (isRunning())
- {
- LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
- terminate();
- }
- }
- LOG_INFO(Frontend, "EmuThread stopped");
-
- System::Shutdown();
+ render_window->moveContext();
}
-
// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
// The corresponding functionality is handled in EmuThread instead
class GGLWidgetInternal : public QGLWidget
@@ -133,13 +86,9 @@ private:
GRenderWindow* parent;
};
-EmuThread& GRenderWindow::GetEmuThread()
-{
- return emu_thread;
-}
+GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) :
+ QWidget(parent), emu_thread(emu_thread), keyboard_id(0) {
-GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0)
-{
std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
setWindowTitle(QString::fromStdString(window_title));
@@ -160,7 +109,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
layout->addWidget(child);
layout->setMargin(0);
setLayout(layout);
- connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
@@ -180,29 +128,17 @@ void GRenderWindow::moveContext()
// We need to move GL context to the swapping thread in Qt5
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
// If the thread started running, move the GL Context to the new thread. Otherwise, move it back.
- child->context()->moveToThread((QThread::currentThread() == qApp->thread()) ? &emu_thread : qApp->thread());
+ auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr) ? emu_thread : qApp->thread();
+ child->context()->moveToThread(thread);
#endif
}
-GRenderWindow::~GRenderWindow()
-{
- if (emu_thread.isRunning())
- emu_thread.Stop();
-}
-
void GRenderWindow::SwapBuffers()
{
// MakeCurrent is already called in renderer_opengl
child->swapBuffers();
}
-void GRenderWindow::closeEvent(QCloseEvent* event)
-{
- if (emu_thread.isRunning())
- emu_thread.Stop();
- QWidget::closeEvent(event);
-}
-
void GRenderWindow::MakeCurrent()
{
child->makeCurrent();
@@ -288,7 +224,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent *event)
void GRenderWindow::mouseMoveEvent(QMouseEvent *event)
{
auto pos = event->pos();
- this->TouchMoved(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y()));
+ this->TouchMoved(static_cast<unsigned>(std::max(pos.x(), 0)), static_cast<unsigned>(std::max(pos.y(), 0)));
}
void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
@@ -335,3 +271,11 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
setMinimumSize(minimal_size.first, minimal_size.second);
}
+
+void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
+ this->emu_thread = emu_thread;
+}
+
+void GRenderWindow::OnEmulationStopping() {
+ emu_thread = nullptr;
+}
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 288da45a..d5d74c94 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -7,74 +7,59 @@
#include <QThread>
#include <QGLWidget>
-#include "common/common.h"
#include "common/emu_window.h"
+#include "common/thread.h"
class QScreen;
class QKeyEvent;
class GRenderWindow;
+class GMainWindow;
class EmuThread : public QThread
{
Q_OBJECT
public:
- /**
- * Set image filename
- *
- * @param filename
- * @warning Only call when not running!
- */
- void SetFilename(std::string filename);
+ EmuThread(GRenderWindow* render_window);
/**
* Start emulation (on new thread)
- *
* @warning Only call when not running!
*/
void run() override;
/**
- * Allow the CPU to process a single instruction (if cpu is not running)
- *
+ * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
* @note This function is thread-safe
*/
- void ExecStep() { exec_cpu_step = true; }
+ void ExecStep() { exec_step = true; }
/**
- * Allow the CPU to continue processing instructions without interruption
- *
+ * Sets whether the emulation thread is running or not
+ * @param running Boolean value, set the emulation thread to running if true
* @note This function is thread-safe
*/
- void SetCpuRunning(bool running) { cpu_running = running; }
+ void SetRunning(bool running) { this->running = running; }
/**
- * Allow the CPU to continue processing instructions without interruption
- *
- * @note This function is thread-safe
- */
- bool IsCpuRunning() { return cpu_running; }
-
+ * Check if the emulation thread is running or not
+ * @return True if the emulation thread is running, otherwise false
+ * @note This function is thread-safe
+ */
+ bool IsRunning() { return running; }
-public slots:
/**
- * Stop emulation and wait for the thread to finish.
- *
- * @details: This function will wait a second for the thread to finish; if it hasn't finished until then, we'll terminate() it and wait another second, hoping that it will be terminated by then.
- * @note: This function is thread-safe.
+ * Requests for the emulation thread to stop running
*/
- void Stop();
+ void RequestStop() {
+ stop_run = true;
+ running = false;
+ };
private:
- friend class GRenderWindow;
-
- EmuThread(GRenderWindow* render_window);
-
- std::string filename;
-
- bool exec_cpu_step;
- bool cpu_running;
+ bool exec_step;
+ bool running;
std::atomic<bool> stop_run;
GRenderWindow* render_window;
@@ -100,10 +85,7 @@ class GRenderWindow : public QWidget, public EmuWindow
Q_OBJECT
public:
- GRenderWindow(QWidget* parent = NULL);
- ~GRenderWindow();
-
- void closeEvent(QCloseEvent*) override;
+ GRenderWindow(QWidget* parent, EmuThread* emu_thread);
// EmuWindow implementation
void SwapBuffers() override;
@@ -116,8 +98,6 @@ public:
void restoreGeometry(const QByteArray& geometry); // overridden
QByteArray saveGeometry(); // overridden
- EmuThread& GetEmuThread();
-
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
@@ -134,15 +114,18 @@ public:
public slots:
void moveContext(); // overridden
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override;
QGLWidget* child;
- EmuThread emu_thread;
-
QByteArray geometry;
/// Device id of keyboard for use with KeyMap
int keyboard_id;
+
+ EmuThread* emu_thread;
};
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index ac250e0a..fb85121b 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -53,6 +53,12 @@ void Config::ReadValues() {
Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt();
qt_config->endGroup();
+ qt_config->beginGroup("Renderer");
+ Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat();
+ Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat();
+ Settings::values.bg_blue = qt_config->value("bg_blue", 1.0).toFloat();
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
qt_config->endGroup();
@@ -98,6 +104,13 @@ void Config::SaveValues() {
qt_config->setValue("frame_skip", Settings::values.frame_skip);
qt_config->endGroup();
+ qt_config->beginGroup("Renderer");
+ // Cast to double because Qt's written float values are not human-readable
+ qt_config->setValue("bg_red", (double)Settings::values.bg_red);
+ qt_config->setValue("bg_green", (double)Settings::values.bg_green);
+ qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
qt_config->endGroup();
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 9bb22ca2..94e20471 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -8,7 +8,7 @@
#include "core/core.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "common/symbols.h"
#include "core/arm/disassembler/arm_disasm.h"
@@ -27,7 +27,6 @@ CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent)
void CallstackWidget::OnDebugModeEntered()
{
- ARM_Disasm* disasm = new ARM_Disasm();
ARM_Interface* app_core = Core::g_app_core;
u32 sp = app_core->GetReg(13); //stack pointer
@@ -46,7 +45,7 @@ void CallstackWidget::OnDebugModeEntered()
/* TODO (mattvail) clean me, move to debugger interface */
u32 insn = Memory::Read32(call_addr);
- if (disasm->Decode(insn) == OP_BL)
+ if (ARM_Disasm::Decode(insn) == OP_BL)
{
std::string name;
// ripped from disasm
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index 54d21dc9..e99ec1b3 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -7,8 +7,7 @@
#include "../bootmanager.h"
#include "../hotkeys.h"
-#include "common/common.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/core.h"
#include "common/break_points.h"
@@ -18,8 +17,8 @@
#include "core/arm/disassembler/arm_disasm.h"
-DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
-
+DisassemblerModel::DisassemblerModel(QObject* parent) :
+ QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
}
int DisassemblerModel::columnCount(const QModelIndex& parent) const {
@@ -158,34 +157,28 @@ void DisassemblerModel::SetNextInstruction(unsigned int address) {
emit dataChanged(prev_index, prev_index);
}
-DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread)
-{
- disasm_ui.setupUi(this);
+DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) :
+ QDockWidget(parent), emu_thread(emu_thread), base_addr(0) {
- model = new DisassemblerModel(this);
- disasm_ui.treeView->setModel(model);
+ disasm_ui.setupUi(this);
RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut);
- connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep()));
connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause()));
connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));
- connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
- model, SLOT(OnSelectionChanged(const QModelIndex&)));
-
connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, SLOT(OnToggleStartStop()));
connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep()));
connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto()));
- connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint()));
+
+ setEnabled(false);
}
-void DisassemblerWidget::Init()
-{
+void DisassemblerWidget::Init() {
model->ParseFromAddress(Core::g_app_core->GetPC());
disasm_ui.treeView->resizeColumnToContents(0);
@@ -197,25 +190,21 @@ void DisassemblerWidget::Init()
disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
-void DisassemblerWidget::OnContinue()
-{
- emu_thread.SetCpuRunning(true);
+void DisassemblerWidget::OnContinue() {
+ emu_thread->SetRunning(true);
}
-void DisassemblerWidget::OnStep()
-{
+void DisassemblerWidget::OnStep() {
OnStepInto(); // change later
}
-void DisassemblerWidget::OnStepInto()
-{
- emu_thread.SetCpuRunning(false);
- emu_thread.ExecStep();
+void DisassemblerWidget::OnStepInto() {
+ emu_thread->SetRunning(false);
+ emu_thread->ExecStep();
}
-void DisassemblerWidget::OnPause()
-{
- emu_thread.SetCpuRunning(false);
+void DisassemblerWidget::OnPause() {
+ emu_thread->SetRunning(false);
// TODO: By now, the CPU might not have actually stopped...
if (Core::g_app_core) {
@@ -223,20 +212,15 @@ void DisassemblerWidget::OnPause()
}
}
-void DisassemblerWidget::OnToggleStartStop()
-{
- emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning());
+void DisassemblerWidget::OnToggleStartStop() {
+ emu_thread->SetRunning(!emu_thread->IsRunning());
}
-void DisassemblerWidget::OnDebugModeEntered()
-{
+void DisassemblerWidget::OnDebugModeEntered() {
ARMword next_instr = Core::g_app_core->GetPC();
- // TODO: Make BreakPoints less crappy (i.e. const-correct) so that this doesn't need a const_cast.
- if (const_cast<BreakPoints&>(model->GetBreakPoints()).IsAddressBreakPoint(next_instr))
- {
- emu_thread.SetCpuRunning(false);
- }
+ if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
+ emu_thread->SetRunning(false);
model->SetNextInstruction(next_instr);
@@ -245,16 +229,35 @@ void DisassemblerWidget::OnDebugModeEntered()
disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
-void DisassemblerWidget::OnDebugModeLeft()
-{
-
+void DisassemblerWidget::OnDebugModeLeft() {
}
-int DisassemblerWidget::SelectedRow()
-{
+int DisassemblerWidget::SelectedRow() {
QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex();
if (!index.isValid())
return -1;
return disasm_ui.treeView->selectionModel()->currentIndex().row();
}
+
+void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) {
+ this->emu_thread = emu_thread;
+
+ model = new DisassemblerModel(this);
+ disasm_ui.treeView->setModel(model);
+
+ connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+ model, SLOT(OnSelectionChanged(const QModelIndex&)));
+ connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
+ connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint()));
+
+ Init();
+ setEnabled(true);
+}
+
+void DisassemblerWidget::OnEmulationStopping() {
+ disasm_ui.treeView->setModel(nullptr);
+ delete model;
+ emu_thread = nullptr;
+ setEnabled(false);
+}
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h
index 5e19d7c5..340fb993 100644
--- a/src/citra_qt/debugger/disassembler.h
+++ b/src/citra_qt/debugger/disassembler.h
@@ -9,8 +9,8 @@
#include "ui_disassembler.h"
-#include "common/common.h"
#include "common/break_points.h"
+#include "common/common_types.h"
class QAction;
class EmuThread;
@@ -51,7 +51,7 @@ class DisassemblerWidget : public QDockWidget
Q_OBJECT
public:
- DisassemblerWidget(QWidget* parent, EmuThread& emu_thread);
+ DisassemblerWidget(QWidget* parent, EmuThread* emu_thread);
void Init();
@@ -65,6 +65,9 @@ public slots:
void OnDebugModeEntered();
void OnDebugModeLeft();
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
// returns -1 if no row is selected
int SelectedRow();
@@ -75,5 +78,5 @@ private:
u32 base_addr;
- EmuThread& emu_thread;
+ EmuThread* emu_thread;
};
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 92348be3..1da64f61 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -8,6 +8,8 @@
#include <QVBoxLayout>
#include <QLabel>
+#include "common/assert.h"
+
#include "graphics_breakpoints.h"
#include "graphics_breakpoints_p.h"
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h
index 232bfc86..34e72e85 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.h
@@ -25,7 +25,7 @@ public:
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
- bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
public slots:
void OnBreakPointHit(Pica::DebugContext::Event event);
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 9bcd2582..66e11dd5 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -159,7 +159,7 @@ void TextureInfoDockWidget::OnStrideChanged(int value) {
}
QPixmap TextureInfoDockWidget::ReloadPixmap() const {
- u8* src = Memory::GetPointer(Pica::PAddrToVAddr(info.physical_address));
+ u8* src = Memory::GetPhysicalPointer(info.physical_address);
return QPixmap::fromImage(LoadTexture(src, info));
}
@@ -274,7 +274,7 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
auto format = Pica::registers.GetTextures()[index].format;
auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
- u8* src = Memory::GetPointer(Pica::PAddrToVAddr(config.GetPhysicalAddress()));
+ u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
new_info_widget = new TextureInfoWidget(src, info);
} else {
new_info_widget = new QWidget;
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index d621d720..0c1a3f47 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -10,6 +10,8 @@
#include <QSpinBox>
#include "core/hw/gpu.h"
+#include "core/memory.h"
+
#include "video_core/color.h"
#include "video_core/pica.h"
#include "video_core/utils.h"
@@ -215,7 +217,7 @@ void GraphicsFramebufferWidget::OnUpdate()
u32 bytes_per_pixel = GraphicsFramebufferWidget::BytesPerPixel(framebuffer_format);
QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
- u8* buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address));
+ u8* buffer = Memory::GetPhysicalPointer(framebuffer_address);
for (unsigned int y = 0; y < framebuffer_height; ++y) {
for (unsigned int x = 0; x < framebuffer_width; ++x) {
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index ae0568b6..2ac1748b 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -26,7 +26,7 @@ static QVariant GetDataForColumn(int col, const AggregatedDuration& duration)
static const TimingCategoryInfo* GetCategoryInfo(int id)
{
const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
- if (id >= categories.size()) {
+ if ((size_t)id >= categories.size()) {
return nullptr;
} else {
return &categories[id];
@@ -98,7 +98,7 @@ QVariant ProfilerModel::data(const QModelIndex& index, int role) const
const TimingCategoryInfo* info = GetCategoryInfo(index.row() - 2);
return info != nullptr ? QString(info->name) : QVariant();
} else {
- if (index.row() - 2 < results.time_per_category.size()) {
+ if (index.row() - 2 < (int)results.time_per_category.size()) {
return GetDataForColumn(index.column(), results.time_per_category[index.row() - 2]);
} else {
return QVariant();
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index a6d87aa0..fabf279b 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -18,7 +18,7 @@ class ProfilerModel : public QAbstractItemModel
public:
ProfilerModel(QObject* parent);
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& child) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
diff --git a/src/citra_qt/debugger/ramview.cpp b/src/citra_qt/debugger/ramview.cpp
index 88570f2c..b6ebc7fc 100644
--- a/src/citra_qt/debugger/ramview.cpp
+++ b/src/citra_qt/debugger/ramview.cpp
@@ -4,8 +4,7 @@
#include "ramview.h"
-#include "common/common.h"
-#include "core/mem_map.h"
+
GRamView::GRamView(QWidget* parent) : QHexEdit(parent)
{
}
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp
index ab366615..5527a2af 100644
--- a/src/citra_qt/debugger/registers.cpp
+++ b/src/citra_qt/debugger/registers.cpp
@@ -7,8 +7,7 @@
#include "core/core.h"
#include "core/arm/arm_interface.h"
-RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
-{
+RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) {
cpu_regs_ui.setupUi(this);
tree = cpu_regs_ui.treeWidget;
@@ -18,8 +17,7 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
registers->setExpanded(true);
CSPR->setExpanded(true);
- for (int i = 0; i < 16; ++i)
- {
+ for (int i = 0; i < 16; ++i) {
QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0'))));
registers->addChild(child);
}
@@ -39,12 +37,16 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
CSPR->addChild(new QTreeWidgetItem(QStringList("C")));
CSPR->addChild(new QTreeWidgetItem(QStringList("Z")));
CSPR->addChild(new QTreeWidgetItem(QStringList("N")));
+
+ setEnabled(false);
}
-void RegistersWidget::OnDebugModeEntered()
-{
+void RegistersWidget::OnDebugModeEntered() {
ARM_Interface* app_core = Core::g_app_core;
+ if (app_core == nullptr)
+ return;
+
for (int i = 0; i < 16; ++i)
registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetReg(i), 8, 16, QLatin1Char('0')));
@@ -66,7 +68,22 @@ void RegistersWidget::OnDebugModeEntered()
CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than
}
-void RegistersWidget::OnDebugModeLeft()
-{
+void RegistersWidget::OnDebugModeLeft() {
+}
+
+void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) {
+ setEnabled(true);
+}
+
+void RegistersWidget::OnEmulationStopping() {
+ // Reset widget text
+ for (int i = 0; i < 16; ++i)
+ registers->child(i)->setText(1, QString(""));
+
+ for (int i = 0; i < 15; ++i)
+ CSPR->child(i)->setText(1, QString(""));
+
+ CSPR->setText(1, QString(""));
+ setEnabled(false);
}
diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h
index bf895562..68e3fb90 100644
--- a/src/citra_qt/debugger/registers.h
+++ b/src/citra_qt/debugger/registers.h
@@ -8,6 +8,7 @@
#include <QTreeWidgetItem>
class QTreeWidget;
+class EmuThread;
class RegistersWidget : public QDockWidget
{
@@ -20,6 +21,9 @@ public slots:
void OnDebugModeEntered();
void OnDebugModeLeft();
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
Ui::ARMRegisters cpu_regs_ui;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index e5ca0412..7b028e32 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -10,11 +10,11 @@
#include "qhexedit.h"
#include "main.h"
-#include "common/common.h"
#include "common/logging/text_formatter.h"
#include "common/logging/log.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
+#include "common/make_unique.h"
#include "common/platform.h"
#include "common/scope_exit.h"
@@ -46,7 +46,7 @@
#include "version.h"
-GMainWindow::GMainWindow()
+GMainWindow::GMainWindow() : emu_thread(nullptr)
{
Pica::g_debug_context = Pica::DebugContext::Construct();
@@ -55,14 +55,14 @@ GMainWindow::GMainWindow()
ui.setupUi(this);
statusBar()->hide();
- render_window = new GRenderWindow;
+ render_window = new GRenderWindow(this, emu_thread.get());
render_window->hide();
profilerWidget = new ProfilerWidget(this);
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
profilerWidget->hide();
- disasmWidget = new DisassemblerWidget(this, render_window->GetEmuThread());
+ disasmWidget = new DisassemblerWidget(this, emu_thread.get());
addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
disasmWidget->hide();
@@ -138,14 +138,12 @@ GMainWindow::GMainWindow()
connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
- // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
-
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping()));
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), registersWidget, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping()));
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
// Setup hotkeys
RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
@@ -196,32 +194,76 @@ void GMainWindow::OnDisplayTitleBars(bool show)
}
}
-void GMainWindow::BootGame(std::string filename)
-{
+void GMainWindow::BootGame(std::string filename) {
LOG_INFO(Frontend, "Citra starting...\n");
+
+ // Initialize the core emulation
System::Init(render_window);
- // Load a game or die...
+ // Load the game
if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {
LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ System::Shutdown();
+ return;
}
- disasmWidget->Init();
+ // Create and start the emulation thread
+ emu_thread = Common::make_unique<EmuThread>(render_window);
+ emit EmulationStarting(emu_thread.get());
+ emu_thread->start();
+
+ // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+
+ // Update the GUI
registersWidget->OnDebugModeEntered();
callstackWidget->OnDebugModeEntered();
-
- render_window->GetEmuThread().SetFilename(filename);
- render_window->GetEmuThread().start();
-
render_window->show();
+
OnStartGame();
}
+void GMainWindow::ShutdownGame() {
+ emu_thread->RequestStop();
+
+ // Release emu threads from any breakpoints
+ // This belongs after RequestStop() and before wait() because if emulation stops on a GPU
+ // breakpoint after (or before) RequestStop() is called, the emulation would never be able
+ // to continue out to the main loop and terminate. Thus wait() would hang forever.
+ // TODO(bunnei): This function is not thread safe, but it's being used as if it were
+ Pica::g_debug_context->ClearBreakpoints();
+
+ emit EmulationStopping();
+
+ // Wait for emulation thread to complete and delete it
+ emu_thread->wait();
+ emu_thread = nullptr;
+
+ // Shutdown the core emulation
+ System::Shutdown();
+
+ // Update the GUI
+ ui.action_Start->setEnabled(false);
+ ui.action_Pause->setEnabled(false);
+ ui.action_Stop->setEnabled(false);
+ render_window->hide();
+}
+
void GMainWindow::OnMenuLoadFile()
{
- QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
- if (filename.size())
- BootGame(filename.toLatin1().data());
+ QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)"));
+ if (filename.size()) {
+ // Shutdown previous session if the emu thread is still active...
+ if (emu_thread != nullptr)
+ ShutdownGame();
+
+ BootGame(filename.toLatin1().data());
+ }
}
void GMainWindow::OnMenuLoadSymbolMap() {
@@ -232,7 +274,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
void GMainWindow::OnStartGame()
{
- render_window->GetEmuThread().SetCpuRunning(true);
+ emu_thread->SetRunning(true);
ui.action_Start->setEnabled(false);
ui.action_Pause->setEnabled(true);
@@ -241,21 +283,15 @@ void GMainWindow::OnStartGame()
void GMainWindow::OnPauseGame()
{
- render_window->GetEmuThread().SetCpuRunning(false);
+ emu_thread->SetRunning(false);
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(true);
}
-void GMainWindow::OnStopGame()
-{
- render_window->GetEmuThread().SetCpuRunning(false);
- // TODO: Shutdown core
-
- ui.action_Start->setEnabled(true);
- ui.action_Pause->setEnabled(false);
- ui.action_Stop->setEnabled(false);
+void GMainWindow::OnStopGame() {
+ ShutdownGame();
}
void GMainWindow::OnOpenHotkeysDialog()
@@ -265,24 +301,22 @@ void GMainWindow::OnOpenHotkeysDialog()
}
-void GMainWindow::ToggleWindowMode()
-{
- bool enable = ui.action_Single_Window_Mode->isChecked();
- if (!enable && render_window->parent() != nullptr)
- {
- ui.horizontalLayout->removeWidget(render_window);
- render_window->setParent(nullptr);
- render_window->setVisible(true);
- render_window->RestoreGeometry();
- render_window->setFocusPolicy(Qt::NoFocus);
- }
- else if (enable && render_window->parent() == nullptr)
- {
+void GMainWindow::ToggleWindowMode() {
+ if (ui.action_Single_Window_Mode->isChecked()) {
+ // Render in the main window...
render_window->BackupGeometry();
ui.horizontalLayout->addWidget(render_window);
render_window->setVisible(true);
render_window->setFocusPolicy(Qt::ClickFocus);
render_window->setFocus();
+
+ } else {
+ // Render in a separate window...
+ ui.horizontalLayout->removeWidget(render_window);
+ render_window->setParent(nullptr);
+ render_window->setVisible(true);
+ render_window->RestoreGeometry();
+ render_window->setFocusPolicy(Qt::NoFocus);
}
}
@@ -303,6 +337,10 @@ void GMainWindow::closeEvent(QCloseEvent* event)
settings.setValue("firstStart", false);
SaveHotkeys(settings);
+ // Shutdown session if the emu thread is active...
+ if (emu_thread != nullptr)
+ ShutdownGame();
+
render_window->close();
QWidget::closeEvent(event);
@@ -312,7 +350,7 @@ void GMainWindow::closeEvent(QCloseEvent* event)
#undef main
#endif
-int __cdecl main(int argc, char* argv[])
+int main(int argc, char* argv[])
{
std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
Log::Filter log_filter(Log::Level::Info);
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 9b57c577..3e29534f 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -5,12 +5,14 @@
#ifndef _CITRA_QT_MAIN_HXX_
#define _CITRA_QT_MAIN_HXX_
+#include <memory>
#include <QMainWindow>
#include "ui_main.h"
class GImageInfo;
class GRenderWindow;
+class EmuThread;
class ProfilerWidget;
class DisassemblerWidget;
class RegistersWidget;
@@ -34,8 +36,27 @@ public:
GMainWindow();
~GMainWindow();
+signals:
+
+ /**
+ * Signal that is emitted when a new EmuThread has been created and an emulation session is
+ * about to start. At this time, the core system emulation has been initialized, and all
+ * emulation handles and memory should be valid.
+ *
+ * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to
+ * access/change emulation state).
+ */
+ void EmulationStarting(EmuThread* emu_thread);
+
+ /**
+ * Signal that is emitted when emulation is about to stop. At this time, the EmuThread and core
+ * system emulation handles and memory are still valid, but are about become invalid.
+ */
+ void EmulationStopping();
+
private:
void BootGame(std::string filename);
+ void ShutdownGame();
void closeEvent(QCloseEvent* event) override;
@@ -55,6 +76,8 @@ private:
GRenderWindow* render_window;
+ std::unique_ptr<EmuThread> emu_thread;
+
ProfilerWidget* profilerWidget;
DisassemblerWidget* disasmWidget;
RegistersWidget* registersWidget;
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index a3752ac1..68980646 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -90,6 +90,9 @@
</property>
</action>
<action name="action_Start">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="text">
<string>&amp;Start</string>
</property>
diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp
index 2e2076a2..de406011 100644
--- a/src/citra_qt/util/spinbox.cpp
+++ b/src/citra_qt/util/spinbox.cpp
@@ -29,6 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <cstdlib>
#include <QLineEdit>
#include <QRegExpValidator>
@@ -206,7 +207,7 @@ QString CSpinBox::TextFromValue()
{
return prefix
+ QString(HasSign() ? ((value < 0) ? "-" : "+") : "")
- + QString("%1").arg(abs(value), num_digits, base, QLatin1Char('0')).toUpper()
+ + QString("%1").arg(std::abs(value), num_digits, base, QLatin1Char('0')).toUpper()
+ suffix;
}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index daa2d59d..f8fc6450 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -5,13 +5,10 @@ set(SRCS
break_points.cpp
emu_window.cpp
file_util.cpp
- hash.cpp
key_map.cpp
logging/filter.cpp
logging/text_formatter.cpp
logging/backend.cpp
- math_util.cpp
- mem_arena.cpp
memory_util.cpp
misc.cpp
profiler.cpp
@@ -27,7 +24,6 @@ set(HEADERS
bit_field.h
break_points.h
chunk_file.h
- common.h
common_funcs.h
common_paths.h
common_types.h
@@ -37,7 +33,6 @@ set(HEADERS
emu_window.h
fifo_queue.h
file_util.h
- hash.h
key_map.h
linear_disk_cache.h
logging/text_formatter.h
@@ -46,7 +41,6 @@ set(HEADERS
logging/backend.h
make_unique.h
math_util.h
- mem_arena.h
memory_util.h
platform.h
profiler.h
diff --git a/src/common/assert.h b/src/common/assert.h
index 9ca7adb1..4f26c63e 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,6 +4,7 @@
#pragma once
+#include <cstdio>
#include <cstdlib>
#include "common/common_funcs.h"
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 8eab054b..1f3ecf84 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -35,7 +35,7 @@
#include <limits>
#include <type_traits>
-#include "common/common.h"
+#include "common/common_funcs.h"
/*
* Abstract bitfield class
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
index 2655d3ce..023a485a 100644
--- a/src/common/break_points.cpp
+++ b/src/common/break_points.cpp
@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
#include "common/debug_interface.h"
#include "common/break_points.h"
#include "common/logging/log.h"
@@ -10,14 +9,14 @@
#include <sstream>
#include <algorithm>
-bool BreakPoints::IsAddressBreakPoint(u32 iAddress)
+bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const
{
auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; };
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
return it != m_BreakPoints.end();
}
-bool BreakPoints::IsTempBreakPoint(u32 iAddress)
+bool BreakPoints::IsTempBreakPoint(u32 iAddress) const
{
auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; };
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
diff --git a/src/common/break_points.h b/src/common/break_points.h
index 5557cd50..f0a55e7b 100644
--- a/src/common/break_points.h
+++ b/src/common/break_points.h
@@ -7,7 +7,7 @@
#include <vector>
#include <string>
-#include "common/common.h"
+#include "common/common_types.h"
class DebugInterface;
@@ -56,8 +56,8 @@ public:
void AddFromStrings(const TBreakPointsStr& bps);
// is address breakpoint
- bool IsAddressBreakPoint(u32 iAddress);
- bool IsTempBreakPoint(u32 iAddress);
+ bool IsAddressBreakPoint(u32 iAddress) const;
+ bool IsTempBreakPoint(u32 iAddress) const;
// Add BreakPoint
void Add(u32 em_address, bool temp=false);
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index 3f97d56b..dcd80525 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -34,8 +34,9 @@
#include <set>
#include <type_traits>
-#include "common/common.h"
+#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
template <class T>
struct LinkedListItem : public T
diff --git a/src/common/common.h b/src/common/common.h
deleted file mode 100644
index f7d0f55c..00000000
--- a/src/common/common.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-// DO NOT EVER INCLUDE <windows.h> directly _or indirectly_ from this file
-// since it slows down the build a lot.
-
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-
-#define STACKALIGN
-
-// An inheritable class to disallow the copy constructor and operator= functions
-class NonCopyable
-{
-protected:
- NonCopyable() {}
- NonCopyable(const NonCopyable&&) {}
- void operator=(const NonCopyable&&) {}
-private:
- NonCopyable(NonCopyable&);
- NonCopyable& operator=(NonCopyable& other);
-};
-
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "common/common_types.h"
-#include "common/common_funcs.h"
-#include "common/common_paths.h"
-#include "common/platform.h"
-
-#ifdef __APPLE__
-// The Darwin ABI requires that stack frames be aligned to 16-byte boundaries.
-// This is only needed on i386 gcc - x86_64 already aligns to 16 bytes.
- #if defined __i386__ && defined __GNUC__
- #undef STACKALIGN
- #define STACKALIGN __attribute__((__force_align_arg_pointer__))
- #endif
-#elif defined _WIN32
-// Check MSC ver
- #if defined _MSC_VER && _MSC_VER <= 1000
- #error needs at least version 1000 of MSC
- #endif
-
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
-
-// Alignment
- #define MEMORY_ALIGNED16(x) __declspec(align(16)) x
- #define MEMORY_ALIGNED32(x) __declspec(align(32)) x
- #define MEMORY_ALIGNED64(x) __declspec(align(64)) x
- #define MEMORY_ALIGNED128(x) __declspec(align(128)) x
- #define MEMORY_ALIGNED16_DECL(x) __declspec(align(16)) x
- #define MEMORY_ALIGNED64_DECL(x) __declspec(align(64)) x
-#endif
-
-// Windows compatibility
-#ifndef _WIN32
- #ifdef _LP64
- #define _M_X64 1
- #else
- #define _M_IX86 1
- #endif
- #define __forceinline inline __attribute__((always_inline))
- #define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x
- #define MEMORY_ALIGNED32(x) __attribute__((aligned(32))) x
- #define MEMORY_ALIGNED64(x) __attribute__((aligned(64))) x
- #define MEMORY_ALIGNED128(x) __attribute__((aligned(128))) x
- #define MEMORY_ALIGNED16_DECL(x) __attribute__((aligned(16))) x
- #define MEMORY_ALIGNED64_DECL(x) __attribute__((aligned(64))) x
-#endif
-
-#ifdef _MSC_VER
- #define __strdup _strdup
- #define __getcwd _getcwd
- #define __chdir _chdir
-#else
- #define __strdup strdup
- #define __getcwd getcwd
- #define __chdir chdir
-#endif
-
-#if defined _M_GENERIC
-# define _M_SSE 0x0
-#elif defined __GNUC__
-# if defined __SSE4_2__
-# define _M_SSE 0x402
-# elif defined __SSE4_1__
-# define _M_SSE 0x401
-# elif defined __SSSE3__
-# define _M_SSE 0x301
-# elif defined __SSE3__
-# define _M_SSE 0x300
-# endif
-#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
-# define _M_SSE 0x402
-#endif
-
-// Host communication.
-enum HOST_COMM
-{
- // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on
- WM_USER_STOP = 10,
- WM_USER_CREATE,
- WM_USER_SETCURSOR,
-};
-
-// Used for notification on emulation state
-enum EMUSTATE_CHANGE
-{
- EMUSTATE_CHANGE_PLAY = 1,
- EMUSTATE_CHANGE_PAUSE,
- EMUSTATE_CHANGE_STOP
-};
-
-#include "swap.h"
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index e76cb7d6..91b74c6b 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -7,13 +7,6 @@
#include "common_types.h"
#include <cstdlib>
-#ifdef _WIN32
-#define SLEEP(x) Sleep(x)
-#else
-#include <unistd.h>
-#define SLEEP(x) usleep(x*1000)
-#endif
-
#define b2(x) ( (x) | ( (x) >> 1) )
#define b4(x) ( b2(x) | ( b2(x) >> 2) )
@@ -34,6 +27,20 @@
#define INSERT_PADDING_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)]
#define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)]
+#ifdef _WIN32
+ // Alignment
+ #define MEMORY_ALIGNED16(x) __declspec(align(16)) x
+ #define MEMORY_ALIGNED32(x) __declspec(align(32)) x
+ #define MEMORY_ALIGNED64(x) __declspec(align(64)) x
+ #define MEMORY_ALIGNED128(x) __declspec(align(128)) x
+#else
+ #define __forceinline inline __attribute__((always_inline))
+ #define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x
+ #define MEMORY_ALIGNED32(x) __attribute__((aligned(32))) x
+ #define MEMORY_ALIGNED64(x) __attribute__((aligned(64))) x
+ #define MEMORY_ALIGNED128(x) __attribute__((aligned(128))) x
+#endif
+
#ifndef _MSC_VER
#include <errno.h>
@@ -73,61 +80,11 @@ inline u64 _rotr64(u64 x, unsigned int shift){
}
#else // _MSC_VER
-#include <locale.h>
-
-// Function Cross-Compatibility
- #define strcasecmp _stricmp
- #define strncasecmp _strnicmp
- #define unlink _unlink
+ // Function Cross-Compatibility
#define snprintf _snprintf
- #define vscprintf _vscprintf
-// Locale Cross-Compatibility
+ // Locale Cross-Compatibility
#define locale_t _locale_t
- #define freelocale _free_locale
- #define newlocale(mask, locale, base) _create_locale(mask, locale)
-
- #define LC_GLOBAL_LOCALE ((locale_t)-1)
- #define LC_ALL_MASK LC_ALL
- #define LC_COLLATE_MASK LC_COLLATE
- #define LC_CTYPE_MASK LC_CTYPE
- #define LC_MONETARY_MASK LC_MONETARY
- #define LC_NUMERIC_MASK LC_NUMERIC
- #define LC_TIME_MASK LC_TIME
-
- inline locale_t uselocale(locale_t new_locale)
- {
- // Retrieve the current per thread locale setting
- bool bIsPerThread = (_configthreadlocale(0) == _ENABLE_PER_THREAD_LOCALE);
-
- // Retrieve the current thread-specific locale
- locale_t old_locale = bIsPerThread ? _get_current_locale() : LC_GLOBAL_LOCALE;
-
- if(new_locale == LC_GLOBAL_LOCALE)
- {
- // Restore the global locale
- _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
- }
- else if(new_locale != nullptr)
- {
- // Configure the thread to set the locale only for this thread
- _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
-
- // Set all locale categories
- for(int i = LC_MIN; i <= LC_MAX; i++)
- setlocale(i, new_locale->locinfo->lc_category[i].locale);
- }
-
- return old_locale;
- }
-
-// 64 bit offsets for windows
- #define fseeko _fseeki64
- #define ftello _ftelli64
- #define atoll _atoi64
- #define stat64 _stat64
- #define fstat64 _fstat64
- #define fileno _fileno
extern "C" {
__declspec(dllimport) void __stdcall DebugBreak(void);
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 440b0606..2903f2cf 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -4,9 +4,6 @@
#pragma once
-// Make sure we pick up USER_DIR if set in config.h
-#include "common/common.h"
-
// Directory separators, do we need this?
#define DIR_SEP "/"
#define DIR_SEP_CHR '/'
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 1b453e7f..f6de0adf 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -47,6 +47,11 @@ typedef std::int64_t s64; ///< 64-bit signed int
typedef float f32; ///< 32-bit floating point
typedef double f64; ///< 64-bit floating point
+// TODO: It would be nice to eventually replace these with strong types that prevent accidental
+// conversion between each other.
+typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
+typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
+
/// Union for fast 16-bit type casting
union t16 {
u8 _u8[2]; ///< 8-bit unsigned char(s)
@@ -73,28 +78,12 @@ union t64 {
u8 _u8[8]; ///< 8-bit unsigned char(s)
};
-namespace Common {
-/// Rectangle data structure
-class Rect {
-public:
- Rect(int x0=0, int y0=0, int x1=0, int y1=0) {
- x0_ = x0;
- y0_ = y0;
- x1_ = x1;
- y1_ = y1;
- }
- ~Rect() { }
-
- int x0_; ///< Rect top left X-coordinate
- int y0_; ///< Rect top left Y-coordinate
- int x1_; ///< Rect bottom left X-coordinate
- int y1_; ///< Rect bottom right Y-coordinate
-
- inline u32 width() const { return std::abs(x1_ - x0_); }
- inline u32 height() const { return std::abs(y1_ - y0_); }
+// An inheritable class to disallow the copy constructor and operator= functions
+class NonCopyable {
+protected:
+ NonCopyable() = default;
+ ~NonCopyable() = default;
- inline bool operator == (const Rect& val) const {
- return (x0_ == val.x0_ && y0_ == val.y0_ && x1_ == val.x1_ && y1_ == val.y1_);
- }
+ NonCopyable(NonCopyable&) = delete;
+ NonCopyable& operator=(NonCopyable&) = delete;
};
-}
diff --git a/src/common/concurrent_ring_buffer.h b/src/common/concurrent_ring_buffer.h
index fc18e6c8..c5889513 100644
--- a/src/common/concurrent_ring_buffer.h
+++ b/src/common/concurrent_ring_buffer.h
@@ -10,7 +10,7 @@
#include <mutex>
#include <thread>
-#include "common/common.h" // for NonCopyable
+#include "common/common_types.h" // for NonCopyable
namespace Common {
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 6516fc63..f5b6c730 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -28,6 +28,17 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi
framebuffer_x < layout.bottom_screen.right);
}
+std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
+
+ new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
+ new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
+
+ new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
+ new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
+
+ return std::make_tuple(new_x, new_y);
+}
+
void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
return;
@@ -52,14 +63,13 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!touch_pressed)
return;
- if (IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
- TouchPressed(framebuffer_x, framebuffer_y);
- else
- TouchReleased();
+ if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
+ std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
+
+ TouchPressed(framebuffer_x, framebuffer_y);
}
-EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width,
- unsigned height) {
+EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
ASSERT(width > 0);
ASSERT(height > 0);
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index c8e2de04..8eca6b5d 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -4,11 +4,11 @@
#pragma once
-#include "common/common.h"
-#include "common/scm_rev.h"
-#include "common/string_util.h"
+#include "common/common_types.h"
#include "common/key_map.h"
#include "common/math_util.h"
+#include "common/scm_rev.h"
+#include "common/string_util.h"
/**
* Abstraction class used to provide an interface between emulation code and the frontend
@@ -206,5 +206,10 @@ private:
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
+ /**
+ * Clip the provided coordinates to be inside the touchscreen area.
+ */
+ std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
+
Service::HID::PadState pad_state;
};
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 4ef4918d..7cdd1484 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -2,42 +2,52 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_paths.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#ifdef _WIN32
-#include <windows.h>
-#include <shlobj.h> // for SHGetFolderPath
-#include <shellapi.h>
-#include <commdlg.h> // for GetSaveFileName
-#include <io.h>
-#include <direct.h> // getcwd
-#include <tchar.h>
+ #include <windows.h>
+ #include <shlobj.h> // for SHGetFolderPath
+ #include <shellapi.h>
+ #include <commdlg.h> // for GetSaveFileName
+ #include <io.h>
+ #include <direct.h> // getcwd
+ #include <tchar.h>
+
+ // 64 bit offsets for windows
+ #define fseeko _fseeki64
+ #define ftello _ftelli64
+ #define atoll _atoi64
+ #define stat64 _stat64
+ #define fstat64 _fstat64
+ #define fileno _fileno
#else
-#include <sys/param.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <unistd.h>
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <pwd.h>
+ #include <unistd.h>
#endif
#if defined(__APPLE__)
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFURL.h>
-#include <CoreFoundation/CFBundle.h>
+ #include <CoreFoundation/CFString.h>
+ #include <CoreFoundation/CFURL.h>
+ #include <CoreFoundation/CFBundle.h>
#endif
#include <algorithm>
#include <sys/stat.h>
#ifndef S_ISDIR
-#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+ #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif
#ifdef BSD4_4
-#define stat64 stat
-#define fstat64 fstat
+ #define stat64 stat
+ #define fstat64 fstat
#endif
// This namespace has various generic functions related to files and paths.
@@ -589,7 +599,7 @@ std::string GetCurrentDir()
{
char *dir;
// Get the current working directory (getcwd uses malloc)
- if (!(dir = __getcwd(nullptr, 0))) {
+ if (!(dir = getcwd(nullptr, 0))) {
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s",
GetLastErrorMsg());
@@ -603,7 +613,7 @@ std::string GetCurrentDir()
// Sets the current directory to the given directory
bool SetCurrentDir(const std::string &directory)
{
- return __chdir(directory.c_str()) == 0;
+ return chdir(directory.c_str()) == 0;
}
#if defined(__APPLE__)
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 86aab2e3..b6582929 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -11,7 +11,7 @@
#include <string>
#include <vector>
-#include "common/common.h"
+#include "common/common_types.h"
#include "common/string_util.h"
// User directory indices for GetUserPath
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
deleted file mode 100644
index 0624dab8..00000000
--- a/src/common/hash.cpp
+++ /dev/null
@@ -1,521 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-
-#include "common/hash.h"
-#if _M_SSE >= 0x402
-#include "common/cpu_detect.h"
-#include <nmmintrin.h>
-#endif
-
-static u64 (*ptrHashFunction)(const u8 *src, int len, u32 samples) = &GetMurmurHash3;
-
-// uint32_t
-// WARNING - may read one more byte!
-// Implementation from Wikipedia.
-u32 HashFletcher(const u8* data_u8, size_t length)
-{
- const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
- size_t len = (length + 1) / 2; /* Length in 16-bit words */
- u32 sum1 = 0xffff, sum2 = 0xffff;
-
- while (len)
- {
- size_t tlen = len > 360 ? 360 : len;
- len -= tlen;
-
- do {
- sum1 += *data++;
- sum2 += sum1;
- }
- while (--tlen);
-
- sum1 = (sum1 & 0xffff) + (sum1 >> 16);
- sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- }
-
- // Second reduction step to reduce sums to 16 bits
- sum1 = (sum1 & 0xffff) + (sum1 >> 16);
- sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- return(sum2 << 16 | sum1);
-}
-
-
-// Implementation from Wikipedia
-// Slightly slower than Fletcher above, but slightly more reliable.
-#define MOD_ADLER 65521
-// data: Pointer to the data to be summed; len is in bytes
-u32 HashAdler32(const u8* data, size_t len)
-{
- u32 a = 1, b = 0;
-
- while (len)
- {
- size_t tlen = len > 5550 ? 5550 : len;
- len -= tlen;
-
- do
- {
- a += *data++;
- b += a;
- }
- while (--tlen);
-
- a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
- b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
- }
-
- // It can be shown that a <= 0x1013a here, so a single subtract will do.
- if (a >= MOD_ADLER)
- {
- a -= MOD_ADLER;
- }
-
- // It can be shown that b can reach 0xfff87 here.
- b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
-
- if (b >= MOD_ADLER)
- {
- b -= MOD_ADLER;
- }
-
- return((b << 16) | a);
-}
-
-// Stupid hash - but can't go back now :)
-// Don't use for new things. At least it's reasonably fast.
-u32 HashEctor(const u8* ptr, int length)
-{
- u32 crc = 0;
-
- for (int i = 0; i < length; i++)
- {
- crc ^= ptr[i];
- crc = (crc << 3) | (crc >> 29);
- }
-
- return(crc);
-}
-
-
-#ifdef _M_X64
-
-//-----------------------------------------------------------------------------
-// Block read - if your platform needs to do endian-swapping or can only
-// handle aligned reads, do the conversion here
-
-inline u64 getblock(const u64 * p, int i)
-{
- return p[i];
-}
-
-//----------
-// Block mix - combine the key bits with the hash bits and scramble everything
-
-inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2)
-{
- k1 *= c1;
- k1 = _rotl64(k1,23);
- k1 *= c2;
- h1 ^= k1;
- h1 += h2;
-
- h2 = _rotl64(h2,41);
-
- k2 *= c2;
- k2 = _rotl64(k2,23);
- k2 *= c1;
- h2 ^= k2;
- h2 += h1;
-
- h1 = h1*3+0x52dce729;
- h2 = h2*3+0x38495ab5;
-
- c1 = c1*5+0x7b7d159c;
- c2 = c2*5+0x6bce6396;
-}
-
-//----------
-// Finalization mix - avalanches all bits to within 0.05% bias
-
-inline u64 fmix64(u64 k)
-{
- k ^= k >> 33;
- k *= 0xff51afd7ed558ccd;
- k ^= k >> 33;
- k *= 0xc4ceb9fe1a85ec53;
- k ^= k >> 33;
-
- return k;
-}
-
-u64 GetMurmurHash3(const u8 *src, int len, u32 samples)
-{
- const u8 * data = (const u8*)src;
- const int nblocks = len / 16;
- u32 Step = (len / 8);
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
-
- u64 h1 = 0x9368e53c2f6af274;
- u64 h2 = 0x586dcd208f7cd3fd;
-
- u64 c1 = 0x87c37b91114253d5;
- u64 c2 = 0x4cf5ad432745937f;
-
-
- //----------
- // body
-
- const u64 * blocks = (const u64 *)(data);
-
- for(int i = 0; i < nblocks; i+=Step)
- {
- u64 k1 = getblock(blocks,i*2+0);
- u64 k2 = getblock(blocks,i*2+1);
-
- bmix64(h1,h2,k1,k2,c1,c2);
- }
-
- //----------
- // tail
-
- const u8 * tail = (const u8*)(data + nblocks*16);
-
- u64 k1 = 0;
- u64 k2 = 0;
-
- switch(len & 15)
- {
- case 15: k2 ^= u64(tail[14]) << 48;
- case 14: k2 ^= u64(tail[13]) << 40;
- case 13: k2 ^= u64(tail[12]) << 32;
- case 12: k2 ^= u64(tail[11]) << 24;
- case 11: k2 ^= u64(tail[10]) << 16;
- case 10: k2 ^= u64(tail[ 9]) << 8;
- case 9: k2 ^= u64(tail[ 8]) << 0;
-
- case 8: k1 ^= u64(tail[ 7]) << 56;
- case 7: k1 ^= u64(tail[ 6]) << 48;
- case 6: k1 ^= u64(tail[ 5]) << 40;
- case 5: k1 ^= u64(tail[ 4]) << 32;
- case 4: k1 ^= u64(tail[ 3]) << 24;
- case 3: k1 ^= u64(tail[ 2]) << 16;
- case 2: k1 ^= u64(tail[ 1]) << 8;
- case 1: k1 ^= u64(tail[ 0]) << 0;
- bmix64(h1,h2,k1,k2,c1,c2);
- };
-
- //----------
- // finalization
-
- h2 ^= len;
-
- h1 += h2;
- h2 += h1;
-
- h1 = fmix64(h1);
- h2 = fmix64(h2);
-
- h1 += h2;
-
- return h1;
-}
-
-
-// CRC32 hash using the SSE4.2 instruction
-u64 GetCRC32(const u8 *src, int len, u32 samples)
-{
-#if _M_SSE >= 0x402
- u64 h = len;
- u32 Step = (len / 8);
- const u64 *data = (const u64 *)src;
- const u64 *end = data + Step;
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
- while(data < end)
- {
- h = _mm_crc32_u64(h, data[0]);
- data += Step;
- }
-
- const u8 *data2 = (const u8*)end;
- return _mm_crc32_u64(h, u64(data2[0]));
-#else
- return 0;
-#endif
-}
-
-
-/*
- * NOTE: This hash function is used for custom texture loading/dumping, so
- * it should not be changed, which would require all custom textures to be
- * recalculated for their new hash values. If the hashing function is
- * changed, make sure this one is still used when the legacy parameter is
- * true.
- */
-u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
-{
- const u64 m = 0xc6a4a7935bd1e995;
- u64 h = len * m;
- const int r = 47;
- u32 Step = (len / 8);
- const u64 *data = (const u64 *)src;
- const u64 *end = data + Step;
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
- while(data < end)
- {
- u64 k = data[0];
- data+=Step;
- k *= m;
- k ^= k >> r;
- k *= m;
- h ^= k;
- h *= m;
- }
-
- const u8 * data2 = (const u8*)end;
-
- switch(len & 7)
- {
- case 7: h ^= u64(data2[6]) << 48;
- case 6: h ^= u64(data2[5]) << 40;
- case 5: h ^= u64(data2[4]) << 32;
- case 4: h ^= u64(data2[3]) << 24;
- case 3: h ^= u64(data2[2]) << 16;
- case 2: h ^= u64(data2[1]) << 8;
- case 1: h ^= u64(data2[0]);
- h *= m;
- };
-
- h ^= h >> r;
- h *= m;
- h ^= h >> r;
-
- return h;
-}
-#else
-// CRC32 hash using the SSE4.2 instruction
-u64 GetCRC32(const u8 *src, int len, u32 samples)
-{
-#if _M_SSE >= 0x402
- u32 h = len;
- u32 Step = (len/4);
- const u32 *data = (const u32 *)src;
- const u32 *end = data + Step;
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
- while(data < end)
- {
- h = _mm_crc32_u32(h, data[0]);
- data += Step;
- }
-
- const u8 *data2 = (const u8*)end;
- return (u64)_mm_crc32_u32(h, u32(data2[0]));
-#else
- return 0;
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Block read - if your platform needs to do endian-swapping or can only
-// handle aligned reads, do the conversion here
-
-inline u32 getblock(const u32 * p, int i)
-{
- return p[i];
-}
-
-//----------
-// Finalization mix - force all bits of a hash block to avalanche
-
-// avalanches all bits to within 0.25% bias
-
-inline u32 fmix32(u32 h)
-{
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- return h;
-}
-
-inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2)
-{
- k1 *= c1;
- k1 = _rotl(k1,11);
- k1 *= c2;
- h1 ^= k1;
- h1 += h2;
-
- h2 = _rotl(h2,17);
-
- k2 *= c2;
- k2 = _rotl(k2,11);
- k2 *= c1;
- h2 ^= k2;
- h2 += h1;
-
- h1 = h1*3+0x52dce729;
- h2 = h2*3+0x38495ab5;
-
- c1 = c1*5+0x7b7d159c;
- c2 = c2*5+0x6bce6396;
-}
-
-//----------
-
-u64 GetMurmurHash3(const u8* src, int len, u32 samples)
-{
- const u8 * data = (const u8*)src;
- u32 out[2];
- const int nblocks = len / 8;
- u32 Step = (len / 4);
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
-
- u32 h1 = 0x8de1c3ac;
- u32 h2 = 0xbab98226;
-
- u32 c1 = 0x95543787;
- u32 c2 = 0x2ad7eb25;
-
- //----------
- // body
-
- const u32 * blocks = (const u32 *)(data + nblocks*8);
-
- for(int i = -nblocks; i < 0; i+=Step)
- {
- u32 k1 = getblock(blocks,i*2+0);
- u32 k2 = getblock(blocks,i*2+1);
-
- bmix32(h1,h2,k1,k2,c1,c2);
- }
-
- //----------
- // tail
-
- const u8 * tail = (const u8*)(data + nblocks*8);
-
- u32 k1 = 0;
- u32 k2 = 0;
-
- switch(len & 7)
- {
- case 7: k2 ^= tail[6] << 16;
- case 6: k2 ^= tail[5] << 8;
- case 5: k2 ^= tail[4] << 0;
- case 4: k1 ^= tail[3] << 24;
- case 3: k1 ^= tail[2] << 16;
- case 2: k1 ^= tail[1] << 8;
- case 1: k1 ^= tail[0] << 0;
- bmix32(h1,h2,k1,k2,c1,c2);
- };
-
- //----------
- // finalization
-
- h2 ^= len;
-
- h1 += h2;
- h2 += h1;
-
- h1 = fmix32(h1);
- h2 = fmix32(h2);
-
- h1 += h2;
- h2 += h1;
-
- out[0] = h1;
- out[1] = h2;
-
- return *((u64 *)&out);
-}
-
-/*
- * FIXME: The old 32-bit version of this hash made different hashes than the
- * 64-bit version. Until someone can make a new version of the 32-bit one that
- * makes identical hashes, this is just a c/p of the 64-bit one.
- */
-u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
-{
- const u64 m = 0xc6a4a7935bd1e995ULL;
- u64 h = len * m;
- const int r = 47;
- u32 Step = (len / 8);
- const u64 *data = (const u64 *)src;
- const u64 *end = data + Step;
- if(samples == 0) samples = std::max(Step, 1u);
- Step = Step / samples;
- if(Step < 1) Step = 1;
- while(data < end)
- {
- u64 k = data[0];
- data+=Step;
- k *= m;
- k ^= k >> r;
- k *= m;
- h ^= k;
- h *= m;
- }
-
- const u8 * data2 = (const u8*)end;
-
- switch(len & 7)
- {
- case 7: h ^= u64(data2[6]) << 48;
- case 6: h ^= u64(data2[5]) << 40;
- case 5: h ^= u64(data2[4]) << 32;
- case 4: h ^= u64(data2[3]) << 24;
- case 3: h ^= u64(data2[2]) << 16;
- case 2: h ^= u64(data2[1]) << 8;
- case 1: h ^= u64(data2[0]);
- h *= m;
- };
-
- h ^= h >> r;
- h *= m;
- h ^= h >> r;
-
- return h;
-}
-#endif
-
-u64 GetHash64(const u8 *src, int len, u32 samples)
-{
- return ptrHashFunction(src, len, samples);
-}
-
-// sets the hash function used for the texture cache
-void SetHash64Function(bool useHiresTextures)
-{
- if (useHiresTextures)
- {
- ptrHashFunction = &GetHashHiresTexture;
- }
-#if _M_SSE >= 0x402
- else if (cpu_info.bSSE4_2 && !useHiresTextures) // sse crc32 version
- {
- ptrHashFunction = &GetCRC32;
- }
-#endif
- else
- {
- ptrHashFunction = &GetMurmurHash3;
- }
-}
-
-
-
diff --git a/src/common/hash.h b/src/common/hash.h
deleted file mode 100644
index 3ac42bc4..00000000
--- a/src/common/hash.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common.h"
-
-u32 HashFletcher(const u8* data_u8, size_t length); // FAST. Length & 1 == 0.
-u32 HashAdler32(const u8* data, size_t len); // Fairly accurate, slightly slower
-u32 HashFNV(const u8* ptr, int length); // Another fast and decent hash
-u32 HashEctor(const u8* ptr, int length); // JUNK. DO NOT USE FOR NEW THINGS
-u64 GetCRC32(const u8 *src, int len, u32 samples); // SSE4.2 version of CRC32
-u64 GetHashHiresTexture(const u8 *src, int len, u32 samples);
-u64 GetMurmurHash3(const u8 *src, int len, u32 samples);
-u64 GetHash64(const u8 *src, int len, u32 samples);
-void SetHash64Function(bool useHiresTextures);
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h
index 74ce74ab..48529cf4 100644
--- a/src/common/linear_disk_cache.h
+++ b/src/common/linear_disk_cache.h
@@ -4,7 +4,7 @@
#pragma once
-#include "common/common.h"
+#include "common/common_types.h"
#include <fstream>
// defined in Version.cpp
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 649640e7..7d3534a4 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -39,6 +39,8 @@ static std::shared_ptr<Logger> global_logger;
SUB(Service, AC) \
SUB(Service, PTM) \
SUB(Service, LDR) \
+ SUB(Service, NIM) \
+ SUB(Service, NWM) \
SUB(Service, CFG) \
SUB(Service, DSP) \
SUB(Service, HID) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 83d64145..123641cb 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -59,6 +59,8 @@ enum class Class : ClassType {
Service_AC, ///< The AC (WiFi status) service
Service_PTM, ///< The PTM (Power status & misc.) service
Service_LDR, ///< The LDR (3ds dll loader) service
+ Service_NIM, ///< The NIM (Network interface manager) service
+ Service_NWM, ///< The NWM (Network manager) service
Service_CFG, ///< The CFG (Configuration) service
Service_DSP, ///< The DSP (DSP control) service
Service_HID, ///< The HID (User input) service
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index 36c91c4f..45be6d0a 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -14,6 +14,7 @@
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
+#include "common/common_funcs.h"
#include "common/string_util.h"
namespace Log {
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp
deleted file mode 100644
index a83592dd..00000000
--- a/src/common/math_util.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-
-#include "common/common.h"
-#include "common/math_util.h"
-
-#include <numeric> // Necessary on OS X, but not Linux
-
-namespace MathUtil
-{
-
-u32 ClassifyDouble(double dvalue)
-{
- // TODO: Optimize the below to be as fast as possible.
- IntDouble value;
- value.d = dvalue;
- u64 sign = value.i & DOUBLE_SIGN;
- u64 exp = value.i & DOUBLE_EXP;
- if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP)
- {
- // Nice normalized number.
- return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
- }
- else
- {
- u64 mantissa = value.i & DOUBLE_FRAC;
- if (mantissa)
- {
- if (exp)
- {
- return PPC_FPCLASS_QNAN;
- }
- else
- {
- // Denormalized number.
- return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
- }
- }
- else if (exp)
- {
- //Infinite
- return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
- }
- else
- {
- //Zero
- return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
- }
- }
-}
-
-u32 ClassifyFloat(float fvalue)
-{
- // TODO: Optimize the below to be as fast as possible.
- IntFloat value;
- value.f = fvalue;
- u32 sign = value.i & FLOAT_SIGN;
- u32 exp = value.i & FLOAT_EXP;
- if (exp > FLOAT_ZERO && exp < FLOAT_EXP)
- {
- // Nice normalized number.
- return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
- }
- else
- {
- u32 mantissa = value.i & FLOAT_FRAC;
- if (mantissa)
- {
- if (exp)
- {
- return PPC_FPCLASS_QNAN; // Quiet NAN
- }
- else
- {
- // Denormalized number.
- return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
- }
- }
- else if (exp)
- {
- // Infinite
- return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
- }
- else
- {
- //Zero
- return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
- }
- }
-}
-
-
-} // namespace
-
-inline void MatrixMul(int n, const float *a, const float *b, float *result)
-{
- for (int i = 0; i < n; ++i)
- {
- for (int j = 0; j < n; ++j)
- {
- float temp = 0;
- for (int k = 0; k < n; ++k)
- {
- temp += a[i * n + k] * b[k * n + j];
- }
- result[i * n + j] = temp;
- }
- }
-}
-
-// Calculate sum of a float list
-float MathFloatVectorSum(const std::vector<float>& Vec)
-{
- return std::accumulate(Vec.begin(), Vec.end(), 0.0f);
-}
-
-void Matrix33::LoadIdentity(Matrix33 &mtx)
-{
- memset(mtx.data, 0, sizeof(mtx.data));
- mtx.data[0] = 1.0f;
- mtx.data[4] = 1.0f;
- mtx.data[8] = 1.0f;
-}
-
-void Matrix33::RotateX(Matrix33 &mtx, float rad)
-{
- float s = sin(rad);
- float c = cos(rad);
- memset(mtx.data, 0, sizeof(mtx.data));
- mtx.data[0] = 1;
- mtx.data[4] = c;
- mtx.data[5] = -s;
- mtx.data[7] = s;
- mtx.data[8] = c;
-}
-void Matrix33::RotateY(Matrix33 &mtx, float rad)
-{
- float s = sin(rad);
- float c = cos(rad);
- memset(mtx.data, 0, sizeof(mtx.data));
- mtx.data[0] = c;
- mtx.data[2] = s;
- mtx.data[4] = 1;
- mtx.data[6] = -s;
- mtx.data[8] = c;
-}
-
-void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result)
-{
- MatrixMul(3, a.data, b.data, result.data);
-}
-
-void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3])
-{
- for (int i = 0; i < 3; ++i) {
- result[i] = 0;
- for (int k = 0; k < 3; ++k) {
- result[i] += a.data[i * 3 + k] * vec[k];
- }
- }
-}
-
-void Matrix44::LoadIdentity(Matrix44 &mtx)
-{
- memset(mtx.data, 0, sizeof(mtx.data));
- mtx.data[0] = 1.0f;
- mtx.data[5] = 1.0f;
- mtx.data[10] = 1.0f;
- mtx.data[15] = 1.0f;
-}
-
-void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33)
-{
- for (int i = 0; i < 3; ++i)
- {
- for (int j = 0; j < 3; ++j)
- {
- mtx.data[i * 4 + j] = m33.data[i * 3 + j];
- }
- }
-
- for (int i = 0; i < 3; ++i)
- {
- mtx.data[i * 4 + 3] = 0;
- mtx.data[i + 12] = 0;
- }
- mtx.data[15] = 1.0f;
-}
-
-void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16])
-{
- for(int i = 0; i < 16; ++i) {
- mtx.data[i] = mtxArray[i];
- }
-}
-
-void Matrix44::Translate(Matrix44 &mtx, const float vec[3])
-{
- LoadIdentity(mtx);
- mtx.data[3] = vec[0];
- mtx.data[7] = vec[1];
- mtx.data[11] = vec[2];
-}
-
-void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result)
-{
- MatrixMul(4, a.data, b.data, result.data);
-}
-
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 43b0e0dc..0b1400b4 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -4,11 +4,9 @@
#pragma once
-#include "common/common.h"
-
#include <algorithm>
+#include <cstdlib>
#include <type_traits>
-#include <vector>
namespace MathUtil
{
@@ -19,83 +17,6 @@ inline T Clamp(const T val, const T& min, const T& max)
return std::max(min, std::min(max, val));
}
-static const u64 DOUBLE_SIGN = 0x8000000000000000ULL,
- DOUBLE_EXP = 0x7FF0000000000000ULL,
- DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL,
- DOUBLE_ZERO = 0x0000000000000000ULL;
-
-static const u32 FLOAT_SIGN = 0x80000000,
- FLOAT_EXP = 0x7F800000,
- FLOAT_FRAC = 0x007FFFFF,
- FLOAT_ZERO = 0x00000000;
-
-union IntDouble {
- double d;
- u64 i;
-};
-union IntFloat {
- float f;
- u32 i;
-};
-
-inline bool IsNAN(double d)
-{
- IntDouble x; x.d = d;
- return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
- ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) );
-}
-
-inline bool IsQNAN(double d)
-{
- IntDouble x; x.d = d;
- return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
- ((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) &&
- ((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) );
-}
-
-inline bool IsSNAN(double d)
-{
- IntDouble x; x.d = d;
- return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
- ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) &&
- ((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) );
-}
-
-inline float FlushToZero(float f)
-{
- IntFloat x; x.f = f;
- if ((x.i & FLOAT_EXP) == 0)
- x.i &= FLOAT_SIGN; // turn into signed zero
- return x.f;
-}
-
-inline double FlushToZeroAsFloat(double d)
-{
- IntDouble x; x.d = d;
- if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL)
- x.i &= DOUBLE_SIGN; // turn into signed zero
- return x.d;
-}
-
-enum PPCFpClass
-{
- PPC_FPCLASS_QNAN = 0x11,
- PPC_FPCLASS_NINF = 0x9,
- PPC_FPCLASS_NN = 0x8,
- PPC_FPCLASS_ND = 0x18,
- PPC_FPCLASS_NZ = 0x12,
- PPC_FPCLASS_PZ = 0x2,
- PPC_FPCLASS_PD = 0x14,
- PPC_FPCLASS_PN = 0x4,
- PPC_FPCLASS_PINF = 0x5,
-};
-
-// Uses PowerPC conventions for the return value, so it can be easily
-// used directly in CPU emulation.
-u32 ClassifyDouble(double dvalue);
-// More efficient float version.
-u32 ClassifyFloat(float fvalue);
-
template<class T>
struct Rectangle
{
@@ -104,101 +25,12 @@ struct Rectangle
T right;
T bottom;
- Rectangle()
- { }
+ Rectangle() {}
- Rectangle(T theLeft, T theTop, T theRight, T theBottom)
- : left(theLeft), top(theTop), right(theRight), bottom(theBottom)
- { }
-
- bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; }
+ Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {}
T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); }
T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); }
-
- // If the rectangle is in a coordinate system with a lower-left origin, use
- // this Clamp.
- void ClampLL(T x1, T y1, T x2, T y2)
- {
- if (left < x1) left = x1;
- if (right > x2) right = x2;
- if (top > y1) top = y1;
- if (bottom < y2) bottom = y2;
- }
-
- // If the rectangle is in a coordinate system with an upper-left origin,
- // use this Clamp.
- void ClampUL(T x1, T y1, T x2, T y2)
- {
- if (left < x1) left = x1;
- if (right > x2) right = x2;
- if (top < y1) top = y1;
- if (bottom > y2) bottom = y2;
- }
};
} // namespace MathUtil
-
-inline float pow2f(float x) {return x * x;}
-inline double pow2(double x) {return x * x;}
-
-float MathFloatVectorSum(const std::vector<float>&);
-
-#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
-
-// Rounds down. 0 -> undefined
-inline u64 Log2(u64 val)
-{
-#if defined(__GNUC__)
- return 63 - __builtin_clzll(val);
-
-#elif defined(_MSC_VER) && defined(_M_X64)
- unsigned long result = -1;
- _BitScanReverse64(&result, val);
- return result;
-
-#else
- u64 result = -1;
- while (val != 0)
- {
- val >>= 1;
- ++result;
- }
- return result;
-#endif
-}
-
-// Tiny matrix/vector library.
-// Used for things like Free-Look in the gfx backend.
-
-class Matrix33
-{
-public:
- static void LoadIdentity(Matrix33 &mtx);
-
- // set mtx to be a rotation matrix around the x axis
- static void RotateX(Matrix33 &mtx, float rad);
- // set mtx to be a rotation matrix around the y axis
- static void RotateY(Matrix33 &mtx, float rad);
-
- // set result = a x b
- static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result);
- static void Multiply(const Matrix33 &a, const float vec[3], float result[3]);
-
- float data[9];
-};
-
-class Matrix44
-{
-public:
- static void LoadIdentity(Matrix44 &mtx);
- static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33);
- static void Set(Matrix44 &mtx, const float mtxArray[16]);
-
- static void Translate(Matrix44 &mtx, const float vec[3]);
-
- static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result);
-
- float data[16];
-};
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
deleted file mode 100644
index 76c70701..00000000
--- a/src/common/mem_arena.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include <string>
-
-#include "common/memory_util.h"
-#include "common/mem_arena.h"
-#include "common/string_util.h"
-
-#ifndef _WIN32
-#include <fcntl.h>
-#ifdef ANDROID
-#include <sys/ioctl.h>
-#include <linux/ashmem.h>
-#endif
-#endif
-
-#ifdef ANDROID
-
-// Hopefully this ABI will never change...
-
-
-#define ASHMEM_DEVICE "/dev/ashmem"
-
-/*
-* ashmem_create_region - creates a new ashmem region and returns the file
-* descriptor, or <0 on error
-*
-* `name' is an optional label to give the region (visible in /proc/pid/maps)
-* `size' is the size of the region, in page-aligned bytes
-*/
-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];
-
- strncpy(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:
- LOG_ERROR(Common_Memory, "NASTY ASHMEM ERROR: ret = %08x", ret);
- close(fd);
- return ret;
-}
-
-int ashmem_set_prot_region(int fd, int prot)
-{
- return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
-}
-
-int ashmem_pin_region(int fd, size_t offset, size_t len)
-{
- struct ashmem_pin pin = { offset, len };
- return ioctl(fd, ASHMEM_PIN, &pin);
-}
-
-int ashmem_unpin_region(int fd, size_t offset, size_t len)
-{
- struct ashmem_pin pin = { offset, len };
- return ioctl(fd, ASHMEM_UNPIN, &pin);
-}
-#endif // Android
-
-
-#if defined(_WIN32)
-SYSTEM_INFO sysInfo;
-#endif
-
-
-// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
-#ifdef _WIN32
-size_t roundup(size_t x) {
- int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
- return (x + gran - 1) & ~(gran - 1);
-}
-#else
-size_t roundup(size_t x) {
- return x;
-}
-#endif
-
-
-void MemArena::GrabLowMemSpace(size_t size)
-{
-#ifdef _WIN32
- hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr);
- GetSystemInfo(&sysInfo);
-#elif defined(ANDROID)
- // Use ashmem so we don't have to allocate a file on disk!
- fd = ashmem_create_region("Citra_RAM", size);
- // Note that it appears that ashmem is pinned by default, so no need to pin.
- if (fd < 0)
- {
- LOG_ERROR(Common_Memory, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
- return;
- }
-#else
- // Try to find a non-existing filename for our shared memory.
- // In most cases the first one will be available, but it's nicer to search
- // a bit more.
- for (int i = 0; i < 10000; i++)
- {
- std::string file_name = Common::StringFromFormat("/citramem.%d", i);
- fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd != -1)
- {
- shm_unlink(file_name.c_str());
- break;
- }
- else if (errno != EEXIST)
- {
- LOG_ERROR(Common_Memory, "shm_open failed: %s", strerror(errno));
- return;
- }
- }
- if (ftruncate(fd, size) < 0)
- LOG_ERROR(Common_Memory, "Failed to allocate low memory space");
-#endif
-}
-
-
-void MemArena::ReleaseSpace()
-{
-#ifdef _WIN32
- CloseHandle(hMemoryMapping);
- hMemoryMapping = 0;
-#else
- close(fd);
-#endif
-}
-
-
-void *MemArena::CreateView(s64 offset, size_t size, void *base)
-{
-#ifdef _WIN32
- size = roundup(size);
- void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
- return ptr;
-#else
- void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
- // Do not sync memory to underlying file. Linux has this by default.
-#ifdef __FreeBSD__
- MAP_NOSYNC |
-#endif
- ((base == nullptr) ? 0 : MAP_FIXED), fd, offset);
-
- if (retval == MAP_FAILED)
- {
- LOG_ERROR(Common_Memory, "mmap failed");
- return nullptr;
- }
- return retval;
-#endif
-}
-
-
-void MemArena::ReleaseView(void* view, size_t size)
-{
-#ifdef _WIN32
- UnmapViewOfFile(view);
-#else
- munmap(view, size);
-#endif
-}
-
-u8* MemArena::Find4GBBase()
-{
-#ifdef _M_X64
-#ifdef _WIN32
- // 64 bit
- u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
- VirtualFree(base, 0, MEM_RELEASE);
- return base;
-#else
- // Very precarious - mmap cannot return an error when trying to map already used pages.
- // This makes the Windows approach above unusable on Linux, so we will simply pray...
- return reinterpret_cast<u8*>(0x2300000000ULL);
-#endif
-
-#else // 32 bit
-
-#ifdef _WIN32
- u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
- if (base) {
- VirtualFree(base, 0, MEM_RELEASE);
- }
- return base;
-#else
- void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_SHARED, -1, 0);
- if (base == MAP_FAILED) {
- LOG_ERROR(Common_Memory, "Failed to map 256 MB of memory space: %s", strerror(errno));
- return 0;
- }
- munmap(base, 0x10000000);
- return static_cast<u8*>(base);
-#endif
-#endif
-}
-
-
-// yeah, this could also be done in like two bitwise ops...
-#define SKIP(a_flags, b_flags)
-//if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
-// continue;
-//if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
-// continue;
-
-static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
- // OK, we know where to find free space. Now grab it!
- // We just mimic the popular BAT setup.
- size_t position = 0;
- size_t last_position = 0;
-
- // Zero all the pointers to be sure.
- for (int i = 0; i < num_views; i++)
- {
- if (views[i].out_ptr_low)
- *views[i].out_ptr_low = 0;
- if (views[i].out_ptr)
- *views[i].out_ptr = 0;
- }
-
- int i;
- for (i = 0; i < num_views; i++)
- {
- const MemoryView &view = views[i];
- if (view.size == 0)
- continue;
- SKIP(flags, view.flags);
- if (view.flags & MV_MIRROR_PREVIOUS) {
- position = last_position;
- }
- else {
- *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size);
- if (!*view.out_ptr_low)
- goto bail;
- }
-#ifdef _M_X64
- *view.out_ptr = (u8*)arena->CreateView(
- position, view.size, base + view.virtual_address);
-#else
- if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical.
- // No need to create multiple identical views.
- *view.out_ptr = *views[i - 1].out_ptr;
- }
- else {
- *view.out_ptr = (u8*)arena->CreateView(
- position, view.size, base + (view.virtual_address & 0x3FFFFFFF));
- if (!*view.out_ptr)
- goto bail;
- }
-#endif
-
- last_position = position;
- position += roundup(view.size);
- }
-
- return true;
-
-bail:
- // Argh! ERROR! Free what we grabbed so far so we can try again.
- for (int j = 0; j <= i; j++)
- {
- if (views[i].size == 0)
- continue;
- SKIP(flags, views[i].flags);
- if (views[j].out_ptr_low && *views[j].out_ptr_low)
- {
- arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
- *views[j].out_ptr_low = nullptr;
- }
- if (*views[j].out_ptr)
- {
-#ifdef _M_X64
- arena->ReleaseView(*views[j].out_ptr, views[j].size);
-#else
- if (!(views[j].flags & MV_MIRROR_PREVIOUS))
- {
- arena->ReleaseView(*views[j].out_ptr, views[j].size);
- }
-#endif
- *views[j].out_ptr = nullptr;
- }
- }
- return false;
-}
-
-u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
-{
- size_t total_mem = 0;
- int base_attempts = 0;
-
- for (int i = 0; i < num_views; i++)
- {
- if (views[i].size == 0)
- continue;
- SKIP(flags, views[i].flags);
- if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0)
- total_mem += roundup(views[i].size);
- }
- // Grab some pagefile backed memory out of the void ...
- arena->GrabLowMemSpace(total_mem);
-
- // Now, create views in high memory where there's plenty of space.
-#ifdef _M_X64
- u8 *base = MemArena::Find4GBBase();
- // This really shouldn't fail - in 64-bit, there will always be enough
- // address space.
- if (!Memory_TryBase(base, views, num_views, flags, arena))
- {
- LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
- return 0;
- }
-#elif defined(_WIN32)
- // Try a whole range of possible bases. Return once we got a valid one.
- u32 max_base_addr = 0x7FFF0000 - 0x10000000;
- u8 *base = nullptr;
-
- for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
- {
- base_attempts++;
- base = (u8 *)base_addr;
- if (Memory_TryBase(base, views, num_views, flags, arena))
- {
- LOG_DEBUG(Common_Memory, "Found valid memory base at %p after %i tries.", base, base_attempts);
- base_attempts = 0;
- break;
- }
- }
-#else
- // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
- u8 *base = MemArena::Find4GBBase();
- if (!Memory_TryBase(base, views, num_views, flags, arena))
- {
- LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
- return 0;
- }
-#endif
- if (base_attempts)
- LOG_ERROR(Common_Memory, "No possible memory base pointer found!");
- return base;
-}
-
-void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
-{
- for (int i = 0; i < num_views; i++)
- {
- if (views[i].size == 0)
- continue;
- SKIP(flags, views[i].flags);
- if (views[i].out_ptr_low && *views[i].out_ptr_low)
- arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
- if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
- arena->ReleaseView(*views[i].out_ptr, views[i].size);
- *views[i].out_ptr = nullptr;
- if (views[i].out_ptr_low)
- *views[i].out_ptr_low = nullptr;
- }
-}
diff --git a/src/common/mem_arena.h b/src/common/mem_arena.h
deleted file mode 100644
index 3379d252..00000000
--- a/src/common/mem_arena.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#pragma once
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#include "common/common.h"
-
-// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
-// Multiple views can mirror the same section of the block, which makes it very convient for emulating
-// memory mirrors.
-
-class MemArena
-{
-public:
- void GrabLowMemSpace(size_t size);
- void ReleaseSpace();
- void *CreateView(s64 offset, size_t size, void *base = 0);
- void ReleaseView(void *view, size_t size);
-
- // This only finds 1 GB in 32-bit
- static u8 *Find4GBBase();
-private:
-
-#ifdef _WIN32
- HANDLE hMemoryMapping;
-#else
- int fd;
-#endif
-};
-
-enum {
- MV_MIRROR_PREVIOUS = 1,
- // MV_FAKE_VMEM = 2,
- // MV_WII_ONLY = 4,
- MV_IS_PRIMARY_RAM = 0x100,
- MV_IS_EXTRA1_RAM = 0x200,
- MV_IS_EXTRA2_RAM = 0x400,
-};
-
-struct MemoryView
-{
- u8 **out_ptr_low;
- u8 **out_ptr;
- u32 virtual_address;
- u32 size;
- u32 flags;
-};
-
-// Uses a memory arena to set up an emulator-friendly memory map according to
-// a passed-in list of MemoryView structures.
-u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena);
-void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena);
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 7e69d31c..20b791a1 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -3,7 +3,8 @@
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
#include "common/memory_util.h"
#include "common/string_util.h"
@@ -70,7 +71,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
}
#endif
-#if defined(_M_X64)
+#if EMU_ARCH_BITS == 64
if ((u64)ptr >= 0x80000000 && low == true)
LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
#endif
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index e33055d1..53cacf37 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -2,10 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/common_funcs.h"
#ifdef _WIN32
#include <windows.h>
+#else
+#include <string.h>
#endif
// Neither Android nor OS X support TLS
diff --git a/src/common/platform.h b/src/common/platform.h
index e27d6e31..df780ac6 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -57,54 +57,33 @@
#endif
-#if defined(__x86_64__) || defined(_M_X64) || defined(__alpha__) || defined(__ia64__)
-#define EMU_ARCHITECTURE_X64
-#else
-#define EMU_ARCHITECTURE_X86
+#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
+ #define EMU_ARCH_BITS 64
+#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
+ #define EMU_ARCH_BITS 32
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Compiler-Specific Definitions
-
-#if EMU_PLATFORM == PLATFORM_WINDOWS
-
-#include <time.h>
-
-#ifndef NOMINMAX
-#define NOMINMAX
+// Feature detection
+
+#if defined _M_GENERIC
+# define _M_SSE 0x0
+#elif defined __GNUC__
+# if defined __SSE4_2__
+# define _M_SSE 0x402
+# elif defined __SSE4_1__
+# define _M_SSE 0x401
+# elif defined __SSSE3__
+# define _M_SSE 0x301
+# elif defined __SSE3__
+# define _M_SSE 0x300
+# endif
+#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
+# define _M_SSE 0x402
#endif
-#define EMU_FASTCALL __fastcall
-
-#ifdef _MSC_VER
-inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
- if (localtime_s(result, clock) == 0)
- return result;
- return nullptr;
-}
-#endif
-
-#else // EMU_PLATFORM != PLATFORM_WINDOWS
-
-#define EMU_FASTCALL __attribute__((fastcall))
-#define __stdcall
-#define __cdecl
-#define BOOL bool
-#define DWORD u32
-
-// TODO: Hacks..
-#include <limits.h>
-
-#include <strings.h>
-#define stricmp(str1, str2) strcasecmp(str1, str2)
-#define _stricmp(str1, str2) strcasecmp(str1, str2)
-#define _snprintf snprintf
-#define _getcwd getcwd
-#define _tzset tzset
-
-typedef void EXCEPTION_POINTERS;
-
-#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Compiler-Specific Definitions
#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \
(__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index 65c3df16..cf6b6b25 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -7,7 +7,6 @@
#include "common/assert.h"
#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
-#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h> // For QueryPerformanceCounter/Frequency
#endif
@@ -127,10 +126,9 @@ void TimingResultsAggregator::AddFrame(const ProfilingFrameResult& frame_result)
static AggregatedDuration AggregateField(const std::vector<Duration>& v, size_t len) {
AggregatedDuration result;
result.avg = Duration::zero();
-
result.min = result.max = (len == 0 ? Duration::zero() : v[0]);
- for (size_t i = 1; i < len; ++i) {
+ for (size_t i = 0; i < len; ++i) {
Duration value = v[i];
result.avg += value;
result.min = std::min(result.min, value);
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 3264dd51..7dc0ba7b 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -4,7 +4,9 @@
#include <boost/range/algorithm.hpp>
-#include "common/common.h"
+#include "common/common_funcs.h"
+#include "common/common_paths.h"
+#include "common/logging/log.h"
#include "common/string_util.h"
#ifdef _MSC_VER
@@ -285,131 +287,6 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
return result;
}
-// UriDecode and UriEncode are from http://www.codeguru.com/cpp/cpp/string/conversions/print.php/c12759
-// by jinq0123 (November 2, 2006)
-
-// Uri encode and decode.
-// RFC1630, RFC1738, RFC2396
-
-//#include <string>
-//#include <assert.h>
-
-const char HEX2DEC[256] =
-{
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16,
-
- /* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
- /* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
- /* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
-
- /* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
-
- /* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
- /* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16
-};
-
-std::string UriDecode(const std::string & sSrc)
-{
- // Note from RFC1630: "Sequences which start with a percent sign
- // but are not followed by two hexadecimal characters (0-9, A-F) are reserved
- // for future extension"
-
- const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
- const size_t SRC_LEN = sSrc.length();
- const unsigned char * const SRC_END = pSrc + SRC_LEN;
- const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
-
- char * const pStart = new char[SRC_LEN];
- char * pEnd = pStart;
-
- while (pSrc < SRC_LAST_DEC)
- {
- if (*pSrc == '%')
- {
- char dec1, dec2;
- if (16 != (dec1 = HEX2DEC[*(pSrc + 1)])
- && 16 != (dec2 = HEX2DEC[*(pSrc + 2)]))
- {
- *pEnd++ = (dec1 << 4) + dec2;
- pSrc += 3;
- continue;
- }
- }
-
- *pEnd++ = *pSrc++;
- }
-
- // the last 2- chars
- while (pSrc < SRC_END)
- *pEnd++ = *pSrc++;
-
- std::string sResult(pStart, pEnd);
- delete [] pStart;
- return sResult;
-}
-
-// Only alphanum is safe.
-const char SAFE[256] =
-{
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
-
- /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
- /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
- /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
- /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
-
- /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
-
- /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
-};
-
-std::string UriEncode(const std::string & sSrc)
-{
- const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
- const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
- const size_t SRC_LEN = sSrc.length();
- unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
- unsigned char * pEnd = pStart;
- const unsigned char * const SRC_END = pSrc + SRC_LEN;
-
- for (; pSrc < SRC_END; ++pSrc)
- {
- if (SAFE[*pSrc])
- *pEnd++ = *pSrc;
- else
- {
- // escape this char
- *pEnd++ = '%';
- *pEnd++ = DEC2HEX[*pSrc >> 4];
- *pEnd++ = DEC2HEX[*pSrc & 0x0F];
- }
- }
-
- std::string sResult((char *)pStart, (char *)pEnd);
- delete [] pStart;
- return sResult;
-}
-
#ifdef _MSC_VER
std::string UTF16ToUTF8(const std::u16string& input)
@@ -600,4 +477,12 @@ std::string SHIFTJISToUTF8(const std::string& input)
#endif
+std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) {
+ size_t len = 0;
+ while (len < max_len && buffer[len] != '\0')
+ ++len;
+
+ return std::string(buffer, len);
+}
+
}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 74974263..fdc41049 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -10,7 +10,7 @@
#include <sstream>
#include <vector>
-#include "common/common.h"
+#include "common/common_types.h"
namespace Common {
@@ -86,8 +86,6 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename);
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
-std::string UriDecode(const std::string & sSrc);
-std::string UriEncode(const std::string & sSrc);
std::string UTF16ToUTF8(const std::u16string& input);
std::u16string UTF8ToUTF16(const std::string& input);
@@ -130,4 +128,10 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
return (begin == end) == (*other == '\0');
}
+/**
+ * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
+ * NUL-terminated then the string ends at max_len characters.
+ */
+std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
+
}
diff --git a/src/common/symbols.h b/src/common/symbols.h
index f76cb6b1..6b62b011 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -5,8 +5,10 @@
#pragma once
#include <map>
+#include <string>
+#include <utility>
-#include "common/common.h"
+#include "common/common_types.h"
struct TSymbol
{
diff --git a/src/common/thread.h b/src/common/thread.h
index a45728e1..7bc41949 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,7 +4,6 @@
#pragma once
-// Don't include common.h here as it will break LogManager
#include "common/common_types.h"
#include <cstdio>
#include <cstring>
@@ -51,109 +50,60 @@ int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
-class Event
-{
+class Event {
public:
- Event()
- : is_set(false)
- {}
+ Event() : is_set(false) {}
- void Set()
- {
+ void Set() {
std::lock_guard<std::mutex> lk(m_mutex);
- if (!is_set)
- {
+ if (!is_set) {
is_set = true;
m_condvar.notify_one();
}
}
- void Wait()
- {
+ void Wait() {
std::unique_lock<std::mutex> lk(m_mutex);
- m_condvar.wait(lk, IsSet(this));
+ m_condvar.wait(lk, [&]{ return is_set; });
is_set = false;
}
- void Reset()
- {
+ void Reset() {
std::unique_lock<std::mutex> lk(m_mutex);
// no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
is_set = false;
}
private:
- class IsSet
- {
- public:
- IsSet(const Event* ev)
- : m_event(ev)
- {}
-
- bool operator()()
- {
- return m_event->is_set;
- }
-
- private:
- const Event* const m_event;
- };
-
- volatile bool is_set;
+ bool is_set;
std::condition_variable m_condvar;
std::mutex m_mutex;
};
-// TODO: doesn't work on windows with (count > 2)
-class Barrier
-{
+class Barrier {
public:
- Barrier(size_t count)
- : m_count(count), m_waiting(0)
- {}
+ Barrier(size_t count) : m_count(count), m_waiting(0) {}
- // block until "count" threads call Sync()
- bool Sync()
- {
+ /// Blocks until all "count" threads have called Sync()
+ void Sync() {
std::unique_lock<std::mutex> lk(m_mutex);
// TODO: broken when next round of Sync()s
// is entered before all waiting threads return from the notify_all
- if (m_count == ++m_waiting)
- {
+ if (++m_waiting == m_count) {
m_waiting = 0;
m_condvar.notify_all();
- return true;
- }
- else
- {
- m_condvar.wait(lk, IsDoneWating(this));
- return false;
+ } else {
+ m_condvar.wait(lk, [&]{ return m_waiting == 0; });
}
}
private:
- class IsDoneWating
- {
- public:
- IsDoneWating(const Barrier* bar)
- : m_bar(bar)
- {}
-
- bool operator()()
- {
- return (0 == m_bar->m_waiting);
- }
-
- private:
- const Barrier* const m_bar;
- };
-
std::condition_variable m_condvar;
std::mutex m_mutex;
const size_t m_count;
- volatile size_t m_waiting;
+ size_t m_waiting;
};
void SleepCurrentThread(int ms);
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 444abf11..12455d7c 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -9,8 +9,6 @@
#include <boost/range/algorithm_ext/erase.hpp>
-#include "common/common.h"
-
namespace Common {
template<class T, unsigned int N>
@@ -40,6 +38,18 @@ struct ThreadQueueList {
return -1;
}
+ T get_first() {
+ Queue *cur = first;
+ while (cur != nullptr) {
+ if (!cur->data.empty()) {
+ return cur->data.front();
+ }
+ cur = cur->next_nonempty;
+ }
+
+ return T();
+ }
+
T pop_first() {
Queue *cur = first;
while (cur != nullptr) {
@@ -79,6 +89,12 @@ struct ThreadQueueList {
cur->data.push_back(thread_id);
}
+ void move(const T& thread_id, Priority old_priority, Priority new_priority) {
+ remove(old_priority, thread_id);
+ prepare(new_priority);
+ push_back(new_priority, thread_id);
+ }
+
void remove(Priority priority, const T& thread_id) {
Queue *cur = &queues[priority];
boost::remove_erase(cur->data, thread_id);
diff --git a/src/common/thunk.h b/src/common/thunk.h
index 4fb7c98e..53348005 100644
--- a/src/common/thunk.h
+++ b/src/common/thunk.h
@@ -6,7 +6,7 @@
#include <map>
-#include "common/common.h"
+#include "common/common_types.h"
// This simple class creates a wrapper around a C/C++ function that saves all fp state
// before entering it, and restores it upon exit. This is required to be able to selectively
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index a6682ea1..b99835ac 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -12,9 +12,9 @@
#include <sys/time.h>
#endif
-#include "common/common.h"
-#include "common/timer.h"
+#include "common/common_types.h"
#include "common/string_util.h"
+#include "common/timer.h"
namespace Common
{
diff --git a/src/common/timer.h b/src/common/timer.h
index 4b44c33a..b5f0f258 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -4,7 +4,7 @@
#pragma once
-#include "common/common.h"
+#include "common/common_types.h"
#include <string>
namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 33e5be3a..e8d8c96d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -6,13 +6,15 @@ set(SRCS
arm/dyncom/arm_dyncom_interpreter.cpp
arm/dyncom/arm_dyncom_run.cpp
arm/dyncom/arm_dyncom_thumb.cpp
- arm/interpreter/armcopro.cpp
arm/interpreter/arminit.cpp
arm/interpreter/armsupp.cpp
arm/skyeye_common/vfp/vfp.cpp
arm/skyeye_common/vfp/vfpdouble.cpp
arm/skyeye_common/vfp/vfpinstr.cpp
arm/skyeye_common/vfp/vfpsingle.cpp
+ core.cpp
+ core_timing.cpp
+ file_sys/archive_backend.cpp
file_sys/archive_extsavedata.cpp
file_sys/archive_romfs.cpp
file_sys/archive_savedata.cpp
@@ -21,15 +23,18 @@ set(SRCS
file_sys/archive_systemsavedata.cpp
file_sys/disk_archive.cpp
file_sys/ivfc_archive.cpp
+ hle/config_mem.cpp
+ hle/hle.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
hle/kernel/mutex.cpp
+ hle/kernel/process.cpp
hle/kernel/semaphore.cpp
hle/kernel/session.cpp
hle/kernel/shared_memory.cpp
- hle/kernel/timer.cpp
hle/kernel/thread.cpp
+ hle/kernel/timer.cpp
hle/service/ac_u.cpp
hle/service/act_u.cpp
hle/service/am_app.cpp
@@ -56,51 +61,51 @@ set(SRCS
hle/service/fs/archive.cpp
hle/service/fs/fs_user.cpp
hle/service/gsp_gpu.cpp
+ hle/service/gsp_lcd.cpp
hle/service/hid/hid.cpp
- hle/service/hid/hid_user.cpp
hle/service/hid/hid_spvr.cpp
- hle/service/gsp_lcd.cpp
+ hle/service/hid/hid_user.cpp
hle/service/http_c.cpp
- hle/service/ir_rst.cpp
- hle/service/ir_u.cpp
+ hle/service/ir/ir.cpp
+ hle/service/ir/ir_rst.cpp
+ hle/service/ir/ir_u.cpp
+ hle/service/ir/ir_user.cpp
hle/service/ldr_ro.cpp
hle/service/mic_u.cpp
hle/service/ndm_u.cpp
hle/service/news_s.cpp
hle/service/news_u.cpp
hle/service/nim_aoc.cpp
+ hle/service/nim_u.cpp
hle/service/ns_s.cpp
hle/service/nwm_uds.cpp
hle/service/pm_app.cpp
hle/service/ptm/ptm.cpp
hle/service/ptm/ptm_play.cpp
- hle/service/ptm/ptm_u.cpp
hle/service/ptm/ptm_sysm.cpp
+ hle/service/ptm/ptm_u.cpp
hle/service/service.cpp
hle/service/soc_u.cpp
hle/service/srv.cpp
hle/service/ssl_c.cpp
hle/service/y2r_u.cpp
- hle/config_mem.cpp
- hle/hle.cpp
hle/shared_page.cpp
hle/svc.cpp
hw/gpu.cpp
hw/hw.cpp
hw/lcd.cpp
+ loader/3dsx.cpp
loader/elf.cpp
loader/loader.cpp
loader/ncch.cpp
- loader/3dsx.cpp
- core.cpp
- core_timing.cpp
mem_map.cpp
- mem_map_funcs.cpp
+ memory.cpp
settings.cpp
system.cpp
)
set(HEADERS
+ arm/arm_interface.h
arm/disassembler/arm_disasm.h
arm/disassembler/load_symbol_map.h
arm/dyncom/arm_dyncom.h
@@ -112,12 +117,11 @@ set(HEADERS
arm/skyeye_common/armdefs.h
arm/skyeye_common/armemu.h
arm/skyeye_common/armmmu.h
- arm/skyeye_common/armos.h
- arm/skyeye_common/skyeye_defs.h
arm/skyeye_common/vfp/asm_vfp.h
arm/skyeye_common/vfp/vfp.h
arm/skyeye_common/vfp/vfp_helper.h
- arm/arm_interface.h
+ core.h
+ core_timing.h
file_sys/archive_backend.h
file_sys/archive_extsavedata.h
file_sys/archive_romfs.h
@@ -125,19 +129,24 @@ set(HEADERS
file_sys/archive_savedatacheck.h
file_sys/archive_sdmc.h
file_sys/archive_systemsavedata.h
+ file_sys/directory_backend.h
file_sys/disk_archive.h
file_sys/file_backend.h
file_sys/ivfc_archive.h
- file_sys/directory_backend.h
+ hle/config_mem.h
+ hle/function_wrappers.h
+ hle/hle.h
hle/kernel/address_arbiter.h
hle/kernel/event.h
hle/kernel/kernel.h
hle/kernel/mutex.h
+ hle/kernel/process.h
hle/kernel/semaphore.h
hle/kernel/session.h
hle/kernel/shared_memory.h
- hle/kernel/timer.h
hle/kernel/thread.h
+ hle/kernel/timer.h
+ hle/result.h
hle/service/ac_u.h
hle/service/act_u.h
hle/service/am_app.h
@@ -164,47 +173,46 @@ set(HEADERS
hle/service/fs/archive.h
hle/service/fs/fs_user.h
hle/service/gsp_gpu.h
+ hle/service/gsp_lcd.h
hle/service/hid/hid.h
hle/service/hid/hid_spvr.h
hle/service/hid/hid_user.h
- hle/service/gsp_lcd.h
hle/service/http_c.h
- hle/service/ir_rst.h
- hle/service/ir_u.h
+ hle/service/ir/ir.h
+ hle/service/ir/ir_rst.h
+ hle/service/ir/ir_u.h
+ hle/service/ir/ir_user.h
hle/service/ldr_ro.h
hle/service/mic_u.h
hle/service/ndm_u.h
hle/service/news_s.h
hle/service/news_u.h
hle/service/nim_aoc.h
+ hle/service/nim_u.h
hle/service/ns_s.h
hle/service/nwm_uds.h
hle/service/pm_app.h
hle/service/ptm/ptm.h
hle/service/ptm/ptm_play.h
- hle/service/ptm/ptm_u.h
hle/service/ptm/ptm_sysm.h
+ hle/service/ptm/ptm_u.h
hle/service/service.h
hle/service/soc_u.h
hle/service/srv.h
hle/service/ssl_c.h
hle/service/y2r_u.h
- hle/config_mem.h
- hle/result.h
- hle/function_wrappers.h
- hle/hle.h
hle/shared_page.h
hle/svc.h
hw/gpu.h
hw/hw.h
hw/lcd.h
+ loader/3dsx.h
loader/elf.h
loader/loader.h
loader/ncch.h
- loader/3dsx.h
- core.h
- core_timing.h
mem_map.h
+ memory.h
+ memory_setup.h
settings.h
system.h
)
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index fe1e584a..85ed2c69 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -4,8 +4,8 @@
#pragma once
-#include "common/common.h"
#include "common/common_types.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
namespace Core {
struct ThreadContext;
@@ -74,6 +74,20 @@ public:
virtual void SetCPSR(u32 cpsr) = 0;
/**
+ * Gets the value stored in a CP15 register.
+ * @param reg The CP15 register to retrieve the value from.
+ * @return the value stored in the given CP15 register.
+ */
+ virtual u32 GetCP15Register(CP15Register reg) = 0;
+
+ /**
+ * Stores the given value into the indicated CP15 register.
+ * @param reg The CP15 register to store the value into.
+ * @param value The value to store into the CP15 register.
+ */
+ virtual void SetCP15Register(CP15Register reg, u32 value) = 0;
+
+ /**
* Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
* @param ticks Number of ticks to advance the CPU core
*/
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index cb1a410a..0072ae53 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -2,6 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
+#include "common/make_unique.h"
+
#include "core/arm/skyeye_common/armemu.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
@@ -12,18 +16,13 @@
#include "core/core.h"
#include "core/core_timing.h"
-const static cpu_config_t s_arm11_cpu_info = {
- "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
-};
-
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
- state = std::unique_ptr<ARMul_State>(new ARMul_State);
+ state = Common::make_unique<ARMul_State>();
ARMul_NewState(state.get());
ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
state->abort_model = ABORT_BASE_RESTORED;
- state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
state->bigendSig = LOW;
state->lateabtSig = LOW;
@@ -31,7 +30,6 @@ ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
// Reset the core to initial state
ARMul_Reset(state.get());
- state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
state->Emulate = RUN;
// Switch to the desired privilege mode.
@@ -68,6 +66,14 @@ void ARM_DynCom::SetCPSR(u32 cpsr) {
state->Cpsr = cpsr;
}
+u32 ARM_DynCom::GetCP15Register(CP15Register reg) {
+ return state->CP15[reg];
+}
+
+void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) {
+ state->CP15[reg] = value;
+}
+
void ARM_DynCom::AddTicks(u64 ticks) {
down_count -= ticks;
if (down_count < 0)
@@ -91,7 +97,6 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e
context.pc = entry_point;
context.sp = stack_top;
context.cpsr = 0x1F; // Usermode
- context.mode = 8; // Instructs dyncom CPU core to start execution as if it's "resuming" a thread.
}
void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
@@ -105,8 +110,6 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
ctx.fpscr = state->VFP[1];
ctx.fpexc = state->VFP[2];
-
- ctx.mode = state->NextInstr;
}
void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
@@ -120,8 +123,6 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
state->VFP[1] = ctx.fpscr;
state->VFP[2] = ctx.fpexc;
-
- state->NextInstr = ctx.mode;
}
void ARM_DynCom::PrepareReschedule() {
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index a7f95d30..2488c879 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -22,10 +22,12 @@ public:
void SetReg(int index, u32 value) override;
u32 GetCPSR() const override;
void SetCPSR(u32 cpsr) override;
+ u32 GetCP15Register(CP15Register reg) override;
+ void SetCP15Register(CP15Register reg, u32 value) override;
void AddTicks(u64 ticks) override;
- void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg);
+ void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override;
void SaveContext(Core::ThreadContext& ctx) override;
void LoadContext(const Core::ThreadContext& ctx) override;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 2765cb36..b79fd171 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -6,13 +6,12 @@
#include <algorithm>
#include <cstdio>
-#include <unordered_map>
#include "common/logging/log.h"
#include "common/profiler.h"
-#include "core/mem_map.h"
-#include "core/hle/hle.h"
+#include "core/memory.h"
+#include "core/hle/svc.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
@@ -339,7 +338,7 @@ static void LnSWoUB(ScaledRegisterPreIndexed)(ARMul_State* cpu, unsigned int ins
unsigned int shift_imm = BITS(inst, 7, 11);
unsigned int Rn = BITS(inst, 16, 19);
unsigned int Rm = BITS(inst, 0, 3);
- unsigned int index;
+ unsigned int index = 0;
unsigned int addr;
unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
@@ -390,7 +389,7 @@ static void LnSWoUB(ScaledRegisterPostIndexed)(ARMul_State* cpu, unsigned int in
unsigned int shift_imm = BITS(inst, 7, 11);
unsigned int Rn = BITS(inst, 16, 19);
unsigned int Rm = BITS(inst, 0, 3);
- unsigned int index;
+ unsigned int index = 0;
unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);
unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
@@ -605,7 +604,7 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u
unsigned int shift_imm = BITS(inst, 7, 11);
unsigned int Rn = BITS(inst, 16, 19);
unsigned int Rm = BITS(inst, 0, 3);
- unsigned int index;
+ unsigned int index = 0;
unsigned int addr;
unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
@@ -993,6 +992,14 @@ typedef struct _mcr_inst {
unsigned int inst;
} mcr_inst;
+typedef struct mcrr_inst {
+ unsigned int opcode_1;
+ unsigned int cp_num;
+ unsigned int crm;
+ unsigned int rt;
+ unsigned int rt2;
+} mcrr_inst;
+
typedef struct _mrs_inst {
unsigned int R;
unsigned int Rd;
@@ -1126,7 +1133,7 @@ int CondPassed(ARMul_State* cpu, unsigned int cond) {
#define CFLAG cpu->CFlag
#define VFLAG cpu->VFlag
- int temp;
+ int temp = 0;
switch (cond) {
case 0x0:
@@ -1262,11 +1269,6 @@ static get_addr_fp_t get_calc_addr_op(unsigned int inst) {
#define CHECK_RM (inst_cream->Rm == 15)
#define CHECK_RS (inst_cream->Rs == 15)
-#define UNIMPLEMENTED_INSTRUCTION(mnemonic) \
- LOG_ERROR(Core_ARM11, "unimplemented instruction: %s", mnemonic); \
- CITRA_IGNORE_EXIT(-1); \
- return nullptr;
-
static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
@@ -1391,7 +1393,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index)
inst_base->br = NON_BRANCH;
inst_base->load_r15 = 0;
- inst_cream->imm = BITS(inst, 8, 19) | BITS(inst, 0, 3);
+ inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3);
return inst_base;
}
@@ -1872,7 +1874,26 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
inst_cream->inst = inst;
return inst_base;
}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("MCRR"); }
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst));
+ mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 4, 7);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->rt = BITS(inst, 12, 15);
+ inst_cream->rt2 = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
@@ -1931,7 +1952,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
inst_cream->inst = inst;
return inst_base;
}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("MRRC"); }
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(mcrr)(inst, index);
+}
+
static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
@@ -3533,31 +3559,12 @@ const transop_fp_t arm_instruction_trans[] = {
INTERPRETER_TRANSLATE(blx_1_thumb)
};
-typedef std::unordered_map<u32, int> bb_map;
-static bb_map CreamCache;
-
-static void insert_bb(unsigned int addr, int start) {
- CreamCache[addr] = start;
-}
-
-static int find_bb(unsigned int addr, int& start) {
- int ret = -1;
- bb_map::const_iterator it = CreamCache.find(addr);
- if (it != CreamCache.end()) {
- start = static_cast<int>(it->second);
- ret = 0;
- } else {
- ret = -1;
- }
- return ret;
-}
-
enum {
FETCH_SUCCESS,
FETCH_FAILURE
};
-static tdstate decode_thumb_instr(ARMul_State* cpu, uint32_t inst, addr_t addr, uint32_t* arm_inst, uint32_t* inst_size, ARM_INST_PTR* ptr_inst_base){
+static tdstate decode_thumb_instr(ARMul_State* cpu, u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) {
// Check if in Thumb mode
tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size);
if(ret == t_branch){
@@ -3620,7 +3627,7 @@ typedef struct instruction_set_encoding_item ISEITEM;
extern const ISEITEM arm_instruction[];
-static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, addr_t addr) {
+static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
Common::Profiling::ScopeTimer timer_decode(profile_decode);
// Decode instruction, get index
@@ -3638,8 +3645,8 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, addr_t addr) {
if (cpu->TFlag)
thumb = THUMB;
- addr_t phys_addr = addr;
- addr_t pc_start = cpu->Reg[15];
+ u32 phys_addr = addr;
+ u32 pc_start = cpu->Reg[15];
while(ret == NON_BRANCH) {
inst = Memory::Read32(phys_addr & 0xFFFFFFFC);
@@ -3674,7 +3681,9 @@ translated:
}
ret = inst_base->br;
};
- insert_bb(pc_start, bb_start);
+
+ cpu->instruction_cache[pc_start] = bb_start;
+
return KEEP_GOING;
}
@@ -3690,20 +3699,16 @@ static int clz(unsigned int x) {
return n;
}
-static bool InAPrivilegedMode(ARMul_State* core) {
- return (core->Mode != USER32MODE);
-}
-
-unsigned InterpreterMainLoop(ARMul_State* state) {
+unsigned InterpreterMainLoop(ARMul_State* cpu) {
Common::Profiling::ScopeTimer timer_execute(profile_execute);
#undef RM
#undef RS
#define CRn inst_cream->crn
+ #define OPCODE_1 inst_cream->opcode_1
#define OPCODE_2 inst_cream->opcode_2
#define CRm inst_cream->crm
- #define CP15_REG(n) cpu->CP15[CP15(n)]
#define RD cpu->Reg[inst_cream->Rd]
#define RD2 cpu->Reg[inst_cream->Rd + 1]
#define RN cpu->Reg[inst_cream->Rn]
@@ -3952,8 +3957,6 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
#define PC (cpu->Reg[15])
#define CHECK_EXT_INT if (!cpu->NirqSig && !(cpu->Cpsr & 0x80)) goto END;
- ARMul_State* cpu = state;
-
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
// to a clunky switch statement.
#if defined __GNUC__ || defined __clang__
@@ -4005,9 +4008,14 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
phys_addr = cpu->Reg[15];
- if (find_bb(cpu->Reg[15], ptr) == -1)
+ // Find the cached instruction cream, otherwise translate it...
+ auto itr = cpu->instruction_cache.find(cpu->Reg[15]);
+ if (itr != cpu->instruction_cache.end()) {
+ ptr = itr->second;
+ } else {
if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
goto END;
+ }
inst_base = (arm_inst *)&inst_buf[ptr];
GOTO_NEXT_INST;
@@ -4764,94 +4772,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
if (inst_cream->Rd == 15) {
DEBUG_MSG;
} else {
- if (inst_cream->cp_num == 15) {
- if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
- CP15_REG(CP15_CONTROL) = RD;
- } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
- CP15_REG(CP15_AUXILIARY_CONTROL) = RD;
- } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
- CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD;
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
- CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD;
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
- CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD;
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
- CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD;
- } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
- CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD;
- } else if(CRn == MMU_CACHE_OPS){
- //LOG_WARNING(Core_ARM11, "cache operations have not implemented.");
- } else if(CRn == MMU_TLB_OPS){
- switch (CRm) {
- case 5: // ITLB
- switch(OPCODE_2) {
- case 0: // Invalidate all
- LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate all");
- break;
- case 1: // Invalidate by MVA
- LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by mva");
- break;
- case 2: // Invalidate by asid
- LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by asid");
- break;
- default:
- break;
- }
-
- break;
- case 6: // DTLB
- switch(OPCODE_2){
- case 0: // Invalidate all
- LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate all");
- break;
- case 1: // Invalidate by MVA
- LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by mva");
- break;
- case 2: // Invalidate by asid
- LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by asid");
- break;
- default:
- break;
- }
- break;
- case 7: // UNIFILED TLB
- switch(OPCODE_2){
- case 0: // invalidate all
- LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate all");
- break;
- case 1: // Invalidate by MVA
- LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by mva");
- break;
- case 2: // Invalidate by asid
- LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by asid");
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- } else if(CRn == MMU_PID) {
- if(OPCODE_2 == 0) {
- CP15_REG(CP15_PID) = RD;
- } else if(OPCODE_2 == 1) {
- CP15_REG(CP15_CONTEXT_ID) = RD;
- } else if (OPCODE_2 == 2) {
- CP15_REG(CP15_THREAD_UPRW) = RD;
- } else if(OPCODE_2 == 3) {
- if (InAPrivilegedMode(cpu))
- CP15_REG(CP15_THREAD_URO) = RD;
- } else if (OPCODE_2 == 4) {
- if (InAPrivilegedMode(cpu))
- CP15_REG(CP15_THREAD_PRW) = RD;
- } else {
- LOG_ERROR(Core_ARM11, "mmu_mcr wrote UNKNOWN - reg %d", CRn);
- }
- } else {
- LOG_ERROR(Core_ARM11, "mcr CRn=%d, CRm=%d OP2=%d is not implemented", CRn, CRm, OPCODE_2);
- }
- }
+ if (inst_cream->cp_num == 15)
+ WriteCP15Register(cpu, RD, CRn, OPCODE_1, CRm, OPCODE_2);
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4859,7 +4781,24 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
FETCH_INST;
GOTO_NEXT_INST;
}
+
MCRR_INST:
+ {
+ // Stubbed, as the MPCore doesn't have any registers that are accessible
+ // through this instruction.
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;
+
+ LOG_ERROR(Core_ARM11, "MCRR executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u",
+ inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
+ }
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mcrr_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
MLA_INST:
{
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
@@ -4926,50 +4865,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
CITRA_IGNORE_EXIT(-1);
goto END;
} else {
- if (inst_cream->cp_num == 15) {
- if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
- RD = cpu->CP15[CP15(CP15_MAIN_ID)];
- } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) {
- RD = cpu->CP15[CP15(CP15_CACHE_TYPE)];
- } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
- RD = cpu->CP15[CP15(CP15_CONTROL)];
- } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
- RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
- } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
- RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
- RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
- RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)];
- } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
- RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)];
- } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
- RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
- } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) {
- RD = cpu->CP15[CP15(CP15_FAULT_STATUS)];
- } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) {
- RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
- } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) {
- RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
- } else if (CRn == 13) {
- if(OPCODE_2 == 0) {
- RD = CP15_REG(CP15_PID);
- } else if(OPCODE_2 == 1) {
- RD = CP15_REG(CP15_CONTEXT_ID);
- } else if (OPCODE_2 == 2) {
- RD = CP15_REG(CP15_THREAD_UPRW);
- } else if(OPCODE_2 == 3) {
- RD = Memory::KERNEL_MEMORY_VADDR;
- } else if (OPCODE_2 == 4) {
- if (InAPrivilegedMode(cpu))
- RD = CP15_REG(CP15_THREAD_PRW);
- } else {
- LOG_ERROR(Core_ARM11, "mmu_mrr wrote UNKNOWN - reg %d", CRn);
- }
- } else {
- LOG_ERROR(Core_ARM11, "mrc CRn=%d, CRm=%d, OP2=%d is not implemented", CRn, CRm, OPCODE_2);
- }
- }
+ if (inst_cream->cp_num == 15)
+ RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2);
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4977,7 +4874,24 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
FETCH_INST;
GOTO_NEXT_INST;
}
+
MRRC_INST:
+ {
+ // Stubbed, as the MPCore doesn't have any registers that are accessible
+ // through this instruction.
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;
+
+ LOG_ERROR(Core_ARM11, "MRRC executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u",
+ inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
+ }
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mcrr_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
MRS_INST:
{
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
@@ -6379,7 +6293,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
SWI_INST:
{
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
- HLE::CallSVC(Memory::Read32(cpu->Reg[15]));
+ SVC::CallSVC(Memory::Read32(cpu->Reg[15]));
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -6637,24 +6551,24 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
s16 sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF);
if (sum1 >= 0x100)
- state->Cpsr |= (1 << 16);
+ cpu->Cpsr |= (1 << 16);
else
- state->Cpsr &= ~(1 << 16);
+ cpu->Cpsr &= ~(1 << 16);
if (sum2 >= 0x100)
- state->Cpsr |= (1 << 17);
+ cpu->Cpsr |= (1 << 17);
else
- state->Cpsr &= ~(1 << 17);
+ cpu->Cpsr &= ~(1 << 17);
if (sum3 >= 0x100)
- state->Cpsr |= (1 << 18);
+ cpu->Cpsr |= (1 << 18);
else
- state->Cpsr &= ~(1 << 18);
+ cpu->Cpsr &= ~(1 << 18);
if (sum4 >= 0x100)
- state->Cpsr |= (1 << 19);
+ cpu->Cpsr |= (1 << 19);
else
- state->Cpsr &= ~(1 << 19);
+ cpu->Cpsr &= ~(1 << 19);
lo_result = ((sum1 & 0xFF) | (sum2 & 0xFF) << 8);
hi_result = ((sum3 & 0xFF) | (sum4 & 0xFF) << 8);
@@ -6667,24 +6581,24 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
s16 diff4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF);
if (diff1 >= 0)
- state->Cpsr |= (1 << 16);
+ cpu->Cpsr |= (1 << 16);
else
- state->Cpsr &= ~(1 << 16);
+ cpu->Cpsr &= ~(1 << 16);
if (diff2 >= 0)
- state->Cpsr |= (1 << 17);
+ cpu->Cpsr |= (1 << 17);
else
- state->Cpsr &= ~(1 << 17);
+ cpu->Cpsr &= ~(1 << 17);
if (diff3 >= 0)
- state->Cpsr |= (1 << 18);
+ cpu->Cpsr |= (1 << 18);
else
- state->Cpsr &= ~(1 << 18);
+ cpu->Cpsr &= ~(1 << 18);
if (diff4 >= 0)
- state->Cpsr |= (1 << 19);
+ cpu->Cpsr |= (1 << 19);
else
- state->Cpsr &= ~(1 << 19);
+ cpu->Cpsr &= ~(1 << 19);
lo_result = (diff1 & 0xFF) | ((diff2 & 0xFF) << 8);
hi_result = (diff3 & 0xFF) | ((diff4 & 0xFF) << 8);
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h
index e1742049..85774c56 100644
--- a/src/core/arm/dyncom/arm_dyncom_run.h
+++ b/src/core/arm/dyncom/arm_dyncom_run.h
@@ -22,31 +22,36 @@
void switch_mode(ARMul_State* core, uint32_t mode);
-/* FIXME, we temporarily think thumb instruction is always 16 bit */
+// Note that for the 3DS, a Thumb instruction will only ever be
+// two bytes in size. Thus we don't need to worry about ThumbEE
+// or Thumb-2 where instructions can be 4 bytes in length.
static inline u32 GET_INST_SIZE(ARMul_State* core) {
return core->TFlag? 2 : 4;
}
/**
-* @brief Read R15 and forced R15 to wold align, used address calculation
-*
-* @param core
-* @param Rn
-*
-* @return
-*/
-static inline addr_t CHECK_READ_REG15_WA(ARMul_State* core, int Rn) {
- return (Rn == 15)? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+ * Checks if the PC is being read, and if so, word-aligns it.
+ * Used with address calculations.
+ *
+ * @param core The ARM CPU state instance.
+ * @param Rn The register being read.
+ *
+ * @return If the PC is being read, then the word-aligned PC value is returned.
+ * If the PC is not being read, then the value stored in the register is returned.
+ */
+static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) {
+ return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
}
/**
-* @brief Read R15, used to data processing with pc
-*
-* @param core
-* @param Rn
-*
-* @return
-*/
+ * Reads the PC. Used for data processing operations that use the PC.
+ *
+ * @param core The ARM CPU state instance.
+ * @param Rn The register being read.
+ *
+ * @return If the PC is being read, then the incremented PC value is returned.
+ * If the PC is not being read, then the values stored in the register is returned.
+ */
static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) {
- return (Rn == 15)? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+ return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index e30d515f..08b5c0b7 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -6,14 +6,12 @@
// ARM instruction, and using the existing ARM simulator.
#include "core/arm/dyncom/arm_dyncom_thumb.h"
-#include "core/arm/skyeye_common/armos.h"
-#include "core/arm/skyeye_common/skyeye_defs.h"
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
// allows easier simulation of the special dual BL instruction.
-tdstate thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size) {
+tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
tdstate valid = t_uninitialized;
ARMword tinstr = instr;
@@ -288,7 +286,7 @@ tdstate thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t*
: 0xE28DDF00) // ADD
|(tinstr & 0x007F); // off7
} else if ((tinstr & 0x0F00) == 0x0e00)
- *ainstr = 0xEF000000 | SWI_Breakpoint;
+ *ainstr = 0xEF000000 | 0x180000; // base | BKPT mask
else {
static const ARMword subset[4] = {
0xE92D0000, // STMDB sp!,{rlist}
@@ -320,7 +318,7 @@ tdstate thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t*
*ainstr |= ((tinstr & 0x00FF) << 16);
// New breakpoint value. See gdb/arm-tdep.c
else if ((tinstr & 0x00FF) == 0xFE)
- *ainstr |= SWI_Breakpoint;
+ *ainstr |= 0x180000; // base |= BKPT mask
else
*ainstr |= (tinstr & 0x00FF);
} else if ((tinstr & 0x0F00) != 0x0E00)
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h
index a1785abb..8394ff15 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.h
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.h
@@ -35,9 +35,9 @@ enum tdstate {
t_uninitialized,
};
-tdstate thumb_translate(addr_t addr, u32 instr, u32* ainstr, u32* inst_size);
+tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
-static inline u32 get_thumb_instr(u32 instr, addr_t pc) {
+static inline u32 get_thumb_instr(u32 instr, u32 pc) {
u32 tinstr;
if ((pc & 0x3) != 0)
tinstr = instr >> 16;
diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp
deleted file mode 100644
index 4ae0c52e..00000000
--- a/src/core/arm/interpreter/armcopro.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/* armcopro.c -- co-processor interface: ARM6 Instruction Emulator.
- Copyright (C) 1994, 2000 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "core/arm/skyeye_common/armdefs.h"
-#include "core/arm/skyeye_common/armemu.h"
-#include "core/arm/skyeye_common/vfp/vfp.h"
-
-// Dummy Co-processors.
-
-static unsigned int NoCoPro3R(ARMul_State* state, unsigned int a, ARMword b)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro4R(ARMul_State* state, unsigned int a, ARMword b, ARMword c)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro4W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro5R(ARMul_State* state, unsigned int a, ARMword b, ARMword c, ARMword d)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro5W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c, ARMword* d)
-{
- return ARMul_CANT;
-}
-
-// Install co-processor instruction handlers in this routine.
-void ARMul_CoProInit(ARMul_State* state)
-{
- // Initialise tham all first.
- for (unsigned int i = 0; i < 16; i++)
- ARMul_CoProDetach(state, i);
-
- // Install CoPro Instruction handlers here.
- // The format is:
- // ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
- // LDC routine, STC routine, MRC routine, MCR routine,
- // CDP routine, Read Reg routine, Write Reg routine).
- if (state->is_v6) {
- ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
- ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
-
- /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
- MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/
- }
-
- // No handlers below here.
-
- // Call all the initialisation routines.
- for (unsigned int i = 0; i < 16; i++) {
- if (state->CPInit[i])
- (state->CPInit[i]) (state);
- }
-}
-
-// Install co-processor finalisation routines in this routine.
-void ARMul_CoProExit(ARMul_State * state)
-{
- for (unsigned int i = 0; i < 16; i++)
- if (state->CPExit[i])
- (state->CPExit[i]) (state);
-
- // Detach all handlers.
- for (unsigned int i = 0; i < 16; i++)
- ARMul_CoProDetach(state, i);
-}
-
-// Routines to hook Co-processors into ARMulator.
-
-void
-ARMul_CoProAttach(ARMul_State* state,
-unsigned number,
-ARMul_CPInits* init,
-ARMul_CPExits* exit,
-ARMul_LDCs* ldc,
-ARMul_STCs* stc,
-ARMul_MRCs* mrc,
-ARMul_MCRs* mcr,
-ARMul_MRRCs* mrrc,
-ARMul_MCRRs* mcrr,
-ARMul_CDPs* cdp,
-ARMul_CPReads* read, ARMul_CPWrites* write)
-{
- if (init != NULL)
- state->CPInit[number] = init;
- if (exit != NULL)
- state->CPExit[number] = exit;
- if (ldc != NULL)
- state->LDC[number] = ldc;
- if (stc != NULL)
- state->STC[number] = stc;
- if (mrc != NULL)
- state->MRC[number] = mrc;
- if (mcr != NULL)
- state->MCR[number] = mcr;
- if (mrrc != NULL)
- state->MRRC[number] = mrrc;
- if (mcrr != NULL)
- state->MCRR[number] = mcrr;
- if (cdp != NULL)
- state->CDP[number] = cdp;
- if (read != NULL)
- state->CPRead[number] = read;
- if (write != NULL)
- state->CPWrite[number] = write;
-}
-
-void ARMul_CoProDetach(ARMul_State* state, unsigned number)
-{
- ARMul_CoProAttach(state, number, NULL, NULL,
- NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
- NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
-
- state->CPInit[number] = NULL;
- state->CPExit[number] = NULL;
- state->CPRead[number] = NULL;
- state->CPWrite[number] = NULL;
-}
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 4ac827e0..680a94a3 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -18,31 +18,16 @@
#include <cstring>
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armemu.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
/***************************************************************************\
* Returns a new instantiation of the ARMulator's state *
\***************************************************************************/
ARMul_State* ARMul_NewState(ARMul_State* state)
{
- memset(state, 0, sizeof(ARMul_State));
-
state->Emulate = RUN;
- for (unsigned int i = 0; i < 16; i++) {
- state->Reg[i] = 0;
- for (unsigned int j = 0; j < 7; j++)
- state->RegBank[j][i] = 0;
- }
- for (unsigned int i = 0; i < 7; i++)
- state->Spsr[i] = 0;
-
state->Mode = USER32MODE;
- state->VectorCatch = 0;
- state->Aborted = false;
- state->Reseted = false;
- state->Inted = 3;
- state->LastInted = 3;
-
state->lateabtSig = HIGH;
state->bigendSig = LOW;
@@ -55,15 +40,69 @@ ARMul_State* ARMul_NewState(ARMul_State* state)
void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
{
- state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
- state->is_v5 = (properties & ARM_v5_Prop) != 0;
- state->is_v5e = (properties & ARM_v5e_Prop) != 0;
- state->is_v6 = (properties & ARM_v6_Prop) != 0;
- state->is_v7 = (properties & ARM_v7_Prop) != 0;
-
- // Only initialse the coprocessor support once we
- // know what kind of chip we are dealing with.
- ARMul_CoProInit(state);
+ state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
+ state->is_v5 = (properties & ARM_v5_Prop) != 0;
+ state->is_v5e = (properties & ARM_v5e_Prop) != 0;
+ state->is_v6 = (properties & ARM_v6_Prop) != 0;
+ state->is_v7 = (properties & ARM_v7_Prop) != 0;
+}
+
+// Resets certain MPCore CP15 values to their ARM-defined reset values.
+static void ResetMPCoreCP15Registers(ARMul_State* cpu)
+{
+ // c0
+ cpu->CP15[CP15_MAIN_ID] = 0x410FB024;
+ cpu->CP15[CP15_TLB_TYPE] = 0x00000800;
+ cpu->CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
+ cpu->CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
+ cpu->CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
+ cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
+ cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
+ cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
+ cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
+ cpu->CP15[CP15_ISA_FEATURE_0] = 0x00100011;
+ cpu->CP15[CP15_ISA_FEATURE_1] = 0x12002111;
+ cpu->CP15[CP15_ISA_FEATURE_2] = 0x11221011;
+ cpu->CP15[CP15_ISA_FEATURE_3] = 0x01102131;
+ cpu->CP15[CP15_ISA_FEATURE_4] = 0x00000141;
+
+ // c1
+ cpu->CP15[CP15_CONTROL] = 0x00054078;
+ cpu->CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
+ cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
+
+ // c2
+ cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
+ cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
+ cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
+
+ // c3
+ cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
+
+ // c7
+ cpu->CP15[CP15_PHYS_ADDRESS] = 0x00000000;
+
+ // c9
+ cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
+
+ // c10
+ cpu->CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
+ cpu->CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
+ cpu->CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
+
+ // c13
+ cpu->CP15[CP15_PID] = 0x00000000;
+ cpu->CP15[CP15_CONTEXT_ID] = 0x00000000;
+ cpu->CP15[CP15_THREAD_UPRW] = 0x00000000;
+ cpu->CP15[CP15_THREAD_URO] = 0x00000000;
+ cpu->CP15[CP15_THREAD_PRW] = 0x00000000;
+
+ // c15
+ cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
+ cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
}
/***************************************************************************\
@@ -71,24 +110,20 @@ void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
\***************************************************************************/
void ARMul_Reset(ARMul_State* state)
{
- state->NextInstr = 0;
+ VFPInit(state);
state->Reg[15] = 0;
state->Cpsr = INTBITS | SVC32MODE;
state->Mode = SVC32MODE;
-
state->Bank = SVCBANK;
- FLUSHPIPE;
- state->EndCondition = 0;
- state->ErrorCode = 0;
+ ResetMPCoreCP15Registers(state);
state->NresetSig = HIGH;
state->NfiqSig = HIGH;
state->NirqSig = HIGH;
state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
state->abortSig = LOW;
- state->AbortAddr = 1;
state->NumInstrs = 0;
}
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index aca2bfbb..1b078dc7 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -15,7 +15,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#include "common/logging/log.h"
+
+#include "core/mem_map.h"
#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
// Unsigned sum of absolute difference
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
@@ -207,3 +211,427 @@ bool InBigEndianMode(ARMul_State* cpu)
{
return (cpu->Cpsr & (1 << 9)) != 0;
}
+
+// Whether or not the given CPU is in a mode other than user mode.
+bool InAPrivilegedMode(ARMul_State* cpu)
+{
+ return (cpu->Mode != USER32MODE);
+}
+
+// Reads from the CP15 registers. Used with implementation of the MRC instruction.
+// Note that since the 3DS does not have the hypervisor extensions, these registers
+// are not implemented.
+u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
+{
+ // Unprivileged registers
+ if (crn == 13 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_THREAD_UPRW];
+
+ if (opcode_2 == 3)
+ return cpu->CP15[CP15_THREAD_URO];
+ }
+
+ if (InAPrivilegedMode(cpu))
+ {
+ if (crn == 0 && opcode_1 == 0)
+ {
+ if (crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_MAIN_ID];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_CACHE_TYPE];
+
+ if (opcode_2 == 3)
+ return cpu->CP15[CP15_TLB_TYPE];
+
+ if (opcode_2 == 5)
+ return cpu->CP15[CP15_CPU_ID];
+ }
+ else if (crm == 1)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_PROCESSOR_FEATURE_0];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_PROCESSOR_FEATURE_1];
+
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_DEBUG_FEATURE_0];
+
+ if (opcode_2 == 4)
+ return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0];
+
+ if (opcode_2 == 5)
+ return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1];
+
+ if (opcode_2 == 6)
+ return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2];
+
+ if (opcode_2 == 7)
+ return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3];
+ }
+ else if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_ISA_FEATURE_0];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_ISA_FEATURE_1];
+
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_ISA_FEATURE_2];
+
+ if (opcode_2 == 3)
+ return cpu->CP15[CP15_ISA_FEATURE_3];
+
+ if (opcode_2 == 4)
+ return cpu->CP15[CP15_ISA_FEATURE_4];
+ }
+ }
+
+ if (crn == 1 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_CONTROL];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_AUXILIARY_CONTROL];
+
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
+ }
+
+ if (crn == 2 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1];
+
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_TRANSLATION_BASE_CONTROL];
+ }
+
+ if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ return cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL];
+
+ if (crn == 5 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_FAULT_STATUS];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_INSTR_FAULT_STATUS];
+ }
+
+ if (crn == 6 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_FAULT_ADDRESS];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_WFAR];
+ }
+
+ if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
+ return cpu->CP15[CP15_PHYS_ADDRESS];
+
+ if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ return cpu->CP15[CP15_DATA_CACHE_LOCKDOWN];
+
+ if (crn == 10 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 0)
+ return cpu->CP15[CP15_TLB_LOCKDOWN];
+
+ if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_PRIMARY_REGION_REMAP];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_NORMAL_REGION_REMAP];
+ }
+ }
+
+ if (crn == 13 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_PID];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_CONTEXT_ID];
+
+ if (opcode_2 == 4)
+ return cpu->CP15[CP15_THREAD_PRW];
+ }
+
+ if (crn == 15)
+ {
+ if (opcode_1 == 0 && crm == 12)
+ {
+ if (opcode_2 == 0)
+ return cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
+
+ if (opcode_2 == 1)
+ return cpu->CP15[CP15_CYCLE_COUNTER];
+
+ if (opcode_2 == 2)
+ return cpu->CP15[CP15_COUNT_0];
+
+ if (opcode_2 == 3)
+ return cpu->CP15[CP15_COUNT_1];
+ }
+
+ if (opcode_1 == 5 && opcode_2 == 2)
+ {
+ if (crm == 5)
+ return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
+
+ if (crm == 6)
+ return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
+
+ if (crm == 7)
+ return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
+ }
+
+ if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
+ return cpu->CP15[CP15_TLB_DEBUG_CONTROL];
+ }
+ }
+
+ LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
+ return 0;
+}
+
+// Write to the CP15 registers. Used with implementation of the MCR instruction.
+// Note that since the 3DS does not have the hypervisor extensions, these registers
+// are not implemented.
+void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
+{
+ if (InAPrivilegedMode(cpu))
+ {
+ if (crn == 1 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_CONTROL] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_AUXILIARY_CONTROL] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
+ }
+ else if (crn == 2 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
+ }
+ else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ {
+ cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
+ }
+ else if (crn == 5 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_FAULT_STATUS] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INSTR_FAULT_STATUS] = value;
+ }
+ else if (crn == 6 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_FAULT_ADDRESS] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_WFAR] = value;
+ }
+ else if (crn == 7 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 4)
+ {
+ cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value;
+ }
+ else if (crm == 4 && opcode_2 == 0)
+ {
+ // NOTE: Not entirely accurate. This should do permission checks.
+ cpu->CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
+ }
+ else if (crm == 5)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
+ else if (opcode_2 == 6)
+ cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
+ else if (opcode_2 == 7)
+ cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
+ }
+ else if (crm == 6)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_INVALIDATE_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ else if (crm == 7 && opcode_2 == 0)
+ {
+ cpu->CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
+ }
+ else if (crm == 10)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_CLEAN_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ else if (crm == 14)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ }
+ else if (crn == 8 && opcode_1 == 0)
+ {
+ LOG_WARNING(Core_ARM11, "TLB operations not fully implemented.");
+
+ if (crm == 5)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_INVALIDATE_ITLB] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
+ }
+ else if (crm == 6)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_INVALIDATE_DTLB] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
+ }
+ else if (crm == 7)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_INVALIDATE_UTLB] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
+ }
+ }
+ else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ {
+ cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
+ }
+ else if (crn == 10 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 0)
+ {
+ cpu->CP15[CP15_TLB_LOCKDOWN] = value;
+ }
+ else if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_PRIMARY_REGION_REMAP] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_NORMAL_REGION_REMAP] = value;
+ }
+ }
+ else if (crn == 13 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_PID] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_CONTEXT_ID] = value;
+ else if (opcode_2 == 3)
+ cpu->CP15[CP15_THREAD_URO] = value;
+ else if (opcode_2 == 4)
+ cpu->CP15[CP15_THREAD_PRW] = value;
+ }
+ else if (crn == 15)
+ {
+ if (opcode_1 == 0 && crm == 12)
+ {
+ if (opcode_2 == 0)
+ cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
+ else if (opcode_2 == 1)
+ cpu->CP15[CP15_CYCLE_COUNTER] = value;
+ else if (opcode_2 == 2)
+ cpu->CP15[CP15_COUNT_0] = value;
+ else if (opcode_2 == 3)
+ cpu->CP15[CP15_COUNT_1] = value;
+ }
+ else if (opcode_1 == 5)
+ {
+ if (crm == 4)
+ {
+ if (opcode_2 == 2)
+ cpu->CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
+ else if (opcode_2 == 4)
+ cpu->CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
+ }
+ else if (crm == 5 && opcode_2 == 2)
+ {
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
+ }
+ else if (crm == 6 && opcode_2 == 2)
+ {
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
+ }
+ else if (crm == 7 && opcode_2 == 2)
+ {
+ cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
+ }
+ }
+ else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
+ {
+ cpu->CP15[CP15_TLB_DEBUG_CONTROL] = value;
+ }
+ }
+ }
+
+ // Unprivileged registers
+ if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
+ {
+ cpu->CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
+ }
+ else if (crn == 7 && opcode_1 == 0 && crm == 10)
+ {
+ if (opcode_2 == 4)
+ cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
+ else if (opcode_2 == 5)
+ cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
+
+ }
+ else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
+ {
+ cpu->CP15[CP15_THREAD_UPRW] = value;
+ }
+}
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index 5be3a561..6c89774e 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -50,55 +50,134 @@ enum {
EXCLUSIVE_TAG,
EXCLUSIVE_STATE,
EXCLUSIVE_RESULT,
- CP15_BASE,
- CP15_C0 = CP15_BASE,
- CP15_C0_C0 = CP15_C0,
- CP15_MAIN_ID = CP15_C0_C0,
+
+ MAX_REG_NUM,
+};
+
+// VFP system registers
+enum {
+ VFP_FPSID,
+ VFP_FPSCR,
+ VFP_FPEXC,
+
+ // Not an actual register.
+ // All VFP system registers should be defined above this.
+ VFP_SYSTEM_REGISTER_COUNT
+};
+
+enum CP15Register {
+ // c0 - Information registers
+ CP15_MAIN_ID,
CP15_CACHE_TYPE,
CP15_TCM_STATUS,
CP15_TLB_TYPE,
- CP15_C0_C1,
- CP15_PROCESSOR_FEATURE_0 = CP15_C0_C1,
+ CP15_CPU_ID,
+ CP15_PROCESSOR_FEATURE_0,
CP15_PROCESSOR_FEATURE_1,
CP15_DEBUG_FEATURE_0,
CP15_AUXILIARY_FEATURE_0,
- CP15_C1_C0,
- CP15_CONTROL = CP15_C1_C0,
+ CP15_MEMORY_MODEL_FEATURE_0,
+ CP15_MEMORY_MODEL_FEATURE_1,
+ CP15_MEMORY_MODEL_FEATURE_2,
+ CP15_MEMORY_MODEL_FEATURE_3,
+ CP15_ISA_FEATURE_0,
+ CP15_ISA_FEATURE_1,
+ CP15_ISA_FEATURE_2,
+ CP15_ISA_FEATURE_3,
+ CP15_ISA_FEATURE_4,
+
+ // c1 - Control registers
+ CP15_CONTROL,
CP15_AUXILIARY_CONTROL,
CP15_COPROCESSOR_ACCESS_CONTROL,
- CP15_C2,
- CP15_C2_C0 = CP15_C2,
- CP15_TRANSLATION_BASE = CP15_C2_C0,
- CP15_TRANSLATION_BASE_TABLE_0 = CP15_TRANSLATION_BASE,
+
+ // c2 - Translation table registers
+ CP15_TRANSLATION_BASE_TABLE_0,
CP15_TRANSLATION_BASE_TABLE_1,
CP15_TRANSLATION_BASE_CONTROL,
CP15_DOMAIN_ACCESS_CONTROL,
CP15_RESERVED,
- /* Fault status */
+
+ // c5 - Fault status registers
CP15_FAULT_STATUS,
CP15_INSTR_FAULT_STATUS,
CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS,
CP15_INST_FSR,
- /* Fault Address register */
+
+ // c6 - Fault Address registers
CP15_FAULT_ADDRESS,
CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS,
CP15_WFAR,
CP15_IFAR,
+
+ // c7 - Cache operation registers
+ CP15_WAIT_FOR_INTERRUPT,
+ CP15_PHYS_ADDRESS,
+ CP15_INVALIDATE_INSTR_CACHE,
+ CP15_INVALIDATE_INSTR_CACHE_USING_MVA,
+ CP15_INVALIDATE_INSTR_CACHE_USING_INDEX,
+ CP15_FLUSH_PREFETCH_BUFFER,
+ CP15_FLUSH_BRANCH_TARGET_CACHE,
+ CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY,
+ CP15_INVALIDATE_DATA_CACHE,
+ CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
+ CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
+ CP15_INVALIDATE_DATA_AND_INSTR_CACHE,
+ CP15_CLEAN_DATA_CACHE,
+ CP15_CLEAN_DATA_CACHE_LINE_USING_MVA,
+ CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX,
+ CP15_DATA_SYNC_BARRIER,
+ CP15_DATA_MEMORY_BARRIER,
+ CP15_CLEAN_AND_INVALIDATE_DATA_CACHE,
+ CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
+ CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
+
+ // c8 - TLB operations
+ CP15_INVALIDATE_ITLB,
+ CP15_INVALIDATE_ITLB_SINGLE_ENTRY,
+ CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH,
+ CP15_INVALIDATE_ITLB_ENTRY_ON_MVA,
+ CP15_INVALIDATE_DTLB,
+ CP15_INVALIDATE_DTLB_SINGLE_ENTRY,
+ CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH,
+ CP15_INVALIDATE_DTLB_ENTRY_ON_MVA,
+ CP15_INVALIDATE_UTLB,
+ CP15_INVALIDATE_UTLB_SINGLE_ENTRY,
+ CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH,
+ CP15_INVALIDATE_UTLB_ENTRY_ON_MVA,
+
+ // c9 - Data cache lockdown register
+ CP15_DATA_CACHE_LOCKDOWN,
+
+ // c10 - TLB/Memory map registers
+ CP15_TLB_LOCKDOWN,
+ CP15_PRIMARY_REGION_REMAP,
+ CP15_NORMAL_REGION_REMAP,
+
+ // c13 - Thread related registers
CP15_PID,
CP15_CONTEXT_ID,
CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write
CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W)
CP15_THREAD_PRW, // Thread ID register - Privileged R/W only.
- CP15_TLB_FAULT_ADDR, /* defined by SkyEye */
- CP15_TLB_FAULT_STATUS, /* defined by SkyEye */
- /* VFP registers */
- VFP_BASE,
- VFP_FPSID = VFP_BASE,
- VFP_FPSCR,
- VFP_FPEXC,
- MAX_REG_NUM,
-};
+ // c15 - Performance and TLB lockdown registers
+ CP15_PERFORMANCE_MONITOR_CONTROL,
+ CP15_CYCLE_COUNTER,
+ CP15_COUNT_0,
+ CP15_COUNT_1,
+ CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY,
+ CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY,
+ CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS,
+ CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS,
+ CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE,
+ CP15_TLB_DEBUG_CONTROL,
+
+ // Skyeye defined
+ CP15_TLB_FAULT_ADDR,
+ CP15_TLB_FAULT_STATUS,
-#define CP15(idx) (idx - CP15_BASE)
-#define VFP_OFFSET(x) (x - VFP_BASE)
+ // Not an actual register.
+ // All registers should be defined above this.
+ CP15_REGISTER_COUNT,
+};
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index c1a19fec..470f9508 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -17,9 +17,10 @@
#pragma once
+#include <unordered_map>
+
#include "common/common_types.h"
#include "core/arm/skyeye_common/arm_regformat.h"
-#include "core/arm/skyeye_common/skyeye_defs.h"
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
#define BIT(s, n) ((s >> (n)) & 1)
@@ -53,26 +54,11 @@ typedef u64 ARMdword; // must be 64 bits wide
typedef u32 ARMword; // must be 32 bits wide
typedef u16 ARMhword; // must be 16 bits wide
typedef u8 ARMbyte; // must be 8 bits wide
-typedef struct ARMul_State ARMul_State;
-
-typedef unsigned ARMul_CPInits(ARMul_State* state);
-typedef unsigned ARMul_CPExits(ARMul_State* state);
-typedef unsigned ARMul_LDCs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-typedef unsigned ARMul_STCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-typedef unsigned ARMul_MRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-typedef unsigned ARMul_MCRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-typedef unsigned ARMul_MRRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2);
-typedef unsigned ARMul_MCRRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
-typedef unsigned ARMul_CDPs(ARMul_State* state, unsigned type, ARMword instr);
-typedef unsigned ARMul_CPReads(ARMul_State* state, unsigned reg, ARMword* value);
-typedef unsigned ARMul_CPWrites(ARMul_State* state, unsigned reg, ARMword value);
#define VFP_REG_NUM 64
struct ARMul_State
{
ARMword Emulate; // To start and stop emulation
- unsigned EndCondition; // Reason for stopping
- unsigned ErrorCode; // Type of illegal instruction
// Order of the following register should not be modified
ARMword Reg[16]; // The current register file
@@ -91,15 +77,15 @@ struct ARMul_State
ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode
ARMword exclusive_state;
ARMword exclusive_result;
- ARMword CP15[VFP_BASE - CP15_BASE];
- ARMword VFP[3]; // FPSID, FPSCR, and FPEXC
+ ARMword CP15[CP15_REGISTER_COUNT];
+
+ // FPSID, FPSCR, and FPEXC
+ ARMword VFP[VFP_SYSTEM_REGISTER_COUNT];
// VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
// VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
// and only 32 singleword registers are accessible (S0-S31).
ARMword ExtReg[VFP_REG_NUM];
/* ---- End of the ordered registers ---- */
-
- ARMword RegBank[7][16]; // all the registers
ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
unsigned int shifter_carry_out;
@@ -112,24 +98,7 @@ struct ARMul_State
unsigned long long NumInstrs; // The number of instructions executed
unsigned NumInstrsToExecute;
- unsigned NextInstr;
- unsigned VectorCatch; // Caught exception mask
-
- ARMul_CPInits* CPInit[16]; // Coprocessor initialisers
- ARMul_CPExits* CPExit[16]; // Coprocessor finalisers
- ARMul_LDCs* LDC[16]; // LDC instruction
- ARMul_STCs* STC[16]; // STC instruction
- ARMul_MRCs* MRC[16]; // MRC instruction
- ARMul_MCRs* MCR[16]; // MCR instruction
- ARMul_MRRCs* MRRC[16]; // MRRC instruction
- ARMul_MCRRs* MCRR[16]; // MCRR instruction
- ARMul_CDPs* CDP[16]; // CDP instruction
- ARMul_CPReads* CPRead[16]; // Read CP register
- ARMul_CPWrites* CPWrite[16]; // Write CP register
- unsigned char* CPData[16]; // Coprocessor data
- unsigned char const* CPRegWords[16]; // Map of coprocessor register sizes
-
- unsigned NresetSig; // Reset the processor
+ unsigned NresetSig; // Reset the processor
unsigned NfiqSig;
unsigned NirqSig;
@@ -171,13 +140,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
*/
unsigned lateabtSig;
- bool Aborted; // Sticky flag for aborts
- bool Reseted; // Sticky flag for Reset
- ARMword Inted, LastInted; // Sticky flags for interrupts
- ARMword Base; // Extra hand for base writeback
- ARMword AbortAddr; // To keep track of Prefetch aborts
- ARMword Vector; // Synthesize aborts in cycle modes
-
// For differentiating ARM core emulaiton.
bool is_v4; // Are we emulating a v4 architecture (or higher)?
bool is_v5; // Are we emulating a v5 architecture?
@@ -189,16 +151,9 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
// 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model
int abort_model;
- // Added by ksh in 2005-10-1
- cpu_config_t* cpu;
-
- u32 CurrInstr;
- u32 last_pc; // The last PC executed
- u32 last_instr; // The last instruction executed
- u32 WriteAddr[17];
- u32 WriteData[17];
- u32 WritePc[17];
- u32 CurrWrite;
+ // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
+ // process for our purposes), not per ARMul_State (which tracks CPU core state).
+ std::unordered_map<u32, int> instruction_cache;
};
/***************************************************************************\
@@ -284,34 +239,6 @@ enum {
ARMul_INC = 3
};
-enum {
- ARMul_CP13_R0_FIQ = 0x1,
- ARMul_CP13_R0_IRQ = 0x2,
- ARMul_CP13_R8_PMUS = 0x1,
-
- ARMul_CP14_R0_ENABLE = 0x0001,
- ARMul_CP14_R0_CLKRST = 0x0004,
- ARMul_CP14_R0_CCD = 0x0008,
- ARMul_CP14_R0_INTEN0 = 0x0010,
- ARMul_CP14_R0_INTEN1 = 0x0020,
- ARMul_CP14_R0_INTEN2 = 0x0040,
- ARMul_CP14_R0_FLAG0 = 0x0100,
- ARMul_CP14_R0_FLAG1 = 0x0200,
- ARMul_CP14_R0_FLAG2 = 0x0400,
- ARMul_CP14_R10_MOE_IB = 0x0004,
- ARMul_CP14_R10_MOE_DB = 0x0008,
- ARMul_CP14_R10_MOE_BT = 0x000c,
- ARMul_CP15_R1_ENDIAN = 0x0080,
- ARMul_CP15_R1_ALIGN = 0x0002,
- ARMul_CP15_R5_X = 0x0400,
- ARMul_CP15_R5_ST_ALIGN = 0x0001,
- ARMul_CP15_R5_IMPRE = 0x0406,
- ARMul_CP15_R5_MMU_EXCPT = 0x0400,
- ARMul_CP15_DBCON_M = 0x0100,
- ARMul_CP15_DBCON_E1 = 0x000c,
- ARMul_CP15_DBCON_E0 = 0x0003
-};
-
/***************************************************************************\
* Definitons of things in the host environment *
\***************************************************************************/
@@ -357,3 +284,7 @@ extern u32 ARMul_SignedSatQ(s32, u8, bool*);
extern u32 ARMul_UnsignedSatQ(s32, u8, bool*);
extern bool InBigEndianMode(ARMul_State*);
+extern bool InAPrivilegedMode(ARMul_State*);
+
+extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
+extern void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 2a1c5077..7e096505 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -38,16 +38,6 @@ enum : u32 {
INTBITS = 0x1C0,
};
-// Different ways to start the next instruction.
-enum {
- SEQ = 0,
- NONSEQ = 1,
- PCINCEDSEQ = 2,
- PCINCEDNONSEQ = 3,
- PRIMEPIPE = 4,
- RESUME = 8
-};
-
// Values for Emulate.
enum {
STOP = 0, // Stop
@@ -55,14 +45,3 @@ enum {
ONCE = 2, // Execute just one interation
RUN = 3 // Continuous execution
};
-
-#define FLUSHPIPE state->NextInstr |= PRIMEPIPE
-
-// Coprocessor support functions.
-extern void ARMul_CoProInit(ARMul_State*);
-extern void ARMul_CoProExit(ARMul_State*);
-extern void ARMul_CoProAttach(ARMul_State*, unsigned, ARMul_CPInits*,
- ARMul_CPExits*, ARMul_LDCs*, ARMul_STCs*,
- ARMul_MRCs*, ARMul_MCRs*, ARMul_MRRCs*, ARMul_MCRRs*,
- ARMul_CDPs*, ARMul_CPReads*, ARMul_CPWrites*);
-extern void ARMul_CoProDetach(ARMul_State*, unsigned);
diff --git a/src/core/arm/skyeye_common/armmmu.h b/src/core/arm/skyeye_common/armmmu.h
index 22e564c3..c67d7209 100644
--- a/src/core/arm/skyeye_common/armmmu.h
+++ b/src/core/arm/skyeye_common/armmmu.h
@@ -20,7 +20,9 @@
#pragma once
-#include "core/mem_map.h"
+#include "common/swap.h"
+
+#include "core/memory.h"
#include "core/arm/skyeye_common/armdefs.h"
// Register numbers in the MMU
diff --git a/src/core/arm/skyeye_common/armos.h b/src/core/arm/skyeye_common/armos.h
deleted file mode 100644
index 1217a728..00000000
--- a/src/core/arm/skyeye_common/armos.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* armos.h -- ARMulator OS definitions: ARM6 Instruction Emulator.
- Copyright (C) 1994 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-//
-// SWI Numbers
-//
-
-#define SWI_Syscall 0x0
-#define SWI_Exit 0x1
-#define SWI_Read 0x3
-#define SWI_Write 0x4
-#define SWI_Open 0x5
-#define SWI_Close 0x6
-#define SWI_Seek 0x13
-#define SWI_Rename 0x26
-#define SWI_Break 0x11
-
-#define SWI_Times 0x2b
-#define SWI_Brk 0x2d
-
-#define SWI_Mmap 0x5a
-#define SWI_Munmap 0x5b
-#define SWI_Mmap2 0xc0
-
-#define SWI_GetUID32 0xc7
-#define SWI_GetGID32 0xc8
-#define SWI_GetEUID32 0xc9
-#define SWI_GetEGID32 0xca
-
-#define SWI_ExitGroup 0xf8
-
-#define SWI_Uname 0x7a
-#define SWI_Fcntl 0xdd
-#define SWI_Fstat64 0xc5
-#define SWI_Gettimeofday 0x4e
-#define SWI_Set_tls 0xf0005
-
-#define SWI_Breakpoint 0x180000 /* see gdb's tm-arm.h */
-
diff --git a/src/core/arm/skyeye_common/skyeye_defs.h b/src/core/arm/skyeye_common/skyeye_defs.h
deleted file mode 100644
index edf6097e..00000000
--- a/src/core/arm/skyeye_common/skyeye_defs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include "common/common_types.h"
-
-struct cpu_config_t
-{
- const char* cpu_arch_name; // CPU architecture version name.e.g. ARMv4T
- const char* cpu_name; // CPU name. e.g. ARM7TDMI or ARM720T
- u32 cpu_val; // CPU value; also call MMU ID or processor id;see
- // ARM Architecture Reference Manual B2-6
- u32 cpu_mask; // cpu_val's mask.
- u32 cachetype; // CPU cache type
-};
-
-enum {
- // No exception
- No_exp = 0,
- // Memory allocation exception
- Malloc_exp,
- // File open exception
- File_open_exp,
- // DLL open exception
- Dll_open_exp,
- // Invalid argument exception
- Invarg_exp,
- // Invalid module exception
- Invmod_exp,
- // wrong format exception for config file parsing
- Conf_format_exp,
- // some reference excess the predefiend range. Such as the index out of array range
- Excess_range_exp,
- // Can not find the desirable result
- Not_found_exp,
- // Unknown exception
- Unknown_exp
-};
-
-typedef u32 addr_t;
diff --git a/src/core/arm/skyeye_common/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h
index ccb7cf4d..1187924f 100644
--- a/src/core/arm/skyeye_common/vfp/asm_vfp.h
+++ b/src/core/arm/skyeye_common/vfp/asm_vfp.h
@@ -7,15 +7,15 @@
#pragma once
-// FPSID Information
+// ARM11 MPCore FPSID Information
// Note that these are used as values and not as flags.
enum : u32 {
- VFP_FPSID_IMPLMEN = 0, // Implementation code. Should be the same as cp15 0 c0 0
- VFP_FPSID_SW = 0, // Software emulation bit value
- VFP_FPSID_SUBARCH = 0x2, // Subarchitecture version number
- VFP_FPSID_PARTNUM = 0x1, // Part number
- VFP_FPSID_VARIANT = 0x1, // Variant number
- VFP_FPSID_REVISION = 0x1 // Revision number
+ VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0
+ VFP_FPSID_SW = 0, // Software emulation bit value
+ VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number
+ VFP_FPSID_PARTNUM = 0x20, // Part number
+ VFP_FPSID_VARIANT = 0xB, // Variant number
+ VFP_FPSID_REVISION = 0x4 // Revision number
};
// FPEXC bits
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index 6286e7b6..b88d4775 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -20,7 +20,6 @@
/* Note: this file handles interface with arm core and vfp registers */
-#include "common/common.h"
#include "common/logging/log.h"
#include "core/arm/skyeye_common/armdefs.h"
@@ -29,304 +28,26 @@
unsigned VFPInit(ARMul_State* state)
{
- state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
- VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
- state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
+ state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
+ VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
+ state->VFP[VFP_FPEXC] = 0;
+ state->VFP[VFP_FPSCR] = 0;
return 0;
}
-unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value)
-{
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 21, 23);
- int Rt = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
- {
- /* VMOV r to s */
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, value);
- return ARMul_DONE;
- }
-
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
- {
- VMRS(state, CRn, Rt, value);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value)
-{
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 21, 23);
- int Rt = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
- if (CoProc == 10 || CoProc == 11)
- {
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
- {
- /* VMOV s to r */
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, &value);
- return ARMul_DONE;
- }
-
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
- {
- VMSR(state, CRn, Rt);
- return ARMul_DONE;
- }
-
- if ((OPC_1 & 0x4) == 0 && CoProc == 11 && CRm == 0)
- {
- VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && CRm == 0)
- {
- VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 4, 7);
- int Rt = BITS(instr, 12, 15);
- int Rt2 = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
-
- if (CoProc == 10 || CoProc == 11)
- {
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
- {
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
- {
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 4, 7);
- int Rt = BITS(instr, 12, 15);
- int Rt2 = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 11 || CoProc == 10)
- {
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
- {
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
- {
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value)
-{
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int CRd = BITS(instr, 12, 15);
- int Rn = BITS(instr, 16, 19);
- int imm8 = BITS(instr, 0, 7);
- int P = BIT(instr, 24);
- int U = BIT(instr, 23);
- int D = BIT(instr, 22);
- int W = BIT(instr, 21);
-
- /* TODO check access permission */
-
- /* VSTM */
- if ( (P|U|D|W) == 0 ) {
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
- exit(-1);
- }
- if (CoProc == 10 || CoProc == 11) {
-#if 1
- if (P == 0 && U == 0 && W == 0) {
- LOG_ERROR(Core_ARM11, "VSTM Related encodings\n");
- exit(-1);
- }
- if (P == U && W == 1) {
- LOG_ERROR(Core_ARM11, "UNDEFINED\n");
- exit(-1);
- }
-#endif
-
- if (P == 1 && W == 0)
- {
- return VSTR(state, type, instr, value);
- }
-
- if (P == 1 && U == 0 && W == 1 && Rn == 0xD)
- {
- return VPUSH(state, type, instr, value);
- }
-
- return VSTM(state, type, instr, value);
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value)
+void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
{
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int CRd = BITS(instr, 12, 15);
- int Rn = BITS(instr, 16, 19);
- int imm8 = BITS(instr, 0, 7);
- int P = BIT(instr, 24);
- int U = BIT(instr, 23);
- int D = BIT(instr, 22);
- int W = BIT(instr, 21);
-
- /* TODO check access permission */
-
- if ( (P|U|D|W) == 0 ) {
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
- exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
+ if (reg == 1)
{
- if (P == 1 && W == 0)
- {
- return VLDR(state, type, instr, value);
- }
-
- if (P == 0 && U == 1 && W == 1 && Rn == 0xD)
- {
- return VPOP(state, type, instr, value);
- }
-
- return VLDM(state, type, instr, value);
+ state->VFP[VFP_FPSCR] = state->Reg[Rt];
}
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr)
-{
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 20, 23);
- int CRd = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
+ else if (reg == 8)
{
- if ((OPC_1 & 0xB) == 0xB && BITS(instr, 4, 7) == 0)
- {
- unsigned int single = BIT(instr, 8) == 0;
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
- unsigned int imm;
- instr = BITS(instr, 16, 19) << 4 | BITS(instr, 0, 3); // FIXME dirty workaround to get a correct imm
-
- if (single)
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0x1f : 0)<<25 | BITS(instr, 0, 5)<<19;
- else
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0xff : 0)<<22 | BITS(instr, 0, 5)<<16;
-
- VMOVI(state, single, d, imm);
- return ARMul_DONE;
- }
-
- if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x6) == 0x2)
- {
- unsigned int single = BIT(instr, 8) == 0;
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
- unsigned int m = (single ? BITS(instr, 0, 3)<<1 | BIT(instr, 5) : BITS(instr, 0, 3) | BIT(instr, 5)<<4);
- VMOVR(state, single, d, m);
- return ARMul_DONE;
- }
-
- int exceptions = 0;
- if (CoProc == 10)
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
- else
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- return ARMul_DONE;
+ state->VFP[VFP_FPEXC] = state->Reg[Rt];
}
- LOG_WARNING(Core_ARM11, "Can't identify %x\n", instr);
- return ARMul_CANT;
}
-/* ----------- MRC ------------ */
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
{
if (to_arm)
@@ -338,43 +59,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
state->ExtReg[n] = *value;
}
}
-void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value)
-{
- if (reg == 1)
- {
- if (Rt != 15)
- {
- *value = state->VFP[VFP_OFFSET(VFP_FPSCR)];
- }
- else
- {
- *value = state->VFP[VFP_OFFSET(VFP_FPSCR)] ;
- }
- }
- else
- {
- switch (reg)
- {
- case 0:
- *value = state->VFP[VFP_OFFSET(VFP_FPSID)];
- break;
- case 6:
- /* MVFR1, VFPv3 only ? */
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", Rt);
- break;
- case 7:
- /* MVFR0, VFPv3 only? */
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", Rt);
- break;
- case 8:
- *value = state->VFP[VFP_OFFSET(VFP_FPEXC)];
- break;
- default:
- LOG_TRACE(Core_ARM11, "\tSUBARCHITECTURE DEFINED\n");
- break;
- }
- }
-}
+
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
{
if (to_arm)
@@ -402,301 +87,6 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
}
}
-/* ----------- MCR ------------ */
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
-{
- if (reg == 1)
- {
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = state->Reg[Rt];
- }
- else if (reg == 8)
- {
- state->VFP[VFP_OFFSET(VFP_FPEXC)] = state->Reg[Rt];
- }
-}
-
-/* Memory operation are not inlined, as old Interpreter and Fast interpreter
- don't have the same memory operation interface.
- Old interpreter framework does one access to coprocessor per data, and
- handles already data write, as well as address computation,
- which is not the case for Fast interpreter. Therefore, implementation
- of vfp instructions in old interpreter and fast interpreter are separate. */
-
-/* ----------- STC ------------ */
-int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_reg, add, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_reg = BIT(instr, 8) == 0; // Double precision
- add = BIT(instr, 23);
- imm32 = BITS(instr, 0,7)<<2; // may not be used
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); /* Base register */
- n = BITS(instr, 16, 19); // destination register
-
- i = 0;
- regs = 1;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_reg)
- {
- *value = state->ExtReg[d+i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2+i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_regs, d, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- imm32 = BITS(instr, 0,7)<<2; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FSTMX if regs is odd
-
- state->Reg[R13] = state->Reg[R13] - imm32;
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- *value = state->ExtReg[d + i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2 + i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_regs, add, wback, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- add = BIT(instr, 23);
- wback = BIT(instr, 21); // write-back
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
- imm32 = BITS(instr, 0,7) * 4; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FSTMX if regs is odd
-
- if (wback) {
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
- }
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- *value = state->ExtReg[d + i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2 + i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-
-/* ----------- LDC ------------ */
-int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_regs, d, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FLDMX if regs is odd
-
- state->Reg[R13] = state->Reg[R13] + imm32;
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_TRANSFER)
- {
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- state->ExtReg[d + i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2 + i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_reg, add, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_reg = BIT(instr, 8) == 0; // Double precision
- add = BIT(instr, 23);
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
-
- i = 0;
- regs = 1;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_TRANSFER)
- {
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_reg)
- {
- state->ExtReg[d+i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2+i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_regs, add, wback, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- add = BIT(instr, 23);
- wback = BIT(instr, 21); // write-back
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
- imm32 = BITS(instr, 0, 7) * 4; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FLDMX if regs is odd
-
- if (wback) {
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
- }
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- state->ExtReg[d + i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2 + i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-
-/* ----------- CDP ------------ */
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
{
if (single)
@@ -774,5 +164,5 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
fpscr |= exceptions;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
+ state->VFP[VFP_FPSCR] = fpscr;
}
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index 445a224b..727350f1 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -25,16 +25,9 @@
#define VFP_DEBUG_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1);
#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__);
#define CHECK_VFP_ENABLED
-#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); //if (ret == -1) {printf("VFP CDP FAILURE %x\n", inst_cream->instr); exit(-1);}
+#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
unsigned VFPInit(ARMul_State* state);
-unsigned VFPMRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-unsigned VFPMCR(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-unsigned VFPMRRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2);
-unsigned VFPMCRR(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
-unsigned VFPSTC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-unsigned VFPLDC(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-unsigned VFPCDP(ARMul_State* state, unsigned type, ARMword instr);
s32 vfp_get_float(ARMul_State* state, u32 reg);
void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
@@ -44,23 +37,10 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
-// MRC
-void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value);
+void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
-// MCR
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
-
-// STC
-int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value);
-int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value);
-int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value);
-
-// LDC
-int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value);
-int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value);
-int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value);
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index 5d1b4e53..ccc0212a 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -35,9 +35,7 @@
#include <cstdio>
#include "common/common_types.h"
#include "core/arm/skyeye_common/armdefs.h"
-
-#define pr_info //printf
-#define pr_debug //printf
+#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#define do_div(n, base) {n/=base;}
@@ -239,33 +237,6 @@ struct vfp_single {
#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
-// Unpack a single-precision float. Note that this returns the magnitude
-// of the single-precision float mantissa with the 1. if necessary,
-// aligned to bit 30.
-static inline void vfp_single_unpack(vfp_single* s, s32 val)
-{
- u32 significand;
-
- s->sign = vfp_single_packed_sign(val) >> 16,
- s->exponent = vfp_single_packed_exponent(val);
-
- significand = (u32) val;
- significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
- if (s->exponent && s->exponent != 255)
- significand |= 0x40000000;
- s->significand = significand;
-}
-
-// Re-pack a single-precision float. This assumes that the float is
-// already normalised such that the MSB is bit 30, _not_ bit 31.
-static inline s32 vfp_single_pack(vfp_single* s)
-{
- u32 val = (s->sign << 16) +
- (s->exponent << VFP_SINGLE_MANTISSA_BITS) +
- (s->significand >> VFP_SINGLE_LOW_BITS);
- return (s32)val;
-}
-
enum : u32 {
VFP_NUMBER = (1 << 0),
VFP_ZERO = (1 << 1),
@@ -297,6 +268,39 @@ static inline int vfp_single_type(vfp_single* s)
return type;
}
+// Unpack a single-precision float. Note that this returns the magnitude
+// of the single-precision float mantissa with the 1. if necessary,
+// aligned to bit 30.
+static inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr)
+{
+ s->sign = vfp_single_packed_sign(val) >> 16,
+ s->exponent = vfp_single_packed_exponent(val);
+
+ u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
+ if (s->exponent && s->exponent != 255)
+ significand |= 0x40000000;
+ s->significand = significand;
+
+ // If flush-to-zero mode is enabled, turn the denormal into zero.
+ // On a VFPv2 architecture, the sign of the zero is always positive.
+ if ((*fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) {
+ s->sign = 0;
+ s->exponent = 0;
+ s->significand = 0;
+ *fpscr |= FPSCR_IDC;
+ }
+}
+
+// Re-pack a single-precision float. This assumes that the float is
+// already normalised such that the MSB is bit 30, _not_ bit 31.
+static inline s32 vfp_single_pack(vfp_single* s)
+{
+ u32 val = (s->sign << 16) +
+ (s->exponent << VFP_SINGLE_MANTISSA_BITS) +
+ (s->significand >> VFP_SINGLE_LOW_BITS);
+ return (s32)val;
+}
+
u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, const char* func);
@@ -331,24 +335,49 @@ struct vfp_double {
#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
+static inline int vfp_double_type(vfp_double* s)
+{
+ int type = VFP_NUMBER;
+ if (s->exponent == 2047) {
+ if (s->significand == 0)
+ type = VFP_INFINITY;
+ else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
+ type = VFP_QNAN;
+ else
+ type = VFP_SNAN;
+ } else if (s->exponent == 0) {
+ if (s->significand == 0)
+ type |= VFP_ZERO;
+ else
+ type |= VFP_DENORMAL;
+ }
+ return type;
+}
+
// Unpack a double-precision float. Note that this returns the magnitude
// of the double-precision float mantissa with the 1. if necessary,
// aligned to bit 62.
-static inline void vfp_double_unpack(vfp_double* s, s64 val)
+static inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr)
{
- u64 significand;
-
s->sign = vfp_double_packed_sign(val) >> 48;
s->exponent = vfp_double_packed_exponent(val);
- significand = (u64) val;
- significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
+ u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
if (s->exponent && s->exponent != 2047)
significand |= (1ULL << 62);
s->significand = significand;
+
+ // If flush-to-zero mode is enabled, turn the denormal into zero.
+ // On a VFPv2 architecture, the sign of the zero is always positive.
+ if ((*fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) {
+ s->sign = 0;
+ s->exponent = 0;
+ s->significand = 0;
+ *fpscr |= FPSCR_IDC;
+ }
}
-// Re-pack a double-precision float. This assumes that the float is
+// Re-pack a double-precision float. This assumes that the float is
// already normalised such that the MSB is bit 30, _not_ bit 31.
static inline s64 vfp_double_pack(vfp_double* s)
{
@@ -358,25 +387,6 @@ static inline s64 vfp_double_pack(vfp_double* s)
return (s64)val;
}
-static inline int vfp_double_type(vfp_double* s)
-{
- int type = VFP_NUMBER;
- if (s->exponent == 2047) {
- if (s->significand == 0)
- type = VFP_INFINITY;
- else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
- type = VFP_QNAN;
- else
- type = VFP_SNAN;
- } else if (s->exponent == 0) {
- if (s->significand == 0)
- type |= VFP_ZERO;
- else
- type |= VFP_DENORMAL;
- }
- return type;
-}
-
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
// A special flag to tell the normalisation code not to normalise.
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index d76d37fd..ab9fec39 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -291,7 +291,8 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32
vfp_double vdm, vdd, *vdp;
int ret, tm;
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
+
tm = vfp_double_type(&vdm);
if (tm & (VFP_NAN|VFP_INFINITY)) {
vdp = &vdd;
@@ -473,7 +474,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32
u32 exceptions = 0;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
tm = vfp_double_type(&vdm);
@@ -543,7 +544,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
int tm;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
/*
* Do we have a denormalised number?
@@ -624,7 +625,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
int tm;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
vfp_double_dump("VDM", &vdm);
/*
@@ -896,11 +897,11 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f
struct vfp_double vdd, vdp, vdn, vdm;
u32 exceptions;
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
if (vdn.exponent == 0 && vdn.significand)
vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
if (vdm.exponent == 0 && vdm.significand)
vfp_double_normalise_denormal(&vdm);
@@ -908,7 +909,7 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f
if (negate & NEG_MULTIPLY)
vdp.sign = vfp_sign_negate(vdp.sign);
- vfp_double_unpack(&vdn, vfp_get_double(state, dd));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dd), &fpscr);
if (vdn.exponent == 0 && vdn.significand != 0)
vfp_double_normalise_denormal(&vdn);
@@ -969,11 +970,11 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
u32 exceptions;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
if (vdn.exponent == 0 && vdn.significand)
vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
if (vdm.exponent == 0 && vdm.significand)
vfp_double_normalise_denormal(&vdm);
@@ -990,11 +991,11 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
u32 exceptions;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
if (vdn.exponent == 0 && vdn.significand)
vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
if (vdm.exponent == 0 && vdm.significand)
vfp_double_normalise_denormal(&vdm);
@@ -1013,11 +1014,11 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
u32 exceptions;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
if (vdn.exponent == 0 && vdn.significand)
vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
if (vdm.exponent == 0 && vdm.significand)
vfp_double_normalise_denormal(&vdm);
@@ -1035,11 +1036,11 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
u32 exceptions;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
if (vdn.exponent == 0 && vdn.significand)
vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
if (vdm.exponent == 0 && vdm.significand)
vfp_double_normalise_denormal(&vdm);
@@ -1063,8 +1064,8 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
int tm, tn;
LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr);
vdd.sign = vdn.sign ^ vdm.sign;
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 368b5a25..72afe216 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -46,9 +46,9 @@ VMLA_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -96,9 +96,9 @@ VMLS_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -146,9 +146,9 @@ VNMLA_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -197,9 +197,9 @@ VNMLS_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -247,9 +247,9 @@ VNMUL_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -297,9 +297,9 @@ VMUL_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -347,9 +347,9 @@ VADD_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -397,9 +397,9 @@ VSUB_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -447,9 +447,9 @@ VDIV_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -591,9 +591,9 @@ VABS_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -642,9 +642,9 @@ VNEG_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -692,9 +692,9 @@ VSQRT_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -742,9 +742,9 @@ VCMP_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -792,9 +792,9 @@ VCMP2_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -842,9 +842,9 @@ VCVTBDS_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -894,9 +894,9 @@ VCVTBFF_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -944,9 +944,9 @@ VCVTBFI_INST:
int ret;
if (inst_cream->dp_operation)
- ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
else
- ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
CHECK_VFP_CDP_RET;
}
@@ -1146,14 +1146,14 @@ VMRS_INST:
{
if (inst_cream->Rt != 15)
{
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_OFFSET(VFP_FPSCR)];
+ cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR];
}
else
{
- cpu->NFlag = (cpu->VFP[VFP_OFFSET(VFP_FPSCR)] >> 31) & 1;
- cpu->ZFlag = (cpu->VFP[VFP_OFFSET(VFP_FPSCR)] >> 30) & 1;
- cpu->CFlag = (cpu->VFP[VFP_OFFSET(VFP_FPSCR)] >> 29) & 1;
- cpu->VFlag = (cpu->VFP[VFP_OFFSET(VFP_FPSCR)] >> 28) & 1;
+ cpu->NFlag = (cpu->VFP[VFP_FPSCR] >> 31) & 1;
+ cpu->ZFlag = (cpu->VFP[VFP_FPSCR] >> 30) & 1;
+ cpu->CFlag = (cpu->VFP[VFP_FPSCR] >> 29) & 1;
+ cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
}
}
else
@@ -1161,7 +1161,7 @@ VMRS_INST:
switch (inst_cream->reg)
{
case 0:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_OFFSET(VFP_FPSID)];
+ cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID];
break;
case 6:
/* MVFR1, VFPv3 only ? */
@@ -1172,7 +1172,7 @@ VMRS_INST:
LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", inst_cream->Rt);
break;
case 8:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_OFFSET(VFP_FPEXC)];
+ cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC];
break;
default:
break;
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 8b2dfa38..4dfe0254 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -51,6 +51,8 @@
* ===========================================================================
*/
+#include "common/logging/log.h"
+
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
@@ -63,8 +65,8 @@ static struct vfp_single vfp_single_default_qnan = {
static void vfp_single_dump(const char *str, struct vfp_single *s)
{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
- str, s->sign != 0, s->exponent, s->significand);
+ LOG_DEBUG(Core_ARM11, "%s: sign=%d exponent=%d significand=%08x",
+ str, s->sign != 0, s->exponent, s->significand);
}
static void vfp_single_normalise_denormal(struct vfp_single *vs)
@@ -154,7 +156,7 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
} else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
- pr_debug("VFP: rounding increment = 0x%08x\n", incr);
+ LOG_DEBUG(Core_ARM11, "rounding increment = 0x%08x", incr);
/*
* Is our rounding going to overflow?
@@ -209,10 +211,8 @@ pack:
vfp_single_dump("pack: final", vs);
{
s32 d = vfp_single_pack(vs);
-#if 1
- pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
- sd, d, exceptions);
-#endif
+ LOG_DEBUG(Core_ARM11, "%s: d(s%d)=%08x exceptions=%08x", func,
+ sd, d, exceptions);
vfp_put_float(state, d, sd);
}
@@ -302,7 +302,7 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
u32 z, a;
if ((significand & 0xc0000000) != 0x40000000) {
- pr_debug("VFP: estimate_sqrt: invalid significand\n");
+ LOG_DEBUG(Core_ARM11, "invalid significand");
}
a = significand << 1;
@@ -330,7 +330,7 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f
struct vfp_single vsm, vsd, *vsp;
int ret, tm;
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
tm = vfp_single_type(&vsm);
if (tm & (VFP_NAN|VFP_INFINITY)) {
vsp = &vsd;
@@ -392,7 +392,7 @@ sqrt_invalid:
term = (u64)vsd.significand * vsd.significand;
rem = ((u64)vsm.significand << 32) - term;
- pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
+ LOG_DEBUG(Core_ARM11, "term=%016lx rem=%016lx", term, rem);
while (rem < 0) {
vsd.significand -= 1;
@@ -498,7 +498,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f
int tm;
u32 exceptions = 0;
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
tm = vfp_single_type(&vsm);
@@ -563,7 +563,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
int rmode = fpscr & FPSCR_RMODE_MASK;
int tm;
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
vfp_single_dump("VSM", &vsm);
/*
@@ -624,7 +624,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
}
}
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+ LOG_DEBUG(Core_ARM11, "ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
vfp_put_float(state, d, sd);
@@ -643,7 +643,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
int rmode = fpscr & FPSCR_RMODE_MASK;
int tm;
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
vfp_single_dump("VSM", &vsm);
/*
@@ -703,7 +703,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
}
}
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+ LOG_DEBUG(Core_ARM11, "ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
vfp_put_float(state, (s32)d, sd);
@@ -800,7 +800,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
if (vsn->significand & 0x80000000 ||
vsm->significand & 0x80000000) {
- pr_info("VFP: bad FP values in %s\n", __func__);
+ LOG_WARNING(Core_ARM11, "bad FP values");
vfp_single_dump("VSN", vsn);
vfp_single_dump("VSM", vsm);
}
@@ -871,7 +871,7 @@ vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_s
struct vfp_single *t = vsn;
vsn = vsm;
vsm = t;
- pr_debug("VFP: swapping M <-> N\n");
+ LOG_DEBUG(Core_ARM11, "swapping M <-> N");
}
vsd->sign = vsn->sign ^ vsm->sign;
@@ -924,12 +924,12 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
s32 v;
v = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, v);
- vfp_single_unpack(&vsn, v);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, v);
+ vfp_single_unpack(&vsn, v, &fpscr);
if (vsn.exponent == 0 && vsn.significand)
vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
if (vsm.exponent == 0 && vsm.significand)
vfp_single_normalise_denormal(&vsm);
@@ -939,8 +939,8 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
vsp.sign = vfp_sign_negate(vsp.sign);
v = vfp_get_float(state, sd);
- pr_debug("VFP: s%u = %08x\n", sd, v);
- vfp_single_unpack(&vsn, v);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sd, v);
+ vfp_single_unpack(&vsn, v, &fpscr);
if (vsn.exponent == 0 && vsn.significand != 0)
vfp_single_normalise_denormal(&vsn);
@@ -961,7 +961,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
*/
static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
}
@@ -970,7 +970,8 @@ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
+ // TODO: this one has its arguments inverted, investigate.
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sd, sn);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
}
@@ -979,7 +980,7 @@ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
*/
static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
}
@@ -988,7 +989,7 @@ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
}
@@ -1001,13 +1002,13 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
- vfp_single_unpack(&vsn, n);
+ vfp_single_unpack(&vsn, n, &fpscr);
if (vsn.exponent == 0 && vsn.significand)
vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
if (vsm.exponent == 0 && vsm.significand)
vfp_single_normalise_denormal(&vsm);
@@ -1024,13 +1025,13 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
- vfp_single_unpack(&vsn, n);
+ vfp_single_unpack(&vsn, n, &fpscr);
if (vsn.exponent == 0 && vsn.significand)
vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
if (vsm.exponent == 0 && vsm.significand)
vfp_single_normalise_denormal(&vsm);
@@ -1048,16 +1049,16 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
/*
* Unpack and normalise denormals.
*/
- vfp_single_unpack(&vsn, n);
+ vfp_single_unpack(&vsn, n, &fpscr);
if (vsn.exponent == 0 && vsn.significand)
vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsm, m, &fpscr);
if (vsm.exponent == 0 && vsm.significand)
vfp_single_normalise_denormal(&vsm);
@@ -1071,7 +1072,7 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
/*
* Subtraction is addition with one sign inverted.
*/
@@ -1091,10 +1092,10 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
s32 n = vfp_get_float(state, sn);
int tm, tn;
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
- vfp_single_unpack(&vsn, n);
- vfp_single_unpack(&vsm, m);
+ vfp_single_unpack(&vsn, n, &fpscr);
+ vfp_single_unpack(&vsm, m, &fpscr);
vsd.sign = vsn.sign ^ vsm.sign;
@@ -1213,7 +1214,6 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
unsigned int sm = vfp_get_sm(inst);
unsigned int vecitr, veclen, vecstride;
struct op *fop;
- pr_debug("In %s\n", __FUNCTION__);
vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
@@ -1239,11 +1239,11 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
else
veclen = fpscr & FPSCR_LENGTH_MASK;
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
+ LOG_DEBUG(Core_ARM11, "vecstride=%u veclen=%u", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
if (!fop->fn) {
- printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
+ LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
exit(-1);
goto invalid;
}
@@ -1255,17 +1255,17 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
type = (fop->flags & OP_DD) ? 'd' : 's';
if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- sm, m);
+ LOG_DEBUG(Core_ARM11, "itr%d (%c%u) = op[%u] (s%u=%08x)",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ sm, m);
else
- pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- FOP_TO_IDX(op), sm, m);
+ LOG_DEBUG(Core_ARM11, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ FOP_TO_IDX(op), sm, m);
except = fop->fn(state, dest, sn, m, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
+ LOG_DEBUG(Core_ARM11, "itr%d: exceptions=%08x",
+ vecitr >> FPSCR_LENGTH_BIT, except);
exceptions |= except;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 15787bc1..79038cd5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -22,9 +23,9 @@ ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
/// Run the core CPU loop
void RunLoop(int tight_loop) {
- // If the current thread is an idle thread, then don't execute instructions,
+ // If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
- if (Kernel::GetCurrentThread()->IsIdle()) {
+ if (Kernel::GetCurrentThread() == nullptr) {
LOG_TRACE(Core_ARM11, "Idling");
CoreTiming::Idle();
CoreTiming::Advance();
diff --git a/src/core/core.h b/src/core/core.h
index 5e132cb5..278f0f1c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -21,9 +21,6 @@ struct ThreadContext {
u32 fpu_registers[32];
u32 fpscr;
u32 fpexc;
-
- // These are not part of native ThreadContext, but needed by emu
- u32 mode;
};
extern ARM_Interface* g_app_core; ///< ARM11 application core
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 6f716b1c..f70c84c3 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -160,6 +160,16 @@ void Init() {
last_global_time_us = 0;
has_ts_events = 0;
mhz_change_callbacks.clear();
+
+ first = nullptr;
+ ts_first = nullptr;
+ ts_last = nullptr;
+
+ event_pool = nullptr;
+ event_ts_pool = nullptr;
+ allocated_ts_events = 0;
+
+ advance_callback = nullptr;
}
void Shutdown() {
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index d62ff360..01519608 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -21,7 +21,7 @@
#include <functional>
-#include "common/common.h"
+#include "common/common_types.h"
extern int g_clock_rate_arm11;
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
new file mode 100644
index 00000000..45a559ce
--- /dev/null
+++ b/src/core/file_sys/archive_backend.cpp
@@ -0,0 +1,127 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <sstream>
+
+#include "common/logging/log.h"
+#include "common/string_util.h"
+
+#include "core/file_sys/archive_backend.h"
+#include "core/memory.h"
+
+
+namespace FileSys {
+
+Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) {
+ switch (type) {
+ case Binary:
+ {
+ u8* data = Memory::GetPointer(pointer);
+ binary = std::vector<u8>(data, data + size);
+ break;
+ }
+
+ case Char:
+ {
+ const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
+ string = std::string(data, size - 1); // Data is always null-terminated.
+ break;
+ }
+
+ case Wchar:
+ {
+ const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
+ u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+const std::string Path::DebugStr() const {
+ switch (GetType()) {
+ case Invalid:
+ default:
+ return "[Invalid]";
+ case Empty:
+ return "[Empty]";
+ case Binary:
+ {
+ std::stringstream res;
+ res << "[Binary: ";
+ for (unsigned byte : binary)
+ res << std::hex << std::setw(2) << std::setfill('0') << byte;
+ res << ']';
+ return res.str();
+ }
+ case Char:
+ return "[Char: " + AsString() + ']';
+ case Wchar:
+ return "[Wchar: " + AsString() + ']';
+ }
+}
+
+const std::string Path::AsString() const {
+ switch (GetType()) {
+ case Char:
+ return string;
+ case Wchar:
+ return Common::UTF16ToUTF8(u16str);
+ case Empty:
+ return{};
+ case Invalid:
+ case Binary:
+ default:
+ // TODO(yuriks): Add assert
+ LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
+ return{};
+ }
+}
+
+const std::u16string Path::AsU16Str() const {
+ switch (GetType()) {
+ case Char:
+ return Common::UTF8ToUTF16(string);
+ case Wchar:
+ return u16str;
+ case Empty:
+ return{};
+ case Invalid:
+ case Binary:
+ // TODO(yuriks): Add assert
+ LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
+ return{};
+ }
+}
+
+const std::vector<u8> Path::AsBinary() const {
+ switch (GetType()) {
+ case Binary:
+ return binary;
+ case Char:
+ return std::vector<u8>(string.begin(), string.end());
+ case Wchar:
+ {
+ // use two u8 for each character of u16str
+ std::vector<u8> to_return(u16str.size() * 2);
+ for (size_t i = 0; i < u16str.size(); ++i) {
+ u16 tmp_char = u16str.at(i);
+ to_return[i*2] = (tmp_char & 0xFF00) >> 8;
+ to_return[i*2 + 1] = (tmp_char & 0x00FF);
+ }
+ return to_return;
+ }
+ case Empty:
+ return{};
+ case Invalid:
+ default:
+ // TODO(yuriks): Add assert
+ LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
+ return{};
+ }
+}
+
+}
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 43a10654..c6a1be79 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -5,22 +5,21 @@
#pragma once
#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
-#include "common/common_types.h"
-#include "common/string_util.h"
#include "common/bit_field.h"
+#include "common/common_types.h"
-#include "core/file_sys/file_backend.h"
-#include "core/file_sys/directory_backend.h"
-
-#include "core/mem_map.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
namespace FileSys {
+class FileBackend;
+class DirectoryBackend;
+
// Path string type
enum LowPathType : u32 {
Invalid = 0,
@@ -39,134 +38,22 @@ union Mode {
class Path {
public:
+ Path() : type(Invalid) {}
+ Path(const char* path) : type(Char), string(path) {}
+ Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) {}
+ Path(LowPathType type, u32 size, u32 pointer);
- Path() : type(Invalid) {
- }
-
- Path(const char* path) : type(Char), string(path) {
- }
-
- Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) {
- }
-
- Path(LowPathType type, u32 size, u32 pointer) : type(type) {
- switch (type) {
- case Binary:
- {
- u8* data = Memory::GetPointer(pointer);
- binary = std::vector<u8>(data, data + size);
- break;
- }
-
- case Char:
- {
- const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
- string = std::string(data, size - 1); // Data is always null-terminated.
- break;
- }
-
- case Wchar:
- {
- const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
- u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
- break;
- }
-
- default:
- break;
- }
- }
-
- LowPathType GetType() const {
- return type;
- }
+ LowPathType GetType() const { return type; }
/**
* Gets the string representation of the path for debugging
* @return String representation of the path for debugging
*/
- const std::string DebugStr() const {
- switch (GetType()) {
- case Invalid:
- default:
- return "[Invalid]";
- case Empty:
- return "[Empty]";
- case Binary:
- {
- std::stringstream res;
- res << "[Binary: ";
- for (unsigned byte : binary)
- res << std::hex << std::setw(2) << std::setfill('0') << byte;
- res << ']';
- return res.str();
- }
- case Char:
- return "[Char: " + AsString() + ']';
- case Wchar:
- return "[Wchar: " + AsString() + ']';
- }
- }
+ const std::string DebugStr() const;
- const std::string AsString() const {
- switch (GetType()) {
- case Char:
- return string;
- case Wchar:
- return Common::UTF16ToUTF8(u16str);
- case Empty:
- return {};
- case Invalid:
- case Binary:
- default:
- // TODO(yuriks): Add assert
- LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
- return {};
- }
- }
-
- const std::u16string AsU16Str() const {
- switch (GetType()) {
- case Char:
- return Common::UTF8ToUTF16(string);
- case Wchar:
- return u16str;
- case Empty:
- return {};
- case Invalid:
- case Binary:
- // TODO(yuriks): Add assert
- LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
- return {};
- }
- }
-
- const std::vector<u8> AsBinary() const {
- switch (GetType()) {
- case Binary:
- return binary;
- case Char:
- return std::vector<u8>(string.begin(), string.end());
- case Wchar:
- {
- // use two u8 for each character of u16str
- std::vector<u8> to_return(u16str.size() * 2);
- for (size_t i = 0; i < u16str.size(); ++i) {
- u16 tmp_char = u16str.at(i);
- to_return[i*2] = (tmp_char & 0xFF00) >> 8;
- to_return[i*2 + 1] = (tmp_char & 0x00FF);
- }
- return to_return;
- }
- case Empty:
- return {};
- case Invalid:
- default:
- // TODO(yuriks): Add assert
- LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
- return {};
- }
- }
+ const std::string AsString() const;
+ const std::u16string AsU16Str() const;
+ const std::vector<u8> AsBinary() const;
private:
LowPathType type;
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 3076fa26..38d498d0 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_extsavedata.h"
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index bf54a386..d4a12ed1 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_romfs.h"
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 8496e06f..8dff5196 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -6,10 +6,12 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/disk_archive.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/fs/archive.h"
#include "core/settings.h"
@@ -35,7 +37,7 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directo
}
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
- std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id);
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id);
if (!FileUtil::Exists(concrete_mount_point)) {
// When a SaveData archive is created for the first time, it is not yet formatted
// and the save file/directory structure expected by the game has not yet been initialized.
@@ -50,7 +52,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
}
ResultCode ArchiveFactory_SaveData::Format(const Path& path) {
- std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id);
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id);
FileUtil::DeleteDirRecursively(concrete_mount_point);
FileUtil::CreateFullPath(concrete_mount_point);
return RESULT_SUCCESS;
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index 47d8a9d2..e7e4fbf1 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_savedatacheck.h"
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 92b20c7f..c1234a18 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_sdmc.h"
diff --git a/src/core/file_sys/directory_backend.h b/src/core/file_sys/directory_backend.h
index 7f327dc4..a25dc0cf 100644
--- a/src/core/file_sys/directory_backend.h
+++ b/src/core/file_sys/directory_backend.h
@@ -4,12 +4,11 @@
#pragma once
+#include <array>
#include <cstddef>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
-
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index f53fd57d..9980cced 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/disk_archive.h"
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index dbbdced7..a22d3837 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -8,6 +8,8 @@
#include "common/file_util.h"
#include "core/file_sys/archive_backend.h"
+#include "core/file_sys/directory_backend.h"
+#include "core/file_sys/file_backend.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -24,7 +26,7 @@ class DiskArchive : public ArchiveBackend {
public:
DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
- virtual std::string GetName() const { return "DiskArchive: " + mount_point; }
+ virtual std::string GetName() const override { return "DiskArchive: " + mount_point; }
std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
bool DeleteFile(const Path& path) const override;
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 35890af1..0fcff184 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -6,8 +6,6 @@
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
-
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 35aca54f..2d2509d1 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/ivfc_archive.h"
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index 1aff9e0a..10415798 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -10,6 +10,8 @@
#include "common/common_types.h"
#include "core/file_sys/archive_backend.h"
+#include "core/file_sys/directory_backend.h"
+#include "core/file_sys/file_backend.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 40bae934..aea936d2 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -2,71 +2,30 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
+#include "common/assert.h"
#include "common/common_types.h"
#include "common/common_funcs.h"
#include "core/core.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/config_mem.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ConfigMem {
-struct ConfigMemDef {
- u8 kernel_unk; // 0
- u8 kernel_version_rev; // 1
- u8 kernel_version_min; // 2
- u8 kernel_version_maj; // 3
- u32 update_flag; // 4
- u64 ns_tid; // 8
- u32 sys_core_ver; // 10
- u8 unit_info; // 14
- u8 boot_firm; // 15
- u8 prev_firm; // 16
- INSERT_PADDING_BYTES(0x1); // 17
- u32 ctr_sdk_ver; // 18
- INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
- u32 app_mem_type; // 30
- INSERT_PADDING_BYTES(0x40 - 0x34); // 34
- u32 app_mem_alloc; // 40
- u32 sys_mem_alloc; // 44
- u32 base_mem_alloc; // 48
- INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
- u8 firm_unk; // 60
- u8 firm_version_rev; // 61
- u8 firm_version_min; // 62
- u8 firm_version_maj; // 63
- u32 firm_sys_core_ver; // 64
- u32 firm_ctr_sdk_ver; // 68
- INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
-};
-
-static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
-
-static ConfigMemDef config_mem;
-
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- u32 offset = addr - Memory::CONFIG_MEMORY_VADDR;
- ASSERT(offset < Memory::CONFIG_MEMORY_SIZE);
- var = *(reinterpret_cast<T*>(((uintptr_t)&config_mem) + offset));
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-
-template void Read<u64>(u64 &var, const u32 addr);
-template void Read<u32>(u32 &var, const u32 addr);
-template void Read<u16>(u16 &var, const u32 addr);
-template void Read<u8>(u8 &var, const u32 addr);
+ConfigMemDef config_mem;
void Init() {
+ std::memset(&config_mem, 0, sizeof(config_mem));
+
config_mem.update_flag = 0; // No update
config_mem.sys_core_ver = 0x2;
config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.prev_firm = 0;
config_mem.app_mem_type = 0x2; // Default app mem type is 0
- config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB)
config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB
config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc);
@@ -77,4 +36,7 @@ void Init() {
config_mem.firm_sys_core_ver = 0x2;
}
+void Shutdown() {
+}
+
} // namespace
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h
index 94853901..9825a09e 100644
--- a/src/core/hle/config_mem.h
+++ b/src/core/hle/config_mem.h
@@ -9,15 +9,49 @@
// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
// putting this as a subset of HLE for now.
+#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/swap.h"
+
+#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ConfigMem {
-template <typename T>
-void Read(T &var, const u32 addr);
+struct ConfigMemDef {
+ u8 kernel_unk; // 0
+ u8 kernel_version_rev; // 1
+ u8 kernel_version_min; // 2
+ u8 kernel_version_maj; // 3
+ u32_le update_flag; // 4
+ u64_le ns_tid; // 8
+ u32_le sys_core_ver; // 10
+ u8 unit_info; // 14
+ u8 boot_firm; // 15
+ u8 prev_firm; // 16
+ INSERT_PADDING_BYTES(0x1); // 17
+ u32_le ctr_sdk_ver; // 18
+ INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
+ u32_le app_mem_type; // 30
+ INSERT_PADDING_BYTES(0x40 - 0x34); // 34
+ u32_le app_mem_alloc; // 40
+ u32_le sys_mem_alloc; // 44
+ u32_le base_mem_alloc; // 48
+ INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
+ u8 firm_unk; // 60
+ u8 firm_version_rev; // 61
+ u8 firm_version_min; // 62
+ u8 firm_version_maj; // 63
+ u32_le firm_sys_core_ver; // 64
+ u32_le firm_ctr_sdk_ver; // 68
+ INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
+};
+static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
+
+extern ConfigMemDef config_mem;
void Init();
+void Shutdown();
} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 0b6b6f51..eb52c8fb 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -7,7 +7,7 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/hle.h"
namespace HLE {
@@ -46,6 +46,13 @@ template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
FuncReturn(retval);
}
+template<ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() {
+ u32 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
+ Core::g_app_core->SetReg(1, param_1);
+ FuncReturn(retval);
+}
+
template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
s32 param_1 = 0;
s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
@@ -102,7 +109,7 @@ template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){
template<ResultCode func(u32*, const char*)> void Wrap() {
u32 param_1 = 0;
- u32 retval = func(&param_1, Memory::GetCharPointer(PARAM(1))).raw;
+ u32 retval = func(&param_1, (char*)Memory::GetPointer(PARAM(1))).raw;
Core::g_app_core->SetReg(1, param_1);
FuncReturn(retval);
}
@@ -156,7 +163,7 @@ template<void func(s64)> void Wrap() {
}
template<void func(const char*)> void Wrap() {
- func(Memory::GetCharPointer(PARAM(0)));
+ func((char*)Memory::GetPointer(PARAM(0)));
}
#undef PARAM
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 1aaeaa9c..fdeb9a02 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -2,12 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <vector>
-
-#include "common/profiler.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/core.h"
#include "core/hle/hle.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
@@ -18,35 +17,7 @@
namespace HLE {
-Common::Profiling::TimingCategory profiler_svc("SVC Calls");
-
-static std::vector<ModuleDef> g_module_db;
-
-bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
-
-static const FunctionDef* GetSVCInfo(u32 opcode) {
- u32 func_num = opcode & 0xFFFFFF; // 8 bits
- if (func_num > 0xFF) {
- LOG_ERROR(Kernel_SVC,"unknown svc=0x%02X", func_num);
- return nullptr;
- }
- return &g_module_db[0].func_table[func_num];
-}
-
-void CallSVC(u32 opcode) {
- Common::Profiling::ScopeTimer timer_svc(profiler_svc);
-
- const FunctionDef *info = GetSVCInfo(opcode);
-
- if (!info) {
- return;
- }
- if (info->func) {
- info->func();
- } else {
- LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name.c_str());
- }
-}
+bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
void Reschedule(const char *reason) {
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
@@ -62,31 +33,21 @@ void Reschedule(const char *reason) {
g_reschedule = true;
}
-void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
- ModuleDef module = {name, num_functions, func_table};
- g_module_db.push_back(module);
-}
-
-static void RegisterAllModules() {
- SVC::Register();
-}
-
void Init() {
Service::Init();
-
- RegisterAllModules();
-
ConfigMem::Init();
SharedPage::Init();
+ g_reschedule = false;
+
LOG_DEBUG(Kernel, "initialized OK");
}
void Shutdown() {
+ ConfigMem::Shutdown();
+ SharedPage::Shutdown();
Service::Shutdown();
- g_module_db.clear();
-
LOG_DEBUG(Kernel, "shutdown OK");
}
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 3f6f9a4b..e0b97797 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -4,40 +4,20 @@
#pragma once
-#include <string>
-
#include "common/common_types.h"
-#include "core/core.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
+typedef u32 Handle;
+typedef s32 Result;
+
+const Handle INVALID_HANDLE = 0;
namespace HLE {
extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
-typedef u32 Addr;
-typedef void (*Func)();
-
-struct FunctionDef {
- u32 id;
- Func func;
- std::string name;
-};
-
-struct ModuleDef {
- std::string name;
- int num_funcs;
- const FunctionDef* func_table;
-};
-
-void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
-
-void CallSVC(u32 opcode);
-
void Reschedule(const char *reason);
void Init();
-
void Shutdown();
} // namespace
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 42f8ce2d..a1221766 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -3,8 +3,9 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/logging/log.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/address_arbiter.h"
@@ -46,14 +47,12 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
case ArbitrationType::WaitIfLessThan:
if ((s32)Memory::Read32(address) <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- HLE::Reschedule(__func__);
}
break;
case ArbitrationType::WaitIfLessThanWithTimeout:
if ((s32)Memory::Read32(address) <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds);
- HLE::Reschedule(__func__);
}
break;
case ArbitrationType::DecrementAndWaitIfLessThan:
@@ -62,7 +61,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
Memory::Write32(address, memory_value);
if (memory_value <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- HLE::Reschedule(__func__);
}
break;
}
@@ -73,7 +71,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
if (memory_value <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds);
- HLE::Reschedule(__func__);
}
break;
}
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 420906ec..f338f326 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -6,7 +6,7 @@
#include <algorithm>
#include <vector>
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/event.h"
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 498b2ec9..b5c98b24 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -4,21 +4,20 @@
#include <algorithm>
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
namespace Kernel {
-unsigned int Object::next_object_id = 0;
-
-SharedPtr<Thread> g_main_thread = nullptr;
+unsigned int Object::next_object_id;
HandleTable g_handle_table;
-u64 g_program_id = 0;
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
@@ -116,8 +115,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
if (handle == CurrentThread) {
return GetCurrentThread();
} else if (handle == CurrentProcess) {
- LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
- return nullptr;
+ return g_current_process;
}
if (!IsValid(handle)) {
@@ -138,6 +136,11 @@ void HandleTable::Clear() {
void Init() {
Kernel::ThreadingInit();
Kernel::TimersInit();
+
+ Object::next_object_id = 0;
+ // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
+ // reserved for low-level services
+ Process::next_process_id = 10;
}
/// Shutdown the kernel
@@ -145,18 +148,7 @@ void Shutdown() {
Kernel::ThreadingShutdown();
Kernel::TimersShutdown();
g_handle_table.Clear(); // Free all kernel objects
-}
-
-/**
- * Loads executable stored at specified address
- * @entry_point Entry point in memory of loaded executable
- * @return True on success, otherwise false
- */
-bool LoadExec(u32 entry_point) {
- // 0x30 is the typical main thread priority I've seen used so far
- g_main_thread = Kernel::SetupMainThread(Kernel::DEFAULT_STACK_SIZE, entry_point, 0x30);
-
- return true;
+ g_current_process = nullptr;
}
} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2d295ea0..7c106d37 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -7,21 +7,16 @@
#include <boost/intrusive_ptr.hpp>
#include <array>
+#include <memory>
#include <string>
#include <vector>
-#include "common/common.h"
-#include "core/hle/result.h"
-
-typedef u32 Handle;
-typedef s32 Result;
+#include "common/common_types.h"
-// TODO: It would be nice to eventually replace these with strong types that prevent accidental
-// conversion between each other.
-typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
-typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
+#include "core/hle/hle.h"
+#include "core/hle/result.h"
-const Handle INVALID_HANDLE = 0;
+struct ApplicationInfo;
namespace Kernel {
@@ -95,12 +90,13 @@ public:
return false;
}
+public:
+ static unsigned int next_object_id;
+
private:
friend void intrusive_ptr_add_ref(Object*);
friend void intrusive_ptr_release(Object*);
- static unsigned int next_object_id;
-
unsigned int ref_count = 0;
unsigned int object_id = next_object_id++;
};
@@ -277,23 +273,10 @@ private:
extern HandleTable g_handle_table;
-/// The ID code of the currently running game
-/// TODO(Subv): This variable should not be here,
-/// we need a way to store information about the currently loaded application
-/// for later query during runtime, maybe using the LDR service?
-extern u64 g_program_id;
-
/// Initialize the kernel
void Init();
/// Shutdown the kernel
void Shutdown();
-/**
- * Loads executable stored at specified address
- * @entry_point Entry point in memory of loaded executable
- * @return True on success, otherwise false
- */
-bool LoadExec(u32 entry_point);
-
} // namespace
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index be2c4970..f530217f 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -7,7 +7,7 @@
#include <boost/range/algorithm_ext/erase.hpp>
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
@@ -56,7 +56,15 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
}
bool Mutex::ShouldWait() {
- return lock_count > 0 && holding_thread != GetCurrentThread();;
+ auto thread = GetCurrentThread();
+ bool wait = lock_count > 0 && holding_thread != thread;
+
+ // If the holding thread of the mutex is lower priority than this thread, that thread should
+ // temporarily inherit this thread's priority
+ if (wait && thread->current_priority < holding_thread->current_priority)
+ holding_thread->BoostPriority(thread->current_priority);
+
+ return wait;
}
void Mutex::Acquire() {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
new file mode 100644
index 00000000..0cdfa58d
--- /dev/null
+++ b/src/core/hle/kernel/process.cpp
@@ -0,0 +1,98 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
+
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/thread.h"
+#include "core/memory.h"
+
+namespace Kernel {
+
+u32 Process::next_process_id;
+
+SharedPtr<Process> Process::Create(std::string name, u64 program_id) {
+ SharedPtr<Process> process(new Process);
+
+ process->name = std::move(name);
+ process->program_id = program_id;
+
+ process->flags.raw = 0;
+ process->flags.memory_region = MemoryRegion::APPLICATION;
+
+ return process;
+}
+
+void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
+ for (int i = 0; i < len; ++i) {
+ u32 descriptor = kernel_caps[i];
+ u32 type = descriptor >> 20;
+
+ if (descriptor == 0xFFFFFFFF) {
+ // Unused descriptor entry
+ continue;
+ } else if ((type & 0xF00) == 0xE00) { // 0x0FFF
+ // Allowed interrupts list
+ LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
+ } else if ((type & 0xF80) == 0xF00) { // 0x07FF
+ // Allowed syscalls mask
+ unsigned int index = ((descriptor >> 24) & 7) * 24;
+ u32 bits = descriptor & 0xFFFFFF;
+
+ while (bits && index < svc_access_mask.size()) {
+ svc_access_mask.set(index, bits & 1);
+ ++index; bits >>= 1;
+ }
+ } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
+ // Handle table size
+ handle_table_size = descriptor & 0x3FF;
+ } else if ((type & 0xFF8) == 0xFF0) { // 0x007F
+ // Misc. flags
+ flags.raw = descriptor & 0xFFFF;
+ } else if ((type & 0xFFE) == 0xFF8) { // 0x001F
+ // Mapped memory range
+ if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) {
+ LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
+ continue;
+ }
+ u32 end_desc = kernel_caps[i+1];
+ ++i; // Skip over the second descriptor on the next iteration
+
+ AddressMapping mapping;
+ mapping.address = descriptor << 12;
+ mapping.size = (end_desc << 12) - mapping.address;
+ mapping.writable = descriptor & (1 << 20);
+ mapping.unk_flag = end_desc & (1 << 20);
+
+ address_mappings.push_back(mapping);
+ } else if ((type & 0xFFF) == 0xFFE) { // 0x000F
+ // Mapped memory page
+ AddressMapping mapping;
+ mapping.address = descriptor << 12;
+ mapping.size = Memory::PAGE_SIZE;
+ mapping.writable = true; // TODO: Not sure if correct
+ mapping.unk_flag = false;
+ } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
+ // Kernel version
+ int minor = descriptor & 0xFF;
+ int major = (descriptor >> 8) & 0xFF;
+ LOG_INFO(Loader, "ExHeader kernel version ignored: %d.%d", major, minor);
+ } else {
+ LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor);
+ }
+ }
+}
+
+void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
+ Kernel::SetupMainThread(entry_point, main_thread_priority);
+}
+
+Kernel::Process::Process() {}
+Kernel::Process::~Process() {}
+
+SharedPtr<Process> g_current_process;
+
+}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
new file mode 100644
index 00000000..90881054
--- /dev/null
+++ b/src/core/hle/kernel/process.h
@@ -0,0 +1,98 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <bitset>
+
+#include <boost/container/static_vector.hpp>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+struct AddressMapping {
+ // Address and size must be page-aligned
+ VAddr address;
+ u32 size;
+ bool writable;
+ bool unk_flag;
+};
+
+enum class MemoryRegion : u16 {
+ APPLICATION = 1,
+ SYSTEM = 2,
+ BASE = 3,
+};
+
+union ProcessFlags {
+ u16 raw;
+
+ BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process.
+ BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set.
+ BitField< 2, 1, u16> allow_nonalphanum;
+ BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
+ BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
+ BitField< 5, 1, u16> allow_main_args;
+ BitField< 6, 1, u16> shared_device_mem;
+ BitField< 7, 1, u16> runnable_on_sleep;
+ BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process
+ BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
+};
+
+class Process final : public Object {
+public:
+ static SharedPtr<Process> Create(std::string name, u64 program_id);
+
+ std::string GetTypeName() const override { return "Process"; }
+ std::string GetName() const override { return name; }
+
+ static const HandleType HANDLE_TYPE = HandleType::Process;
+ HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+ static u32 next_process_id;
+
+ /// Name of the process
+ std::string name;
+ /// Title ID corresponding to the process
+ u64 program_id;
+
+ /// The process may only call SVCs which have the corresponding bit set.
+ std::bitset<0x80> svc_access_mask;
+ /// Maximum size of the handle table for the process.
+ unsigned int handle_table_size = 0x200;
+ /// Special memory ranges mapped into this processes address space. This is used to give
+ /// processes access to specific I/O regions and device memory.
+ boost::container::static_vector<AddressMapping, 8> address_mappings;
+ ProcessFlags flags;
+
+ /// The id of this process
+ u32 process_id = next_process_id++;
+
+ /// Bitmask of the used TLS slots
+ std::bitset<300> used_tls_slots;
+
+ /**
+ * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
+ * to this process.
+ */
+ void ParseKernelCaps(const u32* kernel_caps, size_t len);
+
+ /**
+ * Applies address space changes and launches the process main thread.
+ */
+ void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
+
+private:
+ Process();
+ ~Process() override;
+};
+
+extern SharedPtr<Process> g_current_process;
+
+}
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 6aecc24a..5d6543ef 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/semaphore.h"
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 9e9288e0..54a06297 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -5,19 +5,23 @@
#pragma once
#include "core/hle/kernel/kernel.h"
-#include "core/mem_map.h"
+#include "core/hle/kernel/thread.h"
+#include "core/memory.h"
namespace Kernel {
static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
/**
- * Returns a pointer to the command buffer in kernel memory
+ * Returns a pointer to the command buffer in the current thread's TLS
+ * TODO(Subv): This is not entirely correct, the command buffer should be copied from
+ * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
+ * the service handler process' memory.
* @param offset Optional offset into command buffer
* @return Pointer to command buffer
*/
-inline static u32* GetCommandBuffer(const int offset=0) {
- return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset);
+inline static u32* GetCommandBuffer(const int offset = 0) {
+ return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
}
/**
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4211fcf0..4137683b 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -2,9 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include <cstring>
-#include "core/mem_map.h"
+#include "common/logging/log.h"
+
+#include "core/memory.h"
#include "core/hle/kernel/shared_memory.h"
namespace Kernel {
@@ -12,10 +14,15 @@ namespace Kernel {
SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {}
-SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
+SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->name = std::move(name);
+ shared_memory->base_address = 0x0;
+ shared_memory->size = size;
+ shared_memory->permissions = permissions;
+ shared_memory->other_permissions = other_permissions;
return shared_memory;
}
@@ -23,7 +30,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
MemoryPermission other_permissions) {
- if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
+ if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
GetObjectId(), address);
// TODO: Verify error code with hardware
@@ -31,21 +38,25 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
}
+ // TODO: Test permissions
+
+ // HACK: Since there's no way to write to the memory block without mapping it onto the game
+ // process yet, at least initialize memory the first time it's mapped.
+ if (address != this->base_address) {
+ std::memset(Memory::GetPointer(address), 0, size);
+ }
+
this->base_address = address;
- this->permissions = permissions;
- this->other_permissions = other_permissions;
return RESULT_SUCCESS;
}
-ResultVal<u8*> SharedMemory::GetPointer(u32 offset) {
+u8* SharedMemory::GetPointer(u32 offset) {
if (base_address != 0)
- return MakeResult<u8*>(Memory::GetPointer(base_address + offset));
+ return Memory::GetPointer(base_address + offset);
LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
- // TODO(yuriks): Verify error code.
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
- ErrorSummary::InvalidState, ErrorLevel::Permanent);
+ return nullptr;
}
} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 5833b411..20426689 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -27,11 +27,16 @@ class SharedMemory final : public Object {
public:
/**
* Creates a shared memory object
- * @param name Optional object name, used only for debugging purposes.
+ * @param size Size of the memory block. Must be page-aligned.
+ * @param permissions Permission restrictions applied to the process which created the block.
+ * @param other_permissions Permission restrictions applied to other processes mapping the block.
+ * @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> Create(std::string name = "Unknown");
+ static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, std::string name = "Unknown");
std::string GetTypeName() const override { return "SharedMemory"; }
+ std::string GetName() const override { return name; }
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
@@ -49,12 +54,18 @@ public:
* @param offset Offset from the start of the shared memory block to get pointer
* @return Pointer to the shared memory block from the specified offset
*/
- ResultVal<u8*> GetPointer(u32 offset = 0);
+ u8* GetPointer(u32 offset = 0);
- VAddr base_address; ///< Address of shared memory block in RAM
- MemoryPermission permissions; ///< Permissions of shared memory block (SVC field)
- MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field)
- std::string name; ///< Name of shared memory object (optional)
+ /// Address of shared memory block in the process.
+ VAddr base_address;
+ /// Size of the memory block. Page-aligned.
+ u32 size;
+ /// Permission restrictions applied to the process which created the block.
+ MemoryPermission permissions;
+ /// Permission restrictions applied to other processes mapping the block.
+ MemoryPermission other_permissions;
+ /// Name of shared memory object.
+ std::string name;
private:
SharedMemory();
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index be1aed61..a5f1904d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -6,7 +6,9 @@
#include <list>
#include <vector>
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/thread_queue_list.h"
@@ -15,15 +17,16 @@
#include "core/core_timing.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/result.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
namespace Kernel {
/// Event type for the thread wake up event
-static int ThreadWakeupEventType = -1;
+static int ThreadWakeupEventType;
bool Thread::ShouldWait() {
return status != THREADSTATUS_DEAD;
@@ -42,7 +45,7 @@ static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue;
static Thread* current_thread;
// The first available thread id at startup
-static u32 next_thread_id = 1;
+static u32 next_thread_id;
/**
* Creates a new thread ID
@@ -104,6 +107,8 @@ void Thread::Stop() {
for (auto& wait_object : wait_objects) {
wait_object->RemoveWaitingThread(this);
}
+
+ Kernel::g_current_process->used_tls_slots[tls_index] = false;
}
Thread* ArbitrateHighestPriorityThread(u32 address) {
@@ -140,17 +145,38 @@ void ArbitrateAllThreads(u32 address) {
}
}
+/// Boost low priority threads (temporarily) that have been starved
+static void PriorityBoostStarvedThreads() {
+ u64 current_ticks = CoreTiming::GetTicks();
+
+ for (auto& thread : thread_list) {
+ // TODO(bunnei): Threads that have been waiting to be scheduled for `boost_ticks` (or
+ // longer) will have their priority temporarily adjusted to 1 higher than the highest
+ // priority thread to prevent thread starvation. This general behavior has been verified
+ // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler
+ // should probably be reversed to verify this.
+
+ const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
+
+ u64 delta = current_ticks - thread->last_running_ticks;
+
+ if (thread->status == THREADSTATUS_READY && delta > boost_timeout) {
+ const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
+ thread->BoostPriority(priority);
+ }
+ }
+}
+
/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
static void SwitchContext(Thread* new_thread) {
- DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
-
Thread* previous_thread = GetCurrentThread();
// Save context for previous thread
if (previous_thread) {
+ previous_thread->last_running_ticks = CoreTiming::GetTicks();
Core::g_app_core->SaveContext(previous_thread->context);
if (previous_thread->status == THREADSTATUS_RUNNING) {
@@ -163,12 +189,18 @@ static void SwitchContext(Thread* new_thread) {
// Load context of new thread
if (new_thread) {
+ DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
+
current_thread = new_thread;
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
+ // Restores thread to its nominal priority if it has been temporarily changed
+ new_thread->current_priority = new_thread->nominal_priority;
+
Core::g_app_core->LoadContext(new_thread->context);
+ Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
} else {
current_thread = nullptr;
}
@@ -186,6 +218,10 @@ static Thread* PopNextReadyThread() {
// We have to do better than the current thread.
// This call returns null when that's not possible.
next = ready_queue.pop_first_better(thread->current_priority);
+ if (!next) {
+ // Otherwise just keep going with the current thread
+ next = thread;
+ }
} else {
next = ready_queue.pop_first();
}
@@ -364,7 +400,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->status = THREADSTATUS_DORMANT;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
- thread->initial_priority = thread->current_priority = priority;
+ thread->nominal_priority = thread->current_priority = priority;
+ thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
thread->wait_set_output = false;
thread->wait_all = false;
@@ -372,6 +409,20 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->wait_address = 0;
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
+ thread->owner_process = g_current_process;
+ thread->tls_index = -1;
+
+ // Find the next available TLS index, and mark it as used
+ auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
+ for (unsigned int i = 0; i < used_tls_slots.size(); ++i) {
+ if (used_tls_slots[i] == false) {
+ thread->tls_index = i;
+ used_tls_slots[i] = true;
+ break;
+ }
+ }
+
+ ASSERT_MSG(thread->tls_index != -1, "Out of TLS space");
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
@@ -400,35 +451,26 @@ static void ClampPriority(const Thread* thread, s32* priority) {
void Thread::SetPriority(s32 priority) {
ClampPriority(this, &priority);
- if (current_priority == priority) {
- return;
- }
-
- if (status == THREADSTATUS_READY) {
- // If thread was ready, adjust queues
- ready_queue.remove(current_priority, this);
+ // If thread was ready, adjust queues
+ if (status == THREADSTATUS_READY)
+ ready_queue.move(this, current_priority, priority);
+ else
ready_queue.prepare(priority);
- ready_queue.push_back(priority, this);
- }
-
- current_priority = priority;
-}
-SharedPtr<Thread> SetupIdleThread() {
- // We need to pass a few valid values to get around parameter checking in Thread::Create.
- auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
- THREADPROCESSORID_0, 0).MoveFrom();
+ nominal_priority = current_priority = priority;
+}
- thread->idle = true;
- return thread;
+void Thread::BoostPriority(s32 priority) {
+ ready_queue.move(this, current_priority, priority);
+ current_priority = priority;
}
-SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority) {
+SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
DEBUG_ASSERT(!GetCurrentThread());
// Initialize new "main" thread
auto thread_res = Thread::Create("main", entry_point, priority, 0,
- THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END);
+ THREADPROCESSORID_0, Memory::HEAP_VADDR_END);
SharedPtr<Thread> thread = thread_res.MoveFrom();
@@ -439,21 +481,25 @@ SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority)
}
void Reschedule() {
- Thread* prev = GetCurrentThread();
+ PriorityBoostStarvedThreads();
+
+ Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
HLE::g_reschedule = false;
- if (next != nullptr) {
- LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId());
- SwitchContext(next);
- } else {
- LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId());
+ // Don't bother switching to the same thread
+ if (next == cur)
+ return;
- for (auto& thread : thread_list) {
- LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),
- thread->current_priority, thread->status);
- }
+ if (cur && next) {
+ LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
+ } else if (cur) {
+ LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId());
+ } else if (next) {
+ LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
}
+
+ SwitchContext(next);
}
void Thread::SetWaitSynchronizationResult(ResultCode result) {
@@ -464,13 +510,20 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
+VAddr Thread::GetTLSAddress() const {
+ return Memory::TLS_AREA_VADDR + tls_index * 0x200;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
void ThreadingInit() {
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
- // Setup the idle thread
- SetupIdleThread();
+ current_thread = nullptr;
+ next_thread_id = 1;
+
+ thread_list.clear();
+ ready_queue.clear();
}
void ThreadingShutdown() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index cfd073a7..38992817 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,22 +12,23 @@
#include "common/common_types.h"
#include "core/core.h"
-#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
-enum ThreadPriority {
- THREADPRIO_HIGHEST = 0, ///< Highest thread priority
- THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps
- THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps
- THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread
+enum ThreadPriority : s32{
+ THREADPRIO_HIGHEST = 0, ///< Highest thread priority
+ THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
+ THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
+ THREADPRIO_LOWEST = 63, ///< Lowest thread priority
};
-enum ThreadProcessorId {
- THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode
- THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore
- THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
+enum ThreadProcessorId : s32 {
+ THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
+ THREADPROCESSORID_ALL = -1, ///< Run thread on either core
+ THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
+ THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
+ THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
};
enum ThreadStatus {
@@ -43,6 +44,7 @@ enum ThreadStatus {
namespace Kernel {
class Mutex;
+class Process;
class Thread final : public WaitObject {
public:
@@ -70,12 +72,6 @@ public:
void Acquire() override;
/**
- * Checks if the thread is an idle (stub) thread
- * @return True if the thread is an idle (stub) thread, false otherwise
- */
- inline bool IsIdle() const { return idle; }
-
- /**
* Gets the thread's current priority
* @return The current thread's priority
*/
@@ -88,6 +84,12 @@ public:
void SetPriority(s32 priority);
/**
+ * Temporarily boosts the thread's priority until the next time it is scheduled
+ * @param priority The new priority
+ */
+ void BoostPriority(s32 priority);
+
+ /**
* Gets the thread's thread ID
* @return The thread's ID
*/
@@ -127,6 +129,12 @@ public:
*/
void Stop();
+ /*
+ * Returns the Thread Local Storage address of the current thread
+ * @returns VAddr of the thread's TLS
+ */
+ VAddr GetTLSAddress() const;
+
Core::ThreadContext context;
u32 thread_id;
@@ -135,14 +143,19 @@ public:
u32 entry_point;
u32 stack_top;
- s32 initial_priority;
- s32 current_priority;
+ s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
+ s32 current_priority; ///< Current thread priority, can be temporarily changed
+
+ u64 last_running_ticks; ///< CPU tick when thread was last running
s32 processor_id;
+ s32 tls_index; ///< Index of the Thread Local Storage of the thread
+
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
+ SharedPtr<Process> owner_process; ///< Process that owns this thread
std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
bool wait_all; ///< True if the thread is waiting on all objects before resuming
@@ -150,9 +163,6 @@ public:
std::string name;
- /// Whether this thread is intended to never actually be executed, i.e. always idle
- bool idle = false;
-
private:
Thread();
~Thread() override;
@@ -161,16 +171,13 @@ private:
Handle callback_handle;
};
-extern SharedPtr<Thread> g_main_thread;
-
/**
* Sets up the primary application thread
- * @param stack_size The size of the thread's stack
* @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread
* @return A shared pointer to the main thread
*/
-SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority);
+SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority);
/**
* Reschedules to the next available thread (call after current thread is suspended)
@@ -214,14 +221,6 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
- * Sets up the idle thread, this is a thread that is intended to never execute instructions,
- * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
- * and will try to yield on every call.
- * @return The handle of the idle thread
- */
-SharedPtr<Thread> SetupIdleThread();
-
-/**
* Initialize threading
*/
void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 610e26a3..e69fece6 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -2,7 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
@@ -12,7 +13,7 @@
namespace Kernel {
/// The event type of the generic timer callback event
-static int timer_callback_event_type = -1;
+static int timer_callback_event_type;
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
// us to simply use a pool index or similar.
static Kernel::HandleTable timer_callback_handle_table;
@@ -66,7 +67,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
if (timer == nullptr) {
- LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle);
+ LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08lX", timer_handle);
return;
}
@@ -89,6 +90,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
}
void TimersInit() {
+ timer_callback_handle_table.Clear();
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
}
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 3648a168..ce633d84 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -8,6 +8,7 @@
#include <type_traits>
#include <utility>
+#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp
index b244190a..f9e3fe4b 100644
--- a/src/core/hle/service/am_sys.cpp
+++ b/src/core/hle/service/am_sys.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/am_sys.h"
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 5971f860..09d463dd 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -2,7 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/common_paths.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "core/hle/service/service.h"
#include "core/hle/service/apt/apt.h"
@@ -32,23 +34,31 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
static Kernel::SharedPtr<Kernel::Mutex> lock;
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
-static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event
+static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
+
static std::vector<u8> shared_font;
+static u32 cpu_percent; ///< CPU time available to the running application
+
void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 app_id = cmd_buff[1];
+ u32 flags = cmd_buff[2];
+ cmd_buff[2] = 0x04000000; // According to 3dbrew, this value should be 0x04000000
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
- cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom();
- // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called.
+ // TODO(bunnei): Check if these events are cleared every time Initialize is called.
notification_event->Clear();
- pause_event->Signal(); // Fire start event
+ start_event->Clear();
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
lock->Release();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
}
void GetSharedFont(Service::Interface* self) {
@@ -74,7 +84,7 @@ void NotifyToWait(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
// TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
- pause_event->Signal();
+ start_event->Signal();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
@@ -190,7 +200,38 @@ void CancelParameter(Service::Interface* self) {
cmd_buff[2] = 1; // Set to Success
LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X",
- flag1, unk, flag2, app_id);
+ flag1, unk, flag2, app_id);
+}
+
+void PrepareToStartApplication(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 title_info1 = cmd_buff[1];
+ u32 title_info2 = cmd_buff[2];
+ u32 title_info3 = cmd_buff[3];
+ u32 title_info4 = cmd_buff[4];
+ u32 flags = cmd_buff[5];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
+ "title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags);
+}
+
+void StartApplication(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 buffer1_size = cmd_buff[1];
+ u32 buffer2_size = cmd_buff[2];
+ u32 flag = cmd_buff[3];
+ u32 size1 = cmd_buff[4];
+ u32 buffer1_ptr = cmd_buff[5];
+ u32 size2 = cmd_buff[6];
+ u32 buffer2_ptr = cmd_buff[7];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
+ "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
+ buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
}
void AppletUtility(Service::Interface* self) {
@@ -205,15 +246,15 @@ void AppletUtility(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
- "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
+ LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
+ "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size,
buffer1_addr, buffer2_addr);
}
void SetAppCpuTimeLimit(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 value = cmd_buff[1];
- u32 percent = cmd_buff[2];
+ u32 value = cmd_buff[1];
+ cpu_percent = cmd_buff[2];
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
@@ -221,27 +262,26 @@ void SetAppCpuTimeLimit(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value);
+ LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value);
}
void GetAppCpuTimeLimit(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 value = cmd_buff[1];
+ ASSERT(cpu_percent != 0);
+
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
}
- // TODO(purpasmart96): This is incorrect, I'm pretty sure the percentage should
- // be set by the application.
-
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0x80; // Set to 80%
+ cmd_buff[2] = cpu_percent;
- LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value);
+ LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
}
-void APTInit() {
+void Init() {
AddService(new APT_A_Interface);
AddService(new APT_S_Interface);
AddService(new APT_U_Interface);
@@ -264,21 +304,29 @@ void APTInit() {
file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
// Create shared font memory object
- shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem");
+ using Kernel::MemoryPermission;
+ shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
+ MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
} else {
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
shared_font_mem = nullptr;
}
lock = Kernel::Mutex::Create(false, "APT_U:Lock");
-
+
+ cpu_percent = 0;
+
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
- pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause");
+ start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
}
-void APTShutdown() {
-
+void Shutdown() {
+ shared_font.clear();
+ shared_font_mem = nullptr;
+ lock = nullptr;
+ notification_event = nullptr;
+ start_event = nullptr;
}
} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a39adbff..e7fa3932 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -13,10 +13,13 @@ namespace APT {
/// Signals used by APT functions
enum class SignalType : u32 {
- None = 0x0,
- AppJustStarted = 0x1,
- ReturningToApp = 0xB,
- ExitingApp = 0xC,
+ None = 0x0,
+ AppJustStarted = 0x1,
+ LibAppJustStarted = 0x2,
+ LibAppFinished = 0x3,
+ LibAppClosed = 0xA,
+ ReturningToApp = 0xB,
+ ExitingApp = 0xC,
};
/// App Id's used by APT functions
@@ -179,6 +182,40 @@ void GlanceParameter(Service::Interface* self);
void CancelParameter(Service::Interface* self);
/**
+ * APT::PrepareToStartApplication service function. When the input title-info programID is zero,
+ * NS will load the actual program ID via AMNet:GetTitleIDList. After doing some checks with the
+ * programID, NS will then set a NS state flag to value 1, then set the programID for AppID
+ * 0x300(application) to the input program ID(or the one from GetTitleIDList). A media-type field
+ * in the NS state is also set to the input media-type value
+ * (other state fields are set at this point as well). With 8.0.0-18, NS will set an u8 NS state
+ * field to value 1 when input flags bit8 is set
+ * Inputs:
+ * 1-4 : 0x10-byte title-info struct
+ * 4 : Flags
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void PrepareToStartApplication(Service::Interface* self);
+
+/**
+ * APT::StartApplication service function. Buf0 is copied to NS FIRMparams+0x0, then Buf1 is copied
+ * to the NS FIRMparams+0x480. Then the application is launched.
+ * Inputs:
+ * 1 : Buffer 0 size, max size is 0x300
+ * 2 : Buffer 1 size, max size is 0x20 (this can be zero)
+ * 3 : u8 flag
+ * 4 : (Size0<<14) | 2
+ * 5 : Buffer 0 pointer
+ * 6 : (Size1<<14) | 0x802
+ * 7 : Buffer 1 pointer
+ * Outputs:
+ * 0 : Return Header
+ * 1 : Result of function, 0 on success, otherwise error code
+*/
+void StartApplication(Service::Interface* self);
+
+/**
* APT::AppletUtility service function
* Inputs:
* 1 : Unknown, but clearly used for something
@@ -213,10 +250,10 @@ void SetAppCpuTimeLimit(Service::Interface* self);
void GetAppCpuTimeLimit(Service::Interface* self);
/// Initialize the APT service
-void APTInit();
+void Init();
/// Shutdown the APT service
-void APTShutdown();
+void Shutdown();
} // namespace APT
} // namespace Service
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index dbe5c1d8..86493424 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -12,16 +12,16 @@ namespace APT {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle?"},
{0x00020080, Initialize, "Initialize?"},
- {0x00030040, nullptr, "Enable?"},
+ {0x00030040, Enable, "Enable?"},
{0x00040040, nullptr, "Finalize?"},
{0x00050040, nullptr, "GetAppletManInfo?"},
{0x00060040, nullptr, "GetAppletInfo?"},
{0x000D0080, ReceiveParameter, "ReceiveParameter?"},
{0x000E0080, GlanceParameter, "GlanceParameter?"},
{0x003B0040, nullptr, "CancelLibraryApplet?"},
- {0x00430040, nullptr, "NotifyToWait?"},
+ {0x00430040, NotifyToWait, "NotifyToWait?"},
{0x00440000, GetSharedFont, "GetSharedFont?"},
- {0x004B00C2, nullptr, "AppletUtility?"},
+ {0x004B00C2, AppletUtility, "AppletUtility?"},
{0x00550040, nullptr, "WriteInputToNsState?"},
};
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index 3fd34865..396d1f04 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -3,9 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
-#include "common/file_util.h"
-
#include "core/hle/hle.h"
#include "core/hle/service/apt/apt.h"
#include "core/hle/service/apt/apt_s.h"
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index 5ab23801..d006b593 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
#include "common/file_util.h"
#include "core/hle/service/apt/apt.h"
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 6adadb22..2d26c933 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -4,12 +4,16 @@
#include <algorithm>
-#include "core/hle/service/fs/archive.h"
-#include "core/hle/service/service.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+
+#include "core/file_sys/file_backend.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_i.h"
#include "core/hle/service/cfg/cfg_s.h"
#include "core/hle/service/cfg/cfg_u.h"
+#include "core/hle/service/fs/archive.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace CFG {
@@ -53,12 +57,12 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) {
});
if (itr == std::end(config->block_entries)) {
- LOG_ERROR(Service_CFG, "Config block %u with flags %u was not found", block_id, flag);
+ LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found", block_id, flag, size);
return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
if (itr->size != size) {
- LOG_ERROR(Service_CFG, "Invalid size %u for config block %u with flags %u", size, block_id, flag);
+ LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag);
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
@@ -170,7 +174,7 @@ ResultCode FormatConfig() {
return RESULT_SUCCESS;
}
-void CFGInit() {
+void Init() {
AddService(new CFG_I_Interface);
AddService(new CFG_S_Interface);
AddService(new CFG_U_Interface);
@@ -207,6 +211,7 @@ void CFGInit() {
// Initialize the Username block
// TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals
+ memset(&CONSOLE_USERNAME_BLOCK, 0, sizeof(CONSOLE_USERNAME_BLOCK));
CONSOLE_USERNAME_BLOCK.ng_word = 0;
CONSOLE_USERNAME_BLOCK.zero = 0;
@@ -218,8 +223,7 @@ void CFGInit() {
FormatConfig();
}
-void CFGShutdown() {
-
+void Shutdown() {
}
} // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index e818d7bd..3488c40d 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -135,10 +135,10 @@ ResultCode UpdateConfigNANDSavegame();
ResultCode FormatConfig();
/// Initialize the config service
-void CFGInit();
+void Init();
/// Shutdown the config service
-void CFGShutdown();
+void Shutdown();
} // namespace CFG
} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index c8c1c5b1..221de991 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/string_util.h"
+
#include "core/settings.h"
#include "core/file_sys/archive_systemsavedata.h"
#include "core/hle/hle.h"
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 0b3603ce..fafb43a2 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/dsp_dsp.h"
@@ -11,7 +13,7 @@
namespace DSP_DSP {
-static u32 read_pipe_count = 0;
+static u32 read_pipe_count;
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
static Kernel::SharedPtr<Kernel::Event> interrupt_event;
@@ -40,9 +42,9 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
u32 addr = cmd_buff[1];
cmd_buff[1] = 0; // No error
- cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000);
+ cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
- LOG_WARNING(Service_DSP, "(STUBBED) called with address %u", addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called with address 0x%08X", addr);
}
/**
@@ -60,12 +62,19 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
static void LoadComponent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 size = cmd_buff[1];
+ u32 unk1 = cmd_buff[2];
+ u32 unk2 = cmd_buff[3];
+ u32 new_size = cmd_buff[4];
+ u32 buffer = cmd_buff[5];
+
cmd_buff[1] = 0; // No error
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
// TODO(bunnei): Implement real DSP firmware loading
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X",
+ size, unk1, unk2, new_size, buffer);
}
/**
@@ -84,6 +93,33 @@ static void GetSemaphoreEventHandle(Service::Interface* self) {
}
/**
+ * DSP_DSP::FlushDataCache service function
+ *
+ * This Function is a no-op, We aren't emulating the CPU cache any time soon.
+ *
+ * Inputs:
+ * 1 : Address
+ * 2 : Size
+ * 3 : Value 0, some descriptor for the KProcess Handle
+ * 4 : KProcess handle
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void FlushDataCache(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 address = cmd_buff[1];
+ u32 size = cmd_buff[2];
+ u32 process = cmd_buff[4];
+
+ // TODO(purpasmart96): Verify return header on HW
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X",
+ address, size, process);
+}
+
+/**
* DSP_DSP::RegisterInterruptEvents service function
* Inputs:
* 1 : Parameter 0 (purpose unknown)
@@ -95,6 +131,10 @@ static void GetSemaphoreEventHandle(Service::Interface* self) {
static void RegisterInterruptEvents(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 param0 = cmd_buff[1];
+ u32 param1 = cmd_buff[2];
+ u32 event_handle = cmd_buff[4];
+
auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
if (evt != nullptr) {
interrupt_event = evt;
@@ -106,7 +146,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
cmd_buff[1] = -1;
}
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called param0=%u, param1=%u, event_handle=0x%08X", param0, param1, event_handle);
}
/**
@@ -147,7 +187,7 @@ static void WriteProcessPipe(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%08X, new_size=0x%08X, buffer=0x%08X",
+ LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%X, new_size=0x%X, buffer=0x%08X",
number, size, new_size, buffer);
}
@@ -165,6 +205,8 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
@@ -190,7 +232,8 @@ static void ReadPipeIfPossible(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16);
- LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X",
+ unk1, unk2, size, addr);
}
/**
@@ -225,7 +268,7 @@ static void GetHeadphoneStatus(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Not using headphones?
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_DEBUG(Service_DSP, "(STUBBED) called");
}
const Interface::FunctionInfo FunctionTable[] = {
@@ -242,7 +285,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
{0x001100C2, LoadComponent, "LoadComponent"},
{0x00120000, nullptr, "UnloadComponent"},
- {0x00130082, nullptr, "FlushDataCache"},
+ {0x00130082, FlushDataCache, "FlushDataCache"},
{0x00140082, nullptr, "InvalidateDCache"},
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 58c5acd1..e8c06c1c 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/err_f.h"
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index b0fd834c..6d4a9c7c 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "common/math_util.h"
@@ -78,6 +79,11 @@ enum class DirectoryCommand : u32 {
Close = 0x08020000,
};
+File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path & path)
+ : path(path), priority(0), backend(std::move(backend)) {}
+
+File::~File() {}
+
ResultVal<bool> File::SyncRequest() {
u32* cmd_buff = Kernel::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
@@ -172,6 +178,11 @@ ResultVal<bool> File::SyncRequest() {
return MakeResult<bool>(false);
}
+Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path & path)
+ : path(path), backend(std::move(backend)) {}
+
+Directory::~Directory() {}
+
ResultVal<bool> Directory::SyncRequest() {
u32* cmd_buff = Kernel::GetCommandBuffer();
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index b00f0fd6..faab0cb7 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -45,31 +45,27 @@ typedef u64 ArchiveHandle;
class File : public Kernel::Session {
public:
- File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
- : path(path), priority(0), backend(std::move(backend)) {
- }
+ File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
+ ~File();
std::string GetName() const override { return "Path: " + path.DebugStr(); }
+ ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the file
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
-
- ResultVal<bool> SyncRequest() override;
};
class Directory : public Kernel::Session {
public:
- Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path)
- : path(path), backend(std::move(backend)) {
- }
+ Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
+ ~Directory();
std::string GetName() const override { return "Directory: " + path.DebugStr(); }
+ ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the directory
std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
-
- ResultVal<bool> SyncRequest() override;
};
/**
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index d8d1d554..0d2a426b 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -2,10 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
+
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -20,6 +23,8 @@ using Kernel::Session;
namespace Service {
namespace FS {
+static u32 priority = -1; ///< For SetPriority and GetPriority service functions
+
static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) {
return (u64)low_word | ((u64)high_word << 32);
}
@@ -215,7 +220,7 @@ static void DeleteDirectory(Service::Interface* self) {
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
dirname_type, dirname_size, dir_path.DebugStr().c_str());
-
+
cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
}
@@ -424,7 +429,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw;
// If the SD isn't enabled, it can't be writeable...else, stubbed true
cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
-
+
LOG_DEBUG(Service_FS, " (STUBBED)");
}
@@ -511,7 +516,7 @@ static void CreateExtSaveData(Service::Interface* self) {
MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
u32 save_low = cmd_buff[2];
u32 save_high = cmd_buff[3];
-
+
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
"cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
@@ -573,7 +578,7 @@ static void DeleteSystemSaveData(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 savedata_high = cmd_buff[1];
u32 savedata_low = cmd_buff[2];
-
+
cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw;
}
@@ -601,12 +606,72 @@ static void CreateSystemSaveData(Service::Interface* self) {
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
- "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
+ "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]);
cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw;
}
+/**
+ * FS_User::InitializeWithSdkVersion service function.
+ * Inputs:
+ * 0 : 0x08610042
+ * 1 : Unknown
+ * 2 : Unknown
+ * 3 : Unknown
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void InitializeWithSdkVersion(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[2];
+ u32 unk3 = cmd_buff[3];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X",
+ unk1, unk2, unk3);
+}
+
+/**
+ * FS_User::SetPriority service function.
+ * Inputs:
+ * 0 : 0x08620040
+ * 1 : priority
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void SetPriority(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ priority = cmd_buff[1];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
+}
+
+/**
+ * FS_User::GetPriority service function.
+ * Inputs:
+ * 0 : 0x08630000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : priority
+ */
+static void GetPriority(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ ASSERT(priority != -1);
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = priority;
+
+ LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x000100C6, nullptr, "Dummy1"},
{0x040100C4, nullptr, "Control"},
@@ -695,15 +760,17 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08560240, CreateSystemSaveData, "CreateSystemSaveData"},
{0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"},
{0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
- {0x08610042, nullptr, "InitializeWithSdkVersion"},
- {0x08620040, nullptr, "SetPriority"},
- {0x08630000, nullptr, "GetPriority"},
+ {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"},
+ {0x08620040, SetPriority, "SetPriority"},
+ {0x08630000, GetPriority, "GetPriority"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interface class
Interface::Interface() {
+
+ priority = -1;
Register(FunctionTable);
}
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index cff58569..c11c5fab 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -5,6 +5,7 @@
#include "common/bit_field.h"
#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/result.h"
@@ -30,13 +31,12 @@ namespace GSP_GPU {
Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
/// GSP shared memoryings
Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
-/// Thread index into interrupt relay queue, 1 is arbitrary
-u32 g_thread_id = 1;
+/// Thread index into interrupt relay queue
+u32 g_thread_id = 0;
/// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(u32 thread_id) {
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
- return ptr.ValueOr(nullptr);
+ return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
}
static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
@@ -44,14 +44,14 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in
// For each thread there are two FrameBufferUpdate fields
u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset);
- return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
+ u8* ptr = g_shared_memory->GetPointer(offset);
+ return reinterpret_cast<FrameBufferUpdate*>(ptr);
}
/// Gets a pointer to the interrupt relay queue for a given thread index
static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
- return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
+ u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
+ return reinterpret_cast<InterruptRelayQueue*>(ptr);
}
/**
@@ -204,16 +204,18 @@ static void ReadHWRegs(Service::Interface* self) {
static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
u32 base_address = 0x400000;
+ PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
+ PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
if (info.active_fb == 0) {
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
- &info.address_left);
+ &phys_address_left);
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
- &info.address_right);
+ &phys_address_right);
} else {
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
- &info.address_left);
+ &phys_address_left);
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
- &info.address_right);
+ &phys_address_right);
}
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
&info.stride);
@@ -265,6 +267,9 @@ static void FlushDataCache(Service::Interface* self) {
// TODO(purpasmart96): Verify return header on HW
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X",
+ address, size, process);
}
/**
@@ -273,7 +278,7 @@ static void FlushDataCache(Service::Interface* self) {
* 1 : "Flags" field, purpose is unknown
* 3 : Handle to GSP synchronization event
* Outputs:
- * 0 : Result of function, 0 on success, otherwise error code
+ * 1 : Result of function, 0x2A07 on success, otherwise error code
* 2 : Thread index into GSP command buffer
* 4 : Handle to GSP shared memory
*/
@@ -283,11 +288,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
- g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem");
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
- cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
+ // This specific code is required for a successful initialization, rather than 0
+ cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX,
+ ErrorSummary::Success, ErrorLevel::Success).raw;
cmd_buff[2] = g_thread_id++; // Thread ID
cmd_buff[4] = shmem_handle; // GSP shared memory
@@ -522,8 +528,12 @@ Interface::Interface() {
Register(FunctionTable);
g_interrupt_event = 0;
- g_shared_memory = 0;
- g_thread_id = 1;
+
+ using Kernel::MemoryPermission;
+ g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+ MemoryPermission::ReadWrite, "GSPSharedMem");
+
+ g_thread_id = 0;
}
} // namespace
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 138603d9..9695f7e5 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/service/service.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/hid_spvr.h"
@@ -20,17 +22,17 @@ namespace HID {
static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
// Handle to shared memory region designated to HID_User service
-static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
// Event handles
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
+static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
+static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
+static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
-static u32 next_pad_index = 0;
-static u32 next_touch_index = 0;
+static u32 next_pad_index;
+static u32 next_touch_index;
// TODO(peachum):
// Add a method for setting analog input from joystick device for the circle Pad.
@@ -45,8 +47,8 @@ static u32 next_touch_index = 0;
// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
-void HIDUpdate() {
- SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr));
+void Update() {
+ SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) {
@@ -155,13 +157,15 @@ void GetSoundVolume(Service::Interface* self) {
LOG_WARNING(Service_HID, "(STUBBED) called");
}
-void HIDInit() {
+void Init() {
using namespace Kernel;
AddService(new HID_U_Interface);
AddService(new HID_SPVR_Interface);
- shared_mem = SharedMemory::Create("HID:SharedMem");
+ using Kernel::MemoryPermission;
+ shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+ MemoryPermission::Read, "HID:SharedMem");
next_pad_index = 0;
next_touch_index = 0;
@@ -174,7 +178,13 @@ void HIDInit() {
event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad");
}
-void HIDShutdown() {
+void Shutdown() {
+ shared_mem = nullptr;
+ event_pad_or_touch_1 = nullptr;
+ event_pad_or_touch_2 = nullptr;
+ event_accelerometer = nullptr;
+ event_gyroscope = nullptr;
+ event_debug_pad = nullptr;
}
} // namespace HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 97462c7f..897bd676 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -200,13 +200,13 @@ void EnableGyroscopeLow(Interface* self);
void GetSoundVolume(Interface* self);
/// Checks for user input updates
-void HIDUpdate();
+void Update();
/// Initialize HID service
-void HIDInit();
+void Init();
/// Shutdown HID service
-void HIDShutdown();
+void Shutdown();
}
}
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
new file mode 100644
index 00000000..adfbb258
--- /dev/null
+++ b/src/core/hle/service/ir/ir.cpp
@@ -0,0 +1,52 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_rst.h"
+#include "core/hle/service/ir/ir_u.h"
+#include "core/hle/service/ir/ir_user.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+
+namespace Service {
+namespace IR {
+
+static Kernel::SharedPtr<Kernel::Event> handle_event;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
+
+void GetHandles(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0x4000000;
+ cmd_buff[3] = Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom();
+}
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new IR_RST_Interface);
+ AddService(new IR_U_Interface);
+ AddService(new IR_User_Interface);
+
+ using Kernel::MemoryPermission;
+ shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
+
+ // Create event handle(s)
+ handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent");
+}
+
+void Shutdown() {
+ shared_memory = nullptr;
+ handle_event = nullptr;
+}
+
+} // namespace IR
+
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h
new file mode 100644
index 00000000..c16d963e
--- /dev/null
+++ b/src/core/hle/service/ir/ir.h
@@ -0,0 +1,30 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+/**
+ * IR::GetHandles service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Translate header, used by the ARM11-kernel
+ * 3 : Shared memory handle
+ * 4 : Event handle
+ */
+void GetHandles(Interface* self);
+
+/// Initialize IR service
+void Init();
+
+/// Shutdown IR service
+void Shutdown();
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
new file mode 100644
index 00000000..96ae6342
--- /dev/null
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -0,0 +1,24 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_rst.h"
+
+namespace Service {
+namespace IR {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, GetHandles, "GetHandles"},
+ {0x00020080, nullptr, "Initialize"},
+ {0x00030000, nullptr, "Shutdown"},
+ {0x00090000, nullptr, "WriteToTwoFields"},
+};
+
+IR_RST_Interface::IR_RST_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir/ir_rst.h
index deef701c..a492e15c 100644
--- a/src/core/hle/service/ir_rst.h
+++ b/src/core/hle/service/ir/ir_rst.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_RST
+namespace Service {
+namespace IR {
-namespace IR_RST {
-
-class Interface : public Service::Interface {
+class IR_RST_Interface : public Service::Interface {
public:
- Interface();
+ IR_RST_Interface();
std::string GetPortName() const override {
return "ir:rst";
}
};
-} // namespace
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp
index 608ed3c0..1b1e3078 100644
--- a/src/core/hle/service/ir_u.cpp
+++ b/src/core/hle/service/ir/ir_u.cpp
@@ -3,12 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/ir_u.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_U
-
-namespace IR_U {
+namespace Service {
+namespace IR {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010000, nullptr, "Initialize"},
@@ -31,11 +30,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00120040, nullptr, "SetSleepModeState"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+IR_U_Interface::IR_U_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h
new file mode 100644
index 00000000..056d2ce1
--- /dev/null
+++ b/src/core/hle/service/ir/ir_u.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+class IR_U_Interface : public Service::Interface {
+public:
+ IR_U_Interface();
+
+ std::string GetPortName() const override {
+ return "ir:u";
+ }
+};
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
new file mode 100644
index 00000000..8e3ff140
--- /dev/null
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -0,0 +1,34 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_user.h"
+
+namespace Service {
+namespace IR {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010182, nullptr, "InitializeIrNop"},
+ {0x00020000, nullptr, "FinalizeIrNop"},
+ {0x00030000, nullptr, "ClearReceiveBuffer"},
+ {0x00040000, nullptr, "ClearSendBuffer"},
+ {0x00060040, nullptr, "RequireConnection"},
+ {0x00090000, nullptr, "Disconnect"},
+ {0x000A0000, nullptr, "GetReceiveEvent"},
+ {0x000B0000, nullptr, "GetSendEvent"},
+ {0x000C0000, nullptr, "GetConnectionStatusEvent"},
+ {0x000D0042, nullptr, "SendIrNop"},
+ {0x000E0042, nullptr, "SendIrNopLarge"},
+ {0x00180182, nullptr, "InitializeIrNopShared"},
+ {0x00190040, nullptr, "ReleaseReceivedData"},
+ {0x001A0040, nullptr, "SetOwnMachineId"},
+};
+
+IR_User_Interface::IR_User_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h
new file mode 100644
index 00000000..71c932ff
--- /dev/null
+++ b/src/core/hle/service/ir/ir_user.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+class IR_User_Interface : public Service::Interface {
+public:
+ IR_User_Interface();
+
+ std::string GetPortName() const override {
+ return "ir:USER";
+ }
+};
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp
deleted file mode 100644
index 4c26c2f0..00000000
--- a/src/core/hle/service/ir_rst.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/ir_rst.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_RST
-
-namespace IR_RST {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010000, nullptr, "GetHandles"},
- {0x00020080, nullptr, "Initialize"},
- {0x00030000, nullptr, "Shutdown"},
- {0x00090000, nullptr, "WriteToTwoFields"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp
index c0c4a234..155b97f6 100644
--- a/src/core/hle/service/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/ldr_ro.h"
diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp
new file mode 100644
index 00000000..5f13bd98
--- /dev/null
+++ b/src/core/hle/service/nim_u.cpp
@@ -0,0 +1,48 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/service/nim_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NIM_U
+
+namespace NIM_U {
+
+/**
+ * NIM_U::CheckSysUpdateAvailable service function
+ * Inputs:
+ * 1 : None
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : flag, 0 = no system update available, 1 = system update available.
+ */
+static void CheckSysUpdateAvailable(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0; // No update available
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called");
+}
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "StartSysUpdate"},
+ {0x00020000, nullptr, "GetUpdateDownloadProgress"},
+ {0x00040000, nullptr, "FinishTitlesInstall"},
+ {0x00050000, nullptr, "CheckForSysUpdateEvent"},
+ {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
+ {0x000A0000, nullptr, "GetState"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace
diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/nim_u.h
index ec47a152..57a1f6ac 100644
--- a/src/core/hle/service/ir_u.h
+++ b/src/core/hle/service/nim_u.h
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,16 +7,16 @@
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_U
+// Namespace NIM_U
-namespace IR_U {
+namespace NIM_U {
class Interface : public Service::Interface {
public:
Interface();
std::string GetPortName() const override {
- return "ir:u";
+ return "nim:u";
}
};
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
index 5cf3e203..6b3ef6ec 100644
--- a/src/core/hle/service/ns_s.cpp
+++ b/src/core/hle/service/ns_s.cpp
@@ -3,8 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
-
#include "core/hle/hle.h"
#include "core/hle/service/ns_s.h"
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 88be6c8d..25b01860 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -2,7 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/service/nwm_uds.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -10,21 +13,115 @@
namespace NWM_UDS {
+static Kernel::SharedPtr<Kernel::Event> handle_event;
+
+/**
+ * NWM_UDS::Shutdown service function
+ * Inputs:
+ * 1 : None
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void Shutdown(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // TODO(purpasmart): Verify return header on HW
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called");
+}
+
+/**
+ * NWM_UDS::RecvBeaconBroadcastData service function
+ * Inputs:
+ * 1 : Output buffer max size
+ * 2 : Unknown
+ * 3 : Unknown
+ * 4 : MAC address?
+ * 6-14 : Unknown, usually zero / uninitialized?
+ * 15 : WLan Comm ID
+ * 16 : This is the ID also located at offset 0xE in the CTR-generation structure.
+ * 17 : Value 0
+ * 18 : Input handle
+ * 19 : (Size<<4) | 12
+ * 20 : Output buffer ptr
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void RecvBeaconBroadcastData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 out_buffer_size = cmd_buff[1];
+ u32 unk1 = cmd_buff[2];
+ u32 unk2 = cmd_buff[3];
+ u32 mac_address = cmd_buff[4];
+
+ u32 unk3 = cmd_buff[6];
+
+ u32 wlan_comm_id = cmd_buff[15];
+ u32 ctr_gen_id = cmd_buff[16];
+ u32 value = cmd_buff[17];
+ u32 input_handle = cmd_buff[18];
+ u32 new_buffer_size = cmd_buff[19];
+ u32 out_buffer_ptr = cmd_buff[20];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called out_buffer_size=0x%08X, unk1=0x%08X, unk2=0x%08X,"
+ "mac_address=0x%08X, unk3=0x%08X, wlan_comm_id=0x%08X, ctr_gen_id=0x%08X,"
+ "value=%u, input_handle=0x%08X, new_buffer_size=0x%08X, out_buffer_ptr=0x%08X",
+ out_buffer_size, unk1, unk2, mac_address, unk3, wlan_comm_id, ctr_gen_id, value,
+ input_handle, new_buffer_size, out_buffer_ptr);
+}
+
+/**
+ * NWM_UDS::Initialize service function
+ * Inputs:
+ * 1 : Unknown
+ * 2-11 : Input Structure
+ * 12 : Unknown u16
+ * 13 : Value 0
+ * 14 : Handle
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Value 0
+ * 3 : Output handle
+ */
+static void Initialize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[12];
+ u32 value = cmd_buff[13];
+ u32 handle = cmd_buff[14];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+ cmd_buff[3] = Kernel::g_handle_table.Create(handle_event).MoveFrom(); //TODO(purpasmart): Verify if this is a event handle
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, value=%u, handle=0x%08X",
+ unk1, unk2, value, handle);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
- {0x00030000, nullptr, "Shutdown"},
- {0x000F0404, nullptr, "RecvBeaconBroadcastData"},
- {0x00100042, nullptr, "SetBeaconAdditionalData"},
- {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
- {0x001B0302, nullptr, "Initialize"},
- {0x001D0044, nullptr, "BeginHostingNetwork"},
- {0x001E0084, nullptr, "ConnectToNetwork"},
- {0x001F0006, nullptr, "DecryptBeaconData"},
+ {0x00030000, Shutdown, "Shutdown"},
+ {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"},
+ {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001B0302, Initialize, "Initialize"},
+ {0x001D0044, nullptr, "BeginHostingNetwork"},
+ {0x001E0084, nullptr, "ConnectToNetwork"},
+ {0x001F0006, nullptr, "DecryptBeaconData"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interface class
Interface::Interface() {
+ handle_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "NWM_UDS::handle_event");
+
Register(FunctionTable);
}
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 9043f5aa..82abdff2 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -18,7 +18,7 @@ public:
Interface();
std::string GetPortName() const override {
- return "nwm:UDS";
+ return "nwm::UDS";
}
};
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 56c918d4..2c7d49c9 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -2,12 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/service.h"
+#include "common/logging/log.h"
+
+#include "core/file_sys/file_backend.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_play.h"
#include "core/hle/service/ptm/ptm_sysm.h"
#include "core/hle/service/ptm/ptm_u.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace PTM {
@@ -18,31 +21,70 @@ static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 };
/// Id of the SharedExtData archive used by the PTM process
static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
-static bool shell_open = true;
+static bool shell_open;
-static bool battery_is_charging = true;
+static bool battery_is_charging;
+
+void GetAdapterState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
-u32 GetAdapterState() {
// TODO(purpasmart96): This function is only a stub,
// it returns a valid result without implementing full functionality.
- return battery_is_charging ? 1 : 0;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = battery_is_charging ? 1 : 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-u32 GetShellState() {
- return shell_open ? 1 : 0;
+void GetShellState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = shell_open ? 1 : 0;
+}
+
+void GetBatteryLevel(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // TODO(purpasmart96): This function is only a stub,
+ // it returns a valid result without implementing full functionality.
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-ChargeLevels GetBatteryLevel() {
+void GetBatteryChargeState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
// TODO(purpasmart96): This function is only a stub,
// it returns a valid result without implementing full functionality.
- return ChargeLevels::CompletelyFull; // Set to a completely full battery
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = battery_is_charging ? 1 : 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-void PTMInit() {
+void IsLegacyPowerOff(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
+}
+
+void Init() {
AddService(new PTM_Play_Interface);
AddService(new PTM_Sysm_Interface);
AddService(new PTM_U_Interface);
+ shell_open = true;
+ battery_is_charging = true;
+
// Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist
FileSys::Path archive_path(ptm_shared_extdata_id);
auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
@@ -68,7 +110,7 @@ void PTMInit() {
}
}
-void PTMShutdown() {
+void Shutdown() {
}
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index f697aae4..493e6a11 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include "core/hle/service/service.h"
#include "core/hle/result.h"
namespace Service {
@@ -35,31 +36,54 @@ struct GameCoin {
};
/**
- * Returns whether the battery is charging or not.
* It is unknown if GetAdapterState is the same as GetBatteryChargeState,
* it is likely to just be a duplicate function of GetBatteryChargeState
* that controls another part of the HW.
- * @returns 1 if the battery is charging, and 0 otherwise.
+ * PTM::GetAdapterState service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Output of function, 0 = not charging, 1 = charging.
*/
-u32 GetAdapterState();
+void GetAdapterState(Interface* self);
/**
- * Returns whether the 3DS's physical shell casing is open or closed
- * @returns 1 if the shell is open, and 0 if otherwise
+ * PTM::GetShellState service function.
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
*/
-u32 GetShellState();
+void GetShellState(Interface* self);
/**
- * Get the current battery's charge level.
- * @returns The battery's charge level.
+ * PTM::GetBatteryLevel service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
+ * 3 = half full battery, 2 = low battery, 1 = critical battery.
*/
-ChargeLevels GetBatteryLevel();
+void GetBatteryLevel(Interface* self);
+
+/**
+ * PTM::GetBatteryChargeState service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Output of function, 0 = not charging, 1 = charging.
+ */
+void GetBatteryChargeState(Interface* self);
+
+/**
+ * PTM::IsLegacyPowerOff service function
+ * Outputs:
+ * 1: Result code, 0 on success, otherwise error code
+ * 2: Whether the system is going through a power off
+ */
+void IsLegacyPowerOff(Interface* self);
/// Initialize the PTM service
-void PTMInit();
+void Init();
/// Shutdown the PTM service
-void PTMShutdown();
+void Shutdown();
} // namespace PTM
} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 8e8ae855..48e68a3d 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -9,10 +9,10 @@ namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
- { 0x08070082, nullptr, "GetPlayHistory" },
- { 0x08080000, nullptr, "GetPlayHistoryStart" },
- { 0x08090000, nullptr, "GetPlayHistoryLength" },
- { 0x080B0080, nullptr, "CalcPlayHistoryStart" },
+ {0x08070082, nullptr, "GetPlayHistory"},
+ {0x08080000, nullptr, "GetPlayHistoryStart"},
+ {0x08090000, nullptr, "GetPlayHistoryLength"},
+ {0x080B0080, nullptr, "CalcPlayHistoryStart"},
};
PTM_Play_Interface::PTM_Play_Interface() {
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 2d841f69..655658f3 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -2,57 +2,44 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/make_unique.h"
-#include "core/file_sys/archive_extsavedata.h"
#include "core/hle/hle.h"
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_sysm.h"
namespace Service {
namespace PTM {
-/**
- * Returns whether the system is powering off (?)
- * Outputs:
- * 1: Result code, 0 on success, otherwise error code
- * 2: Whether the system is going through a power off
- */
-void IsLegacyPowerOff(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
-}
-
const Interface::FunctionInfo FunctionTable[] = {
- {0x040100C0, nullptr, "SetRtcAlarmEx"},
- {0x04020042, nullptr, "ReplySleepQuery"},
- {0x04030042, nullptr, "NotifySleepPreparationComplete"},
- {0x04040102, nullptr, "SetWakeupTrigger"},
- {0x04050000, nullptr, "GetAwakeReason"},
- {0x04060000, nullptr, "RequestSleep"},
- {0x040700C0, nullptr, "ShutdownAsync"},
- {0x04080000, nullptr, "Awake"},
- {0x04090080, nullptr, "RebootAsync"},
- {0x040A0000, nullptr, "CheckNew3DS"},
- {0x08010640, nullptr, "SetInfoLEDPattern"},
- {0x08020040, nullptr, "SetInfoLEDPatternHeader"},
- {0x08030000, nullptr, "GetInfoLEDStatus"},
- {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"},
- {0x08050000, nullptr, "ClearStepHistory"},
- {0x080600C2, nullptr, "SetStepHistory"},
- {0x08070082, nullptr, "GetPlayHistory"},
- {0x08080000, nullptr, "GetPlayHistoryStart"},
- {0x08090000, nullptr, "GetPlayHistoryLength"},
- {0x080A0000, nullptr, "ClearPlayHistory"},
- {0x080B0080, nullptr, "CalcPlayHistoryStart"},
- {0x080C0080, nullptr, "SetUserTime"},
- {0x080D0000, nullptr, "InvalidateSystemTime"},
- {0x080E0140, nullptr, "NotifyPlayEvent"},
- {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
- {0x08100000, nullptr, "ClearLegacyPowerOff"},
- {0x08110000, nullptr, "GetShellStatus"},
- {0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
- {0x08130000, nullptr, "FormatSavedata"},
- {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}
+ {0x040100C0, nullptr, "SetRtcAlarmEx"},
+ {0x04020042, nullptr, "ReplySleepQuery"},
+ {0x04030042, nullptr, "NotifySleepPreparationComplete"},
+ {0x04040102, nullptr, "SetWakeupTrigger"},
+ {0x04050000, nullptr, "GetAwakeReason"},
+ {0x04060000, nullptr, "RequestSleep"},
+ {0x040700C0, nullptr, "ShutdownAsync"},
+ {0x04080000, nullptr, "Awake"},
+ {0x04090080, nullptr, "RebootAsync"},
+ {0x040A0000, nullptr, "CheckNew3DS"},
+ {0x08010640, nullptr, "SetInfoLEDPattern"},
+ {0x08020040, nullptr, "SetInfoLEDPatternHeader"},
+ {0x08030000, nullptr, "GetInfoLEDStatus"},
+ {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"},
+ {0x08050000, nullptr, "ClearStepHistory"},
+ {0x080600C2, nullptr, "SetStepHistory"},
+ {0x08070082, nullptr, "GetPlayHistory"},
+ {0x08080000, nullptr, "GetPlayHistoryStart"},
+ {0x08090000, nullptr, "GetPlayHistoryLength"},
+ {0x080A0000, nullptr, "ClearPlayHistory"},
+ {0x080B0080, nullptr, "CalcPlayHistoryStart"},
+ {0x080C0080, nullptr, "SetUserTime"},
+ {0x080D0000, nullptr, "InvalidateSystemTime"},
+ {0x080E0140, nullptr, "NotifyPlayEvent"},
+ {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
+ {0x08100000, nullptr, "ClearLegacyPowerOff"},
+ {0x08110000, nullptr, "GetShellStatus"},
+ {0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
+ {0x08130000, nullptr, "FormatSavedata"},
+ {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}
};
PTM_Sysm_Interface::PTM_Sysm_Interface() {
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 0af7c8bf..3f5e9c7c 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/make_unique.h"
+#include "common/logging/log.h"
#include "core/hle/hle.h"
#include "core/hle/service/ptm/ptm.h"
@@ -11,68 +11,6 @@
namespace Service {
namespace PTM {
-/**
- * PTM_U::GetAdapterState service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output of function, 0 = not charging, 1 = charging.
- */
-static void GetAdapterState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetAdapterState();
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
-/*
- * PTM_User::GetShellState service function.
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
- */
-static void GetShellState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetShellState();
-}
-
-/**
- * PTM_U::GetBatteryLevel service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
- * 3 = half full battery, 2 = low battery, 1 = critical battery.
- */
-static void GetBatteryLevel(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = static_cast<u32>(GetBatteryLevel());
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
-/**
- * PTM_U::GetBatteryChargeState service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output of function, 0 = not charging, 1 = charging.
- */
-static void GetBatteryChargeState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- // TODO(purpasmart96): This function is only a stub,
- // it returns a valid result without implementing full functionality.
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetAdapterState();
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, nullptr, "RegisterAlarmClient"},
{0x00020080, nullptr, "SetRtcAlarm"},
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 91f13cd7..64185c62 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/hle/service/service.h"
@@ -24,14 +24,13 @@
#include "core/hle/service/gsp_gpu.h"
#include "core/hle/service/gsp_lcd.h"
#include "core/hle/service/http_c.h"
-#include "core/hle/service/ir_rst.h"
-#include "core/hle/service/ir_u.h"
#include "core/hle/service/ldr_ro.h"
#include "core/hle/service/mic_u.h"
#include "core/hle/service/ndm_u.h"
#include "core/hle/service/news_s.h"
#include "core/hle/service/news_u.h"
#include "core/hle/service/nim_aoc.h"
+#include "core/hle/service/nim_u.h"
#include "core/hle/service/ns_s.h"
#include "core/hle/service/nwm_uds.h"
#include "core/hle/service/pm_app.h"
@@ -44,6 +43,7 @@
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ptm/ptm.h"
namespace Service {
@@ -51,6 +51,49 @@ namespace Service {
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+/**
+ * Creates a function string for logging, complete with the name (or header code, depending
+ * on what's passed in) the port name, and all the cmd_buff arguments.
+ */
+static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
+ // Number of params == bits 0-5 + bits 6-11
+ int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
+
+ std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
+ for (int i = 1; i <= num_params; ++i) {
+ function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
+ }
+ return function_string;
+}
+
+ResultVal<bool> Interface::SyncRequest() {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ auto itr = m_functions.find(cmd_buff[0]);
+
+ if (itr == m_functions.end() || itr->second.func == nullptr) {
+ std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
+ LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
+
+ // TODO(bunnei): Hack - ignore error
+ cmd_buff[1] = 0;
+ return MakeResult<bool>(false);
+ } else {
+ LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
+ }
+
+ itr->second.func(this);
+
+ return MakeResult<bool>(false); // TODO: Implement return from actual function
+}
+
+void Interface::Register(const FunctionInfo* functions, size_t n) {
+ m_functions.reserve(n);
+ for (size_t i = 0; i < n; ++i) {
+ // Usually this array is sorted by id already, so hint to instead at the end
+ m_functions.emplace_hint(m_functions.cend(), functions[i].id, functions[i]);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module interface
@@ -68,10 +111,11 @@ void Init() {
AddNamedPort(new ERR_F::Interface);
Service::FS::ArchiveInit();
- Service::CFG::CFGInit();
- Service::APT::APTInit();
- Service::PTM::PTMInit();
- Service::HID::HIDInit();
+ Service::CFG::Init();
+ Service::APT::Init();
+ Service::PTM::Init();
+ Service::HID::Init();
+ Service::IR::Init();
AddService(new AC_U::Interface);
AddService(new ACT_U::Interface);
@@ -90,14 +134,13 @@ void Init() {
AddService(new GSP_GPU::Interface);
AddService(new GSP_LCD::Interface);
AddService(new HTTP_C::Interface);
- AddService(new IR_RST::Interface);
- AddService(new IR_U::Interface);
AddService(new LDR_RO::Interface);
AddService(new MIC_U::Interface);
AddService(new NDM_U::Interface);
AddService(new NEWS_S::Interface);
AddService(new NEWS_U::Interface);
AddService(new NIM_AOC::Interface);
+ AddService(new NIM_U::Interface);
AddService(new NS_S::Interface);
AddService(new NWM_UDS::Interface);
AddService(new PM_APP::Interface);
@@ -110,10 +153,11 @@ void Init() {
/// Shutdown ServiceManager
void Shutdown() {
- Service::HID::HIDShutdown();
- Service::PTM::PTMShutdown();
- Service::APT::APTShutdown();
- Service::CFG::CFGShutdown();
+ Service::IR::Shutdown();
+ Service::HID::Shutdown();
+ Service::PTM::Shutdown();
+ Service::APT::Shutdown();
+ Service::CFG::Shutdown();
Service::FS::ArchiveShutdown();
g_srv_services.clear();
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index bfe16eba..77bfb9ff 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,20 +4,15 @@
#pragma once
-#include <algorithm>
#include <string>
#include <unordered_map>
-#include <vector>
#include <boost/container/flat_map.hpp>
-#include "common/common.h"
-#include "common/string_util.h"
-#include "core/mem_map.h"
+#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
-#include "core/hle/svc.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -26,31 +21,11 @@ namespace Service {
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
-class Manager;
-
/// Interface to a CTROS service
class Interface : public Kernel::Session {
// TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
// just something that encapsulates a session and acts as a helper to implement service
// processes.
-
- friend class Manager;
-
- /**
- * Creates a function string for logging, complete with the name (or header code, depending
- * on what's passed in) the port name, and all the cmd_buff arguments.
- */
- std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
- // Number of params == bits 0-5 + bits 6-11
- int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
-
- std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
- for (int i = 1; i <= num_params; ++i) {
- function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
- }
- return function_string;
- }
-
public:
std::string GetName() const override { return GetPortName(); }
@@ -70,25 +45,7 @@ public:
return "[UNKNOWN SERVICE PORT]";
}
- ResultVal<bool> SyncRequest() override {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- auto itr = m_functions.find(cmd_buff[0]);
-
- if (itr == m_functions.end() || itr->second.func == nullptr) {
- std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
- LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
-
- // TODO(bunnei): Hack - ignore error
- cmd_buff[1] = 0;
- return MakeResult<bool>(false);
- } else {
- LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
- }
-
- itr->second.func(this);
-
- return MakeResult<bool>(false); // TODO: Implement return from actual function
- }
+ ResultVal<bool> SyncRequest() override;
protected:
@@ -96,14 +53,12 @@ protected:
* Registers the functions in the service
*/
template <size_t N>
- void Register(const FunctionInfo (&functions)[N]) {
- m_functions.reserve(N);
- for (auto& fn : functions) {
- // Usually this array is sorted by id already, so hint to instead at the end
- m_functions.emplace_hint(m_functions.cend(), fn.id, fn);
- }
+ inline void Register(const FunctionInfo (&functions)[N]) {
+ Register(functions, N);
}
+ void Register(const FunctionInfo* functions, size_t n);
+
private:
boost::container::flat_map<u32, FunctionInfo> m_functions;
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 231ead18..39b8d65f 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
#include "common/platform.h"
#if EMU_PLATFORM == PLATFORM_WINDOWS
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index cc59a03c..6c49fa6c 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/srv.h"
#include "core/hle/kernel/event.h"
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 6607965e..085192a0 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/y2r_u.h"
@@ -11,7 +13,7 @@
namespace Y2R_U {
-static Kernel::SharedPtr<Kernel::Event> completion_event = 0;
+static Kernel::SharedPtr<Kernel::Event> completion_event;
/**
* Y2R_U::IsBusyConversion service function
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 568dad68..4014eee9 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -2,11 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/common_types.h"
#include "common/common_funcs.h"
#include "core/core.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
@@ -14,61 +16,15 @@
namespace SharedPage {
-// see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes
-
-#pragma pack(1)
-struct DateTime {
- u64 date_time; // 0x0
- u64 update_tick; // 0x8
- INSERT_PADDING_BYTES(0x20 - 0x10); // 0x10
-};
-
-struct SharedPageDef {
- // most of these names are taken from the 3dbrew page linked above.
- u32 date_time_selector; // 0x0
- u8 running_hw; // 0x4
- u8 mcu_hw_info; // 0x5: don't know what the acronyms mean
- INSERT_PADDING_BYTES(0x20 - 0x6); // 0x6
- DateTime date_time_0; // 0x20
- DateTime date_time_1; // 0x40
- u8 wifi_macaddr[6]; // 0x60
- u8 wifi_unknown1; // 0x66: 3dbrew says these are "Likely wifi hardware related"
- u8 wifi_unknown2; // 0x67
- INSERT_PADDING_BYTES(0x80 - 0x68); // 0x68
- float sliderstate_3d; // 0x80
- u8 ledstate_3d; // 0x84
- INSERT_PADDING_BYTES(0xA0 - 0x85); // 0x85
- u64 menu_title_id; // 0xA0
- u64 active_menu_title_id; // 0xA8
- INSERT_PADDING_BYTES(0x1000 - 0xB0); // 0xB0
-};
-#pragma pack()
+SharedPageDef shared_page;
-static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
-static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong");
-
-static SharedPageDef shared_page;
-
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- u32 offset = addr - Memory::SHARED_PAGE_VADDR;
- var = *(reinterpret_cast<T*>(((uintptr_t)&shared_page) + offset));
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-template void Read<u64>(u64 &var, const u32 addr);
-template void Read<u32>(u32 &var, const u32 addr);
-template void Read<u16>(u16 &var, const u32 addr);
-template void Read<u8>(u8 &var, const u32 addr);
+void Init() {
+ std::memset(&shared_page, 0, sizeof(shared_page));
-void Set3DSlider(float amount) {
- shared_page.sliderstate_3d = amount;
- shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero
+ shared_page.running_hw = 0x1; // product
}
-void Init() {
- shared_page.running_hw = 0x1; // product
- Set3DSlider(0.0f);
+void Shutdown() {
}
} // namespace
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index 8f93545e..fd2ab66a 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -11,16 +11,46 @@
*/
#include "common/common_types.h"
+#include "common/swap.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace SharedPage {
-template <typename T>
-void Read(T &var, const u32 addr);
-
-void Set3DSlider(float amount);
+// See http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes
+
+struct DateTime {
+ u64_le date_time; // 0
+ u64_le update_tick; // 8
+ INSERT_PADDING_BYTES(0x20 - 0x10); // 10
+};
+static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
+
+struct SharedPageDef {
+ // Most of these names are taken from the 3dbrew page linked above.
+ u32_le date_time_selector; // 0
+ u8 running_hw; // 4
+ /// "Microcontroller hardware info"
+ u8 mcu_hw_info; // 5
+ INSERT_PADDING_BYTES(0x20 - 0x6); // 6
+ DateTime date_time_0; // 20
+ DateTime date_time_1; // 40
+ u8 wifi_macaddr[6]; // 60
+ u8 wifi_unknown1; // 66
+ u8 wifi_unknown2; // 67
+ INSERT_PADDING_BYTES(0x80 - 0x68); // 68
+ float_le sliderstate_3d; // 80
+ u8 ledstate_3d; // 84
+ INSERT_PADDING_BYTES(0xA0 - 0x85); // 85
+ u64_le menu_title_id; // A0
+ u64_le active_menu_title_id; // A8
+ INSERT_PADDING_BYTES(0x1000 - 0xB0); // B0
+};
+static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong");
+
+extern SharedPageDef shared_page;
void Init();
+void Shutdown();
} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index bbb4eb9c..9bf88625 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -4,6 +4,8 @@
#include <map>
+#include "common/logging/log.h"
+#include "common/profiler.h"
#include "common/string_util.h"
#include "common/symbols.h"
@@ -14,6 +16,7 @@
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
@@ -283,8 +286,13 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val
if (arbiter == nullptr)
return ERR_INVALID_HANDLE;
- return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type),
- address, value, nanoseconds);
+ auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type),
+ address, value, nanoseconds);
+
+ if (res == RESULT_SUCCESS)
+ HLE::Reschedule(__func__);
+
+ return res;
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
@@ -305,14 +313,14 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) {
/// Get resource limit current values
static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
s32 name_count) {
- LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
+ LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%p, name_count=%d",
resource_limit, names, name_count);
- Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
+ values[0] = 0; // Normmatt: Set used memory to 0 for now
return RESULT_SUCCESS;
}
/// Creates a new thread
-static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
+static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
using Kernel::Thread;
std::string name;
@@ -323,6 +331,27 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u
name = Common::StringFromFormat("unknown-%08x", entry_point);
}
+ // TODO(bunnei): Implement resource limits to return an error code instead of the below assert.
+ // The error code should be: Description::NotAuthorized, Module::OS, Summary::WrongArgument,
+ // Level::Permanent
+ ASSERT_MSG(priority >= THREADPRIO_USERLAND_MAX, "Unexpected thread priority!");
+
+ if (priority > THREADPRIO_LOWEST) {
+ return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }
+
+ switch (processor_id) {
+ case THREADPROCESSORID_DEFAULT:
+ case THREADPROCESSORID_0:
+ case THREADPROCESSORID_1:
+ break;
+ default:
+ // TODO(bunnei): Implement support for other processor IDs
+ ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
+ break;
+ }
+
CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(
name, entry_point, priority, arg, processor_id, stack_top));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread)));
@@ -331,10 +360,7 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u
"threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
name.c_str(), arg, stack_top, priority, processor_id, *out_handle);
- if (THREADPROCESSORID_1 == processor_id) {
- LOG_WARNING(Kernel_SVC,
- "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling");
- }
+ HLE::Reschedule(__func__);
return RESULT_SUCCESS;
}
@@ -374,8 +400,11 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
+ HLE::Reschedule(__func__);
+
LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
initial_locked ? "true" : "false", *out_handle);
+
return RESULT_SUCCESS;
}
@@ -390,6 +419,37 @@ static ResultCode ReleaseMutex(Handle handle) {
return ERR_INVALID_HANDLE;
mutex->Release();
+
+ HLE::Reschedule(__func__);
+
+ return RESULT_SUCCESS;
+}
+
+/// Get the ID of the specified process
+static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
+ LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
+
+ const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
+ if (process == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ *process_id = process->process_id;
+ return RESULT_SUCCESS;
+}
+
+/// Get the ID of the process that owns the specified thread
+static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
+ LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
+
+ const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
+ if (thread == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ const SharedPtr<Kernel::Process> process = thread->owner_process;
+
+ ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
+
+ *process_id = process->process_id;
return RESULT_SUCCESS;
}
@@ -428,6 +488,9 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
return ERR_INVALID_HANDLE;
CASCADE_RESULT(*count, semaphore->Release(release_count));
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -520,6 +583,9 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
return ERR_INVALID_HANDLE;
timer->Set(initial, interval);
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -534,6 +600,9 @@ static ResultCode CancelTimer(Handle handle) {
return ERR_INVALID_HANDLE;
timer->Cancel();
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -561,14 +630,26 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
using Kernel::SharedMemory;
// TODO(Subv): Implement this function
- SharedPtr<SharedMemory> shared_memory = SharedMemory::Create();
+ using Kernel::MemoryPermission;
+ SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
+ (MemoryPermission)my_permission, (MemoryPermission)other_permission);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
return RESULT_SUCCESS;
}
-const HLE::FunctionDef SVC_Table[] = {
+namespace {
+ struct FunctionDef {
+ using Func = void();
+
+ u32 id;
+ Func* func;
+ const char* name;
+ };
+}
+
+static const FunctionDef SVC_Table[] = {
{0x00, nullptr, "Unknown"},
{0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
{0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
@@ -622,8 +703,8 @@ const HLE::FunctionDef SVC_Table[] = {
{0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
{0x33, nullptr, "OpenProcess"},
{0x34, nullptr, "OpenThread"},
- {0x35, nullptr, "GetProcessId"},
- {0x36, nullptr, "GetProcessIdOfThread"},
+ {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"},
+ {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"},
{0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
{0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
{0x39, nullptr, "GetResourceLimitLimitValues"},
@@ -697,8 +778,28 @@ const HLE::FunctionDef SVC_Table[] = {
{0x7D, nullptr, "QueryProcessMemory"},
};
-void Register() {
- HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
+Common::Profiling::TimingCategory profiler_svc("SVC Calls");
+
+static const FunctionDef* GetSVCInfo(u32 opcode) {
+ u32 func_num = opcode & 0xFFFFFF; // 8 bits
+ if (func_num >= ARRAY_SIZE(SVC_Table)) {
+ LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
+ return nullptr;
+ }
+ return &SVC_Table[func_num];
+}
+
+void CallSVC(u32 opcode) {
+ Common::Profiling::ScopeTimer timer_svc(profiler_svc);
+
+ const FunctionDef *info = GetSVCInfo(opcode);
+ if (info) {
+ if (info->func) {
+ info->func();
+ } else {
+ LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
+ }
+ }
}
} // namespace
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 5d020a5b..4389aa73 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
namespace SVC {
-void Register();
+void CallSVC(u32 opcode);
} // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index e6983a22..8ef1f70d 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -8,7 +8,7 @@
#include "core/settings.h"
#include "core/core.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/core_timing.h"
#include "core/hle/hle.h"
@@ -29,8 +29,7 @@ namespace GPU {
Regs g_regs;
/// True if the current frame was skipped
-bool g_skip_frame = false;
-
+bool g_skip_frame;
/// 268MHz / gpu_refresh_rate frames per second
static u64 frame_ticks;
/// Event id for CoreTiming
@@ -38,7 +37,7 @@ static int vblank_event;
/// Total number of frames drawn
static u64 frame_count;
/// True if the last frame was skipped
-static bool last_skip_frame = false;
+static bool last_skip_frame;
template <typename T>
inline void Read(T &var, const u32 raw_addr) {
@@ -77,8 +76,8 @@ inline void Write(u32 addr, const T data) {
auto& config = g_regs.memory_fill_config[is_second_filler];
if (config.address_start && config.trigger) {
- u8* start = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress()));
- u8* end = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress()));
+ u8* start = Memory::GetPhysicalPointer(config.GetStartAddress());
+ u8* end = Memory::GetPhysicalPointer(config.GetEndAddress());
if (config.fill_24bit) {
// fill with 24-bit values
@@ -115,8 +114,8 @@ inline void Write(u32 addr, const T data) {
{
const auto& config = g_regs.display_transfer_config;
if (config.trigger & 1) {
- u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
- u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
+ u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress());
+ u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress());
if (config.scaling > config.ScaleXY) {
LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value());
@@ -136,7 +135,7 @@ inline void Write(u32 addr, const T data) {
memcpy(dst_pointer, src_pointer, config.output_width * config.output_height *
GPU::Regs::BytesPerPixel(config.output_format));
- LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy",
+ LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy",
config.output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format),
config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
config.GetPhysicalOutputAddress(), config.output_width.Value(), config.output_height.Value(),
@@ -258,7 +257,7 @@ inline void Write(u32 addr, const T data) {
const auto& config = g_regs.command_processor_config;
if (config.trigger & 1)
{
- u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress()));
+ u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
}
break;
@@ -312,7 +311,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
DSP_DSP::SignalInterrupt();
// Check for user input updates
- Service::HID::HIDUpdate();
+ Service::HID::Update();
// Reschedule recurrent event
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event);
@@ -320,6 +319,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
/// Initialize hardware
void Init() {
+ memset(&g_regs, 0, sizeof(g_regs));
+
auto& framebuffer_top = g_regs.framebuffer_config[0];
auto& framebuffer_sub = g_regs.framebuffer_config[1];
@@ -349,6 +350,7 @@ void Init() {
frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
last_skip_frame = false;
g_skip_frame = false;
+ frame_count = 0;
vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback);
CoreTiming::ScheduleEvent(frame_ticks, vblank_event);
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index c8f88449..699bcd2a 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -6,8 +6,10 @@
#include <cstddef>
-#include "common/common_types.h"
+#include "common/assert.h"
#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
namespace GPU {
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index bed50af5..f4906cc7 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "core/hw/hw.h"
#include "core/hw/gpu.h"
@@ -63,6 +64,8 @@ void Init() {
/// Shutdown hardware
void Shutdown() {
+ GPU::Shutdown();
+ LCD::Shutdown();
LOG_DEBUG(HW, "shutdown OK");
}
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 7986f3dd..09134c95 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -2,7 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/hle/hle.h"
@@ -55,6 +58,7 @@ template void Write<u8>(u32 addr, const u8 data);
/// Initialize hardware
void Init() {
+ memset(&g_regs, 0, sizeof(g_regs));
LOG_DEBUG(HW_LCD, "initialized OK");
}
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index 43893a62..fb14c3b2 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -6,8 +6,9 @@
#include <cstddef>
-#include "common/common_types.h"
#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
#define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32))
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 958dd03e..84b13ee5 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -5,11 +5,14 @@
#include <algorithm>
#include <vector>
+#include "common/logging/log.h"
+
#include "core/file_sys/archive_romfs.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/fs/archive.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
-#include "core/hle/service/fs/archive.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "3dsx.h"
@@ -227,8 +230,13 @@ ResultStatus AppLoader_THREEDSX::Load() {
if (!file->IsOpen())
return ResultStatus::Error;
- Load3DSXFile(*file, 0x00100000);
- Kernel::LoadExec(0x00100000);
+ Kernel::g_current_process = Kernel::Process::Create(filename, 0);
+ Kernel::g_current_process->svc_access_mask.set();
+ Kernel::g_current_process->address_mappings = default_address_mappings;
+
+ Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR);
+
+ Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index a1166740..096b3ec2 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -4,6 +4,8 @@
#pragma once
+#include <string>
+
#include "common/common_types.h"
#include "core/loader/loader.h"
@@ -15,7 +17,8 @@ namespace Loader {
/// Loads an 3DSX file
class AppLoader_THREEDSX final : public AppLoader {
public:
- AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
+ AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename)
+ : AppLoader(std::move(file)), filename(std::move(filename)) {}
/**
* Returns the type of the file
@@ -29,6 +32,9 @@ public:
* @return ResultStatus result of function
*/
ResultStatus Load() override;
+
+private:
+ std::string filename;
};
} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 773eaf77..a951bc80 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -5,13 +5,14 @@
#include <string>
#include <memory>
-#include "common/common.h"
+#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/symbols.h"
-#include "core/mem_map.h"
-#include "core/loader/elf.h"
#include "core/hle/kernel/kernel.h"
+#include "core/loader/elf.h"
+#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// ELF Header Constants
@@ -349,9 +350,15 @@ ResultStatus AppLoader_ELF::Load() {
if (file->ReadBytes(&buffer[0], size) != size)
return ResultStatus::Error;
+ Kernel::g_current_process = Kernel::Process::Create(filename, 0);
+ Kernel::g_current_process->svc_access_mask.set();
+ Kernel::g_current_process->address_mappings = default_address_mappings;
+
ElfReader elf_reader(&buffer[0]);
- elf_reader.LoadInto(0x00100000);
- Kernel::LoadExec(elf_reader.GetEntryPoint());
+ elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
+ // TODO: Fill application title
+
+ Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index b6e6651f..32841606 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -4,6 +4,8 @@
#pragma once
+#include <string>
+
#include "common/common_types.h"
#include "core/loader/loader.h"
@@ -15,7 +17,8 @@ namespace Loader {
/// Loads an ELF/AXF file
class AppLoader_ELF final : public AppLoader {
public:
- AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
+ AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename)
+ : AppLoader(std::move(file)), filename(std::move(filename)) { }
/**
* Returns the type of the file
@@ -29,6 +32,9 @@ public:
* @return ResultStatus result of function
*/
ResultStatus Load() override;
+
+private:
+ std::string filename;
};
} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index aca09b37..8b14edf0 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -4,19 +4,26 @@
#include <string>
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_romfs.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/fs/archive.h"
#include "core/loader/3dsx.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
-#include "core/hle/service/fs/archive.h"
-#include "core/mem_map.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Loader {
+const std::initializer_list<Kernel::AddressMapping> default_address_mappings = {
+ { 0x1FF50000, 0x8000, true }, // part of DSP RAM
+ { 0x1FF70000, 0x8000, true }, // part of DSP RAM
+ { 0x1F000000, 0x600000, false }, // entire VRAM
+};
+
/**
* Identifies the type of a bootable file
* @param file open file
@@ -41,19 +48,11 @@ static FileType IdentifyFile(FileUtil::IOFile& file) {
/**
* Guess the type of a bootable file from its extension
- * @param filename String filename of bootable file
+ * @param extension String extension of bootable file
* @return FileType of file
*/
-static FileType GuessFromFilename(const std::string& filename) {
- if (filename.size() == 0) {
- LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
- return FileType::Error;
- }
-
- size_t extension_loc = filename.find_last_of('.');
- if (extension_loc == std::string::npos)
- return FileType::Unknown;
- std::string extension = Common::ToLower(filename.substr(extension_loc));
+static FileType GuessFromExtension(const std::string& extension_) {
+ std::string extension = Common::ToLower(extension_);
if (extension == ".elf")
return FileType::ELF;
@@ -63,8 +62,6 @@ static FileType GuessFromFilename(const std::string& filename) {
return FileType::CXI;
else if (extension == ".cci")
return FileType::CCI;
- else if (extension == ".bin")
- return FileType::BIN;
else if (extension == ".3ds")
return FileType::CCI;
else if (extension == ".3dsx")
@@ -82,8 +79,6 @@ static const char* GetFileTypeString(FileType type) {
return "ELF";
case FileType::THREEDSX:
return "3DSX";
- case FileType::BIN:
- return "raw";
case FileType::Error:
case FileType::Unknown:
break;
@@ -99,8 +94,11 @@ ResultStatus LoadFile(const std::string& filename) {
return ResultStatus::Error;
}
+ std::string filename_filename, filename_extension;
+ Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension);
+
FileType type = IdentifyFile(*file);
- FileType filename_type = GuessFromFilename(filename);
+ FileType filename_type = GuessFromExtension(filename_extension);
if (type != filename_type) {
LOG_WARNING(Loader, "File %s has a different type than its extension.", filename.c_str());
@@ -114,11 +112,11 @@ ResultStatus LoadFile(const std::string& filename) {
//3DSX file format...
case FileType::THREEDSX:
- return AppLoader_THREEDSX(std::move(file)).Load();
+ return AppLoader_THREEDSX(std::move(file), filename_filename).Load();
// Standard ELF file format...
case FileType::ELF:
- return AppLoader_ELF(std::move(file)).Load();
+ return AppLoader_ELF(std::move(file), filename_filename).Load();
// NCCH/NCSD container formats...
case FileType::CXI:
@@ -128,24 +126,12 @@ ResultStatus LoadFile(const std::string& filename) {
// Load application and RomFS
if (ResultStatus::Success == app_loader.Load()) {
- Kernel::g_program_id = app_loader.GetProgramId();
Service::FS::RegisterArchiveType(Common::make_unique<FileSys::ArchiveFactory_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
return ResultStatus::Success;
}
break;
}
- // Raw BIN file format...
- case FileType::BIN:
- {
- size_t size = (size_t)file->GetSize();
- if (file->ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), size) != size)
- return ResultStatus::Error;
-
- Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
- return ResultStatus::Success;
- }
-
// Error occurred durring IdentifyFile...
case FileType::Error:
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 3510c6b2..87e16fb9 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -6,9 +6,11 @@
#include <vector>
-#include "common/common.h"
+#include "common/common_types.h"
#include "common/file_util.h"
+#include "core/hle/kernel/process.h"
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace
@@ -22,7 +24,6 @@ enum class FileType {
CXI,
CIA,
ELF,
- BIN,
THREEDSX, //3DSX
};
@@ -105,6 +106,12 @@ protected:
};
/**
+ * Common address mappings found in most games, used for binary formats that don't have this
+ * information.
+ */
+extern const std::initializer_list<Kernel::AddressMapping> default_address_mappings;
+
+/**
* Identifies and loads a bootable file
* @param filename String filename of bootable file
* @return ResultStatus result of function
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index aaaa4d65..36e341fd 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -2,11 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <memory>
-#include "core/loader/ncch.h"
+#include "common/logging/log.h"
+#include "common/make_unique.h"
+#include "common/string_util.h"
+#include "common/swap.h"
+
#include "core/hle/kernel/kernel.h"
-#include "core/mem_map.h"
+#include "core/loader/ncch.h"
+#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace
@@ -115,8 +121,21 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
std::vector<u8> code;
if (ResultStatus::Success == ReadCode(code)) {
+ std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
+ (const char*)exheader_header.codeset_info.name, 8);
+ u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
+ Kernel::g_current_process = Kernel::Process::Create(process_name, program_id);
+
+ // Copy data while converting endianess
+ std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps;
+ std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));
+ Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
+
Memory::WriteBlock(entry_point, &code[0], code.size());
- Kernel::LoadExec(entry_point);
+
+ s32 priority = exheader_header.arm11_system_local_caps.priority;
+ u32 stack_size = exheader_header.codeset_info.stack_size;
+ Kernel::g_current_process->Run(entry_point, priority, stack_size);
return ResultStatus::Success;
}
return ResultStatus::Error;
@@ -198,20 +217,33 @@ ResultStatus AppLoader_NCCH::Load() {
if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
return ResultStatus::Error;
- is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
- entry_point = exheader_header.codeset_info.text.address;
-
- LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
- LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
- LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
+ is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
+ entry_point = exheader_header.codeset_info.text.address;
+ code_size = exheader_header.codeset_info.text.code_size;
+ stack_size = exheader_header.codeset_info.stack_size;
+ bss_size = exheader_header.codeset_info.bss_size;
+ core_version = exheader_header.arm11_system_local_caps.core_version;
+ priority = exheader_header.arm11_system_local_caps.priority;
+ resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category;
+
+ LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name);
+ LOG_DEBUG(Loader, "Code compressed: %s" , is_compressed ? "yes" : "no");
+ LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
+ LOG_DEBUG(Loader, "Code size: 0x%08X", code_size);
+ LOG_DEBUG(Loader, "Stack size: 0x%08X", stack_size);
+ LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
+ LOG_DEBUG(Loader, "Core version: %d" , core_version);
+ LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
+ LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
+ LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
// Read ExeFS...
exefs_offset = ncch_header.exefs_offset * kBlockSize;
u32 exefs_size = ncch_header.exefs_size * kBlockSize;
- LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
- LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
+ LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
+ LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
file->Seek(exefs_offset + ncch_offset, SEEK_SET);
if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
@@ -247,8 +279,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
- LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
- LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
+ LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
+ LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
buffer.resize(romfs_size);
@@ -262,8 +294,4 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
return ResultStatus::ErrorNotUsed;
}
-u64 AppLoader_NCCH::GetProgramId() const {
- return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]);
-}
-
} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index f6f67006..29e39d2c 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -4,7 +4,11 @@
#pragma once
-#include "common/common.h"
+#include <memory>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/swap.h"
#include "core/loader/loader.h"
@@ -43,6 +47,8 @@ struct NCCH_Header {
u8 romfs_super_block_hash[0x20];
};
+static_assert(sizeof(NCCH_Header) == 0x200, "NCCH header structure size is wrong");
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// ExeFS (executable file system) headers
@@ -61,13 +67,13 @@ struct ExeFs_Header {
////////////////////////////////////////////////////////////////////////////////////////////////////
// ExHeader (executable file system header) headers
-struct ExHeader_SystemInfoFlags{
+struct ExHeader_SystemInfoFlags {
u8 reserved[5];
u8 flag;
u8 remaster_version[2];
};
-struct ExHeader_CodeSegmentInfo{
+struct ExHeader_CodeSegmentInfo {
u32 address;
u32 num_max_pages;
u32 code_size;
@@ -77,24 +83,24 @@ struct ExHeader_CodeSetInfo {
u8 name[8];
ExHeader_SystemInfoFlags flags;
ExHeader_CodeSegmentInfo text;
- u8 stacksize[4];
+ u32 stack_size;
ExHeader_CodeSegmentInfo ro;
u8 reserved[4];
ExHeader_CodeSegmentInfo data;
- u8 bsssize[4];
+ u32 bss_size;
};
-struct ExHeader_DependencyList{
+struct ExHeader_DependencyList {
u8 program_id[0x30][8];
};
-struct ExHeader_SystemInfo{
+struct ExHeader_SystemInfo {
u64 save_data_size;
u8 jump_id[8];
u8 reserved_2[0x30];
};
-struct ExHeader_StorageInfo{
+struct ExHeader_StorageInfo {
u8 ext_save_data_id[8];
u8 system_save_data_id[8];
u8 reserved[8];
@@ -102,30 +108,36 @@ struct ExHeader_StorageInfo{
u8 other_attributes;
};
-struct ExHeader_ARM11_SystemLocalCaps{
+struct ExHeader_ARM11_SystemLocalCaps {
u8 program_id[8];
u32 core_version;
- u8 flags[3];
+ u8 reserved_flags[2];
+ union {
+ u8 flags0;
+ BitField<0, 2, u8> ideal_processor;
+ BitField<2, 2, u8> affinity_mask;
+ BitField<4, 4, u8> system_mode;
+ };
u8 priority;
- u8 resource_limit_descriptor[0x16][2];
+ u8 resource_limit_descriptor[0x10][2];
ExHeader_StorageInfo storage_info;
- u8 service_access_control[0x32][8];
+ u8 service_access_control[0x20][8];
u8 ex_service_access_control[0x2][8];
u8 reserved[0xf];
u8 resource_limit_category;
};
-struct ExHeader_ARM11_KernelCaps{
- u8 descriptors[28][4];
+struct ExHeader_ARM11_KernelCaps {
+ u32_le descriptors[28];
u8 reserved[0x10];
};
-struct ExHeader_ARM9_AccessControl{
+struct ExHeader_ARM9_AccessControl {
u8 descriptors[15];
u8 descversion;
};
-struct ExHeader_Header{
+struct ExHeader_Header {
ExHeader_CodeSetInfo codeset_info;
ExHeader_DependencyList dependency_list;
ExHeader_SystemInfo system_info;
@@ -141,6 +153,8 @@ struct ExHeader_Header{
} access_desc;
};
+static_assert(sizeof(ExHeader_Header) == 0x800, "ExHeader structure size is wrong");
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace
@@ -199,12 +213,6 @@ public:
*/
ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
- /*
- * Gets the program id from the NCCH header
- * @return u64 Program id
- */
- u64 GetProgramId() const;
-
private:
/**
@@ -224,6 +232,12 @@ private:
bool is_compressed = false;
u32 entry_point = 0;
+ u32 code_size = 0;
+ u32 stack_size = 0;
+ u32 bss_size = 0;
+ u32 core_version = 0;
+ u8 priority = 0;
+ u8 resource_limit_category = 0;
u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header
u32 exefs_offset = 0;
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index a14e8303..5ecec956 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -2,88 +2,160 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
-#include "common/mem_arena.h"
+#include <map>
+#include "common/common_types.h"
+#include "common/logging/log.h"
+
+#include "core/hle/config_mem.h"
+#include "core/hle/shared_page.h"
#include "core/mem_map.h"
+#include "core/memory.h"
+#include "core/memory_setup.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Memory {
-u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena.
-
-static MemArena arena; ///< The MemArena class
-
-u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here
-u8* g_system_mem = nullptr; ///< System memory
-u8* g_heap = nullptr; ///< Application heap (main memory)
-u8* g_heap_linear = nullptr; ///< Linear heap
-u8* g_vram = nullptr; ///< Video memory (VRAM) pointer
-u8* g_shared_mem = nullptr; ///< Shared memory
-u8* g_dsp_mem = nullptr; ///< DSP memory
-u8* g_kernel_mem; ///< Kernel memory
-
-static u8* physical_bootrom = nullptr; ///< Bootrom physical memory
-static u8* uncached_bootrom = nullptr;
-
-static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here
-static u8* physical_system_mem = nullptr; ///< System physical memory
-static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM)
-static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory
-static u8* physical_vram = nullptr; ///< Video physical memory (VRAM)
-static u8* physical_shared_mem = nullptr; ///< Physical shared memory
-static u8* physical_dsp_mem = nullptr; ///< Physical DSP memory
-static u8* physical_kernel_mem; ///< Kernel memory
-
-// We don't declare the IO region in here since its handled by other means.
-static MemoryView g_views[] = {
- {&g_exefs_code, &physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0},
- {&g_vram, &physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
- {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
- {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0},
- {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0},
- {&g_dsp_mem, &physical_dsp_mem, DSP_MEMORY_VADDR, DSP_MEMORY_SIZE, 0},
- {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0},
- {&g_heap_linear, &physical_heap_gsp, HEAP_LINEAR_VADDR, HEAP_LINEAR_SIZE, 0},
+u8* g_exefs_code; ///< ExeFS:/.code is loaded here
+u8* g_heap; ///< Application heap (main memory)
+u8* g_shared_mem; ///< Shared memory
+u8* g_heap_linear; ///< Linear heap
+u8* g_vram; ///< Video memory (VRAM) pointer
+u8* g_dsp_mem; ///< DSP memory
+u8* g_tls_mem; ///< TLS memory
+
+namespace {
+
+struct MemoryArea {
+ u8** ptr;
+ u32 base;
+ u32 size;
};
-/*static MemoryView views[] =
-{
- {&m_pScratchPad, &m_pPhysicalScratchPad, 0x00010000, SCRATCHPAD_SIZE, 0},
- {NULL, &m_pUncachedScratchPad, 0x40010000, SCRATCHPAD_SIZE, MV_MIRROR_PREVIOUS},
- {&m_pVRAM, &m_pPhysicalVRAM, 0x04000000, 0x00800000, 0},
- {NULL, &m_pUncachedVRAM, 0x44000000, 0x00800000, MV_MIRROR_PREVIOUS},
- {&m_pRAM, &m_pPhysicalRAM, 0x08000000, g_MemorySize, MV_IS_PRIMARY_RAM}, // only from 0x08800000 is it usable (last 24 megs)
- {NULL, &m_pUncachedRAM, 0x48000000, g_MemorySize, MV_MIRROR_PREVIOUS | MV_IS_PRIMARY_RAM},
- {NULL, &m_pKernelRAM, 0x88000000, g_MemorySize, MV_MIRROR_PREVIOUS | MV_IS_PRIMARY_RAM},
+// We don't declare the IO regions in here since its handled by other means.
+static MemoryArea memory_areas[] = {
+ {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE},
+ {&g_heap, HEAP_VADDR, HEAP_SIZE },
+ {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE },
+ {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE },
+ {&g_vram, VRAM_VADDR, VRAM_SIZE },
+ {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE },
+ {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE },
+};
- // TODO: There are a few swizzled mirrors of VRAM, not sure about the best way to
- // implement those.
-};*/
+/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
+struct MemoryBlock {
+ MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) {
+ }
+ u32 handle;
+ u32 base_address;
+ u32 address;
+ u32 size;
+ u32 operation;
+ u32 permissions;
+
+ const u32 GetVirtualAddress() const{
+ return base_address + address;
+ }
+};
-static const int kNumMemViews = sizeof(g_views) / sizeof(MemoryView); ///< Number of mem views
+static std::map<u32, MemoryBlock> heap_map;
+static std::map<u32, MemoryBlock> heap_linear_map;
-void Init() {
- int flags = 0;
+}
+
+u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
+ MemoryBlock block;
- for (size_t i = 0; i < ARRAY_SIZE(g_views); i++) {
- if (g_views[i].flags & MV_IS_PRIMARY_RAM)
- g_views[i].size = FCRAM_SIZE;
+ block.base_address = HEAP_VADDR;
+ block.size = size;
+ block.operation = operation;
+ block.permissions = permissions;
+
+ if (heap_map.size() > 0) {
+ const MemoryBlock last_block = heap_map.rbegin()->second;
+ block.address = last_block.address + last_block.size;
}
+ heap_map[block.GetVirtualAddress()] = block;
+
+ return block.GetVirtualAddress();
+}
+
+u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
+ MemoryBlock block;
- g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena);
+ block.base_address = LINEAR_HEAP_VADDR;
+ block.size = size;
+ block.operation = operation;
+ block.permissions = permissions;
+
+ if (heap_linear_map.size() > 0) {
+ const MemoryBlock last_block = heap_linear_map.rbegin()->second;
+ block.address = last_block.address + last_block.size;
+ }
+ heap_linear_map[block.GetVirtualAddress()] = block;
- LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
- physical_fcram);
+ return block.GetVirtualAddress();
+}
+
+PAddr VirtualToPhysicalAddress(const VAddr addr) {
+ if (addr == 0) {
+ return 0;
+ } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
+ return addr - VRAM_VADDR + VRAM_PADDR;
+ } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
+ return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
+ } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
+ return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
+ } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
+ return addr - IO_AREA_VADDR + IO_AREA_PADDR;
+ }
+
+ LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
+ // To help with debugging, set bit on address so that it's obviously invalid.
+ return addr | 0x80000000;
+}
+
+VAddr PhysicalToVirtualAddress(const PAddr addr) {
+ if (addr == 0) {
+ return 0;
+ } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
+ return addr - VRAM_PADDR + VRAM_VADDR;
+ } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
+ return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR;
+ } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
+ return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
+ } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
+ return addr - IO_AREA_PADDR + IO_AREA_VADDR;
+ }
+
+ LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
+ // To help with debugging, set bit on address so that it's obviously invalid.
+ return addr | 0x80000000;
+}
+
+void Init() {
+ InitMemoryMap();
+
+ for (MemoryArea& area : memory_areas) {
+ *area.ptr = new u8[area.size];
+ MapMemoryRegion(area.base, area.size, *area.ptr);
+ }
+ MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem);
+ MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page);
+
+ LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap);
}
void Shutdown() {
- u32 flags = 0;
- MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena);
+ heap_map.clear();
+ heap_linear_map.clear();
- arena.ReleaseSpace();
- g_base = nullptr;
+ for (MemoryArea& area : memory_areas) {
+ delete[] *area.ptr;
+ *area.ptr = nullptr;
+ }
LOG_DEBUG(HW_Memory, "shutdown OK");
}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index bce99dff..945815cd 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -4,163 +4,21 @@
#pragma once
-#include "common/common.h"
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
-
namespace Memory {
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-enum : u32 {
- BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
- BOOTROM_PADDR = 0x00000000, ///< Bootrom physical address
- BOOTROM_PADDR_END = (BOOTROM_PADDR + BOOTROM_SIZE),
-
- BOOTROM_MIRROR_SIZE = 0x00010000, ///< Bootrom Mirror size
- BOOTROM_MIRROR_PADDR = 0x00010000, ///< Bootrom Mirror physical address
- BOOTROM_MIRROR_PADDR_END = (BOOTROM_MIRROR_PADDR + BOOTROM_MIRROR_SIZE),
-
- MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
- MPCORE_PRIV_PADDR = 0x17E00000, ///< MPCore private memory region physical address
- MPCORE_PRIV_PADDR_END = (MPCORE_PRIV_PADDR + MPCORE_PRIV_SIZE),
-
- FCRAM_SIZE = 0x08000000, ///< FCRAM size
- FCRAM_PADDR = 0x20000000, ///< FCRAM physical address
- FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
- FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
- FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
-
- AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
- AXI_WRAM_PADDR = 0x1FF80000, ///< AXI WRAM physical address
- AXI_WRAM_PADDR_END = (AXI_WRAM_PADDR + AXI_WRAM_SIZE),
-
- SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
- SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory
- SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE),
-
- DSP_MEMORY_SIZE = 0x00080000, ///< DSP memory size
- DSP_MEMORY_VADDR = 0x1FF00000, ///< DSP memory virtual address
- DSP_MEMORY_VADDR_END = (DSP_MEMORY_VADDR + DSP_MEMORY_SIZE),
-
- CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size
- CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address
- CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE),
-
- SHARED_PAGE_SIZE = 0x00001000, ///< Shared page size
- SHARED_PAGE_VADDR = 0x1FF81000, ///< Shared page virtual address
- SHARED_PAGE_VADDR_END = (SHARED_PAGE_VADDR + SHARED_PAGE_SIZE),
-
- KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size
- KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are
- KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE),
-
- EXEFS_CODE_SIZE = 0x03F00000,
- EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here
- EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
-
- // Region of FCRAM used by system
- SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
- SYSTEM_MEMORY_VADDR = 0x04000000,
- SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
-
- HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
- //HEAP_PADDR = HEAP_GSP_SIZE,
- //HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
- HEAP_VADDR = 0x08000000,
- HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
-
- HEAP_LINEAR_SIZE = 0x08000000, ///< Linear heap size... TODO: Define correctly?
- HEAP_LINEAR_VADDR = 0x14000000,
- HEAP_LINEAR_VADDR_END = (HEAP_LINEAR_VADDR + HEAP_LINEAR_SIZE),
- HEAP_LINEAR_PADDR = 0x00000000,
- HEAP_LINEAR_PADDR_END = (HEAP_LINEAR_PADDR + HEAP_LINEAR_SIZE),
-
- HARDWARE_IO_SIZE = 0x01000000,
- HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start
- HARDWARE_IO_VADDR = 0x1EC00000, ///< IO virtual address start
- HARDWARE_IO_PADDR_END = (HARDWARE_IO_PADDR + HARDWARE_IO_SIZE),
- HARDWARE_IO_VADDR_END = (HARDWARE_IO_VADDR + HARDWARE_IO_SIZE),
-
- VRAM_SIZE = 0x00600000,
- VRAM_PADDR = 0x18000000,
- VRAM_VADDR = 0x1F000000,
- VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
- VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE),
-
- SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
- SCRATCHPAD_VADDR_END = 0x10000000,
- SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
-struct MemoryBlock {
- MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) {
- }
- u32 handle;
- u32 base_address;
- u32 address;
- u32 size;
- u32 operation;
- u32 permissions;
-
- const u32 GetVirtualAddress() const{
- return base_address + address;
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// Base is a pointer to the base of the memory map. Yes, some MMU tricks
-// are used to set up a full GC or Wii memory map in process memory. on
-// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that
-// some things are mirrored too many times, but eh... it works.
-
-// In 64-bit, this might point to "high memory" (above the 32-bit limit),
-// so be sure to load it into a 64-bit register.
-extern u8 *g_base;
-
-// These are guaranteed to point to "low memory" addresses (sub-32-bit).
-// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
-// 32-bit: Same as the corresponding physical/virtual pointers.
-extern u8* g_heap_linear; ///< Linear heap (main memory)
-extern u8* g_heap; ///< Application heap (main memory)
-extern u8* g_vram; ///< Video memory (VRAM)
-extern u8* g_shared_mem; ///< Shared memory
-extern u8* g_kernel_mem; ///< Kernel memory
-extern u8* g_dsp_mem; ///< DSP memory
-extern u8* g_system_mem; ///< System memory
-extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
+extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
+extern u8* g_heap; ///< Application heap (main memory)
+extern u8* g_shared_mem; ///< Shared memory
+extern u8* g_heap_linear; ///< Linear heap (main memory)
+extern u8* g_vram; ///< Video memory (VRAM)
+extern u8* g_dsp_mem; ///< DSP memory
+extern u8* g_tls_mem; ///< TLS memory
void Init();
void Shutdown();
-template <typename T>
-inline void Read(T &var, VAddr addr);
-
-template <typename T>
-inline void Write(VAddr addr, T data);
-
-u8 Read8(VAddr addr);
-u16 Read16(VAddr addr);
-u32 Read32(VAddr addr);
-u64 Read64(VAddr addr);
-
-u32 Read8_ZX(VAddr addr);
-u32 Read16_ZX(VAddr addr);
-
-void Write8(VAddr addr, u8 data);
-void Write16(VAddr addr, u16 data);
-void Write32(VAddr addr, u32 data);
-void Write64(VAddr addr, u64 data);
-
-void WriteBlock(VAddr addr, const u8* data, size_t size);
-
-u8* GetPointer(VAddr virtual_address);
-
/**
* Maps a block of memory on the heap
* @param size Size of block in bytes
@@ -177,14 +35,15 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions);
*/
u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions);
-inline const char* GetCharPointer(const VAddr address) {
- return (const char *)GetPointer(address);
-}
+/**
+ * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
+ * address. This should be used by services to translate addresses for use by the hardware.
+ */
+PAddr VirtualToPhysicalAddress(VAddr addr);
-/// Converts a physical address to virtual address
+/**
+ * Undoes a mapping performed by VirtualToPhysicalAddress().
+ */
VAddr PhysicalToVirtualAddress(PAddr addr);
-/// Converts a virtual address to physical address
-PAddr VirtualToPhysicalAddress(VAddr addr);
-
} // namespace
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
deleted file mode 100644
index a161a820..00000000
--- a/src/core/mem_map_funcs.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <map>
-
-#include "common/common.h"
-
-#include "core/mem_map.h"
-#include "core/hw/hw.h"
-#include "hle/config_mem.h"
-#include "hle/shared_page.h"
-
-namespace Memory {
-
-static std::map<u32, MemoryBlock> heap_map;
-static std::map<u32, MemoryBlock> heap_linear_map;
-static std::map<u32, MemoryBlock> shared_map;
-
-/// Convert a physical address to virtual address
-VAddr PhysicalToVirtualAddress(const PAddr addr) {
- // Our memory interface read/write functions assume virtual addresses. Put any physical address
- // to virtual address translations here. This is quite hacky, but necessary until we implement
- // proper MMU emulation.
- // TODO: Screw it, I'll let bunnei figure out how to do this properly.
- if ((addr >= VRAM_PADDR) && (addr < VRAM_PADDR_END)) {
- return addr - VRAM_PADDR + VRAM_VADDR;
- }else if ((addr >= FCRAM_PADDR) && (addr < FCRAM_PADDR_END)) {
- return addr - FCRAM_PADDR + FCRAM_VADDR;
- }
-
- LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
- return addr;
-}
-
-/// Convert a physical address to virtual address
-PAddr VirtualToPhysicalAddress(const VAddr addr) {
- // Our memory interface read/write functions assume virtual addresses. Put any physical address
- // to virtual address translations here. This is quite hacky, but necessary until we implement
- // proper MMU emulation.
- // TODO: Screw it, I'll let bunnei figure out how to do this properly.
- if ((addr >= VRAM_VADDR) && (addr < VRAM_VADDR_END)) {
- return addr - 0x07000000;
- } else if ((addr >= FCRAM_VADDR) && (addr < FCRAM_VADDR_END)) {
- return addr - FCRAM_VADDR + FCRAM_PADDR;
- }
-
- LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
- return addr;
-}
-
-template <typename T>
-inline void Read(T &var, const VAddr vaddr) {
- // TODO: Figure out the fastest order of tests for both read and write (they are probably different).
- // TODO: Make sure this represents the mirrors in a correct way.
- // Could just do a base-relative read, too.... TODO
-
- // Kernel memory command buffer
- if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- var = *((const T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR]);
-
- // ExeFS:/.code is loaded here
- } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- var = *((const T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR]);
-
- // FCRAM - linear heap
- } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
- var = *((const T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR]);
-
- // FCRAM - application heap
- } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- var = *((const T*)&g_heap[vaddr - HEAP_VADDR]);
-
- // Shared memory
- } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]);
-
- // System memory
- } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- var = *((const T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR]);
-
- // Config memory
- } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
- ConfigMem::Read<T>(var, vaddr);
-
- // Shared page
- } else if ((vaddr >= SHARED_PAGE_VADDR) && (vaddr < SHARED_PAGE_VADDR_END)) {
- SharedPage::Read<T>(var, vaddr);
-
- // DSP memory
- } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) {
- var = *((const T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR]);
-
- // VRAM
- } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- var = *((const T*)&g_vram[vaddr - VRAM_VADDR]);
-
- } else {
- LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
- }
-}
-
-template <typename T>
-inline void Write(const VAddr vaddr, const T data) {
-
- // Kernel memory command buffer
- if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- *(T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR] = data;
-
- // ExeFS:/.code is loaded here
- } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- *(T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR] = data;
-
- // FCRAM - linear heap
- } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
- *(T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR] = data;
-
- // FCRAM - application heap
- } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- *(T*)&g_heap[vaddr - HEAP_VADDR] = data;
-
- // Shared memory
- } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- *(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data;
-
- // System memory
- } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- *(T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR] = data;
-
- // VRAM
- } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- *(T*)&g_vram[vaddr - VRAM_VADDR] = data;
-
- // DSP memory
- } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) {
- *(T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR] = data;
-
- //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) {
- // ASSERT_MSG(MEMMAP, false, "umimplemented write to Configuration Memory");
- //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) {
- // ASSERT_MSG(MEMMAP, false, "umimplemented write to shared page");
-
- // Error out...
- } else {
- LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr);
- }
-}
-
-u8 *GetPointer(const VAddr vaddr) {
- // Kernel memory command buffer
- if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- return g_kernel_mem + (vaddr - KERNEL_MEMORY_VADDR);
-
- // ExeFS:/.code is loaded here
- } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- return g_exefs_code + (vaddr - EXEFS_CODE_VADDR);
-
- // FCRAM - linear heap
- } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
- return g_heap_linear + (vaddr - HEAP_LINEAR_VADDR);
-
- // FCRAM - application heap
- } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- return g_heap + (vaddr - HEAP_VADDR);
-
- // Shared memory
- } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR);
-
- // System memory
- } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- return g_system_mem + (vaddr - SYSTEM_MEMORY_VADDR);
-
- // VRAM
- } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- return g_vram + (vaddr - VRAM_VADDR);
-
- } else {
- LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr);
- return 0;
- }
-}
-
-/**
- * Maps a block of memory on the heap
- * @param size Size of block in bytes
- * @param operation Memory map operation type
- * @param flags Memory allocation flags
- */
-u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
- MemoryBlock block;
-
- block.base_address = HEAP_VADDR;
- block.size = size;
- block.operation = operation;
- block.permissions = permissions;
-
- if (heap_map.size() > 0) {
- const MemoryBlock last_block = heap_map.rbegin()->second;
- block.address = last_block.address + last_block.size;
- }
- heap_map[block.GetVirtualAddress()] = block;
-
- return block.GetVirtualAddress();
-}
-
-/**
- * Maps a block of memory on the linear heap
- * @param size Size of block in bytes
- * @param operation Memory map operation type
- * @param flags Memory allocation flags
- */
-u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
- MemoryBlock block;
-
- block.base_address = HEAP_LINEAR_VADDR;
- block.size = size;
- block.operation = operation;
- block.permissions = permissions;
-
- if (heap_linear_map.size() > 0) {
- const MemoryBlock last_block = heap_linear_map.rbegin()->second;
- block.address = last_block.address + last_block.size;
- }
- heap_linear_map[block.GetVirtualAddress()] = block;
-
- return block.GetVirtualAddress();
-}
-
-u8 Read8(const VAddr addr) {
- u8 data = 0;
- Read<u8>(data, addr);
- return data;
-}
-
-u16 Read16(const VAddr addr) {
- u16_le data = 0;
- Read<u16_le>(data, addr);
- return (u16)data;
-}
-
-u32 Read32(const VAddr addr) {
- u32_le data = 0;
- Read<u32_le>(data, addr);
- return (u32)data;
-}
-
-u64 Read64(const VAddr addr) {
- u64_le data = 0;
- Read<u64_le>(data, addr);
- return (u64)data;
-}
-
-u32 Read8_ZX(const VAddr addr) {
- return (u32)Read8(addr);
-}
-
-u32 Read16_ZX(const VAddr addr) {
- return (u32)Read16(addr);
-}
-
-void Write8(const VAddr addr, const u8 data) {
- Write<u8>(addr, data);
-}
-
-void Write16(const VAddr addr, const u16 data) {
- Write<u16_le>(addr, data);
-}
-
-void Write32(const VAddr addr, const u32 data) {
- Write<u32_le>(addr, data);
-}
-
-void Write64(const VAddr addr, const u64 data) {
- Write<u64_le>(addr, data);
-}
-
-void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
- u32 offset = 0;
- while (offset < (size & ~3)) {
- Write32(addr + offset, *(u32*)&data[offset]);
- offset += 4;
- }
-
- if (size & 2) {
- Write16(addr + offset, *(u16*)&data[offset]);
- offset += 2;
- }
-
- if (size & 1)
- Write8(addr + offset, data[offset]);
-}
-
-} // namespace
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
new file mode 100644
index 00000000..5d8069ac
--- /dev/null
+++ b/src/core/memory.cpp
@@ -0,0 +1,202 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/swap.h"
+
+#include "core/hle/config_mem.h"
+#include "core/hle/shared_page.h"
+#include "core/hw/hw.h"
+#include "core/mem_map.h"
+#include "core/memory.h"
+
+namespace Memory {
+
+const u32 PAGE_MASK = PAGE_SIZE - 1;
+const int PAGE_BITS = 12;
+
+enum class PageType {
+ /// Page is unmapped and should cause an access error.
+ Unmapped,
+ /// Page is mapped to regular memory. This is the only type you can get pointers to.
+ Memory,
+ /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
+ Special,
+};
+
+/**
+ * A (reasonably) fast way of allowing switchable and remmapable process address spaces. It loosely
+ * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and
+ * fetching requirements when acessing. In the usual case of an access to regular memory, it only
+ * requires an indexed fetch and a check for NULL.
+ */
+struct PageTable {
+ static const size_t NUM_ENTRIES = 1 << (32 - PAGE_BITS);
+
+ /**
+ * Array of memory pointers backing each page. An entry can only be non-null if the
+ * corresponding entry in the `attributes` array is of type `Memory`.
+ */
+ std::array<u8*, NUM_ENTRIES> pointers;
+
+ /**
+ * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
+ * the corresponding entry in `pointer` MUST be set to null.
+ */
+ std::array<PageType, NUM_ENTRIES> attributes;
+};
+
+/// Singular page table used for the singleton process
+static PageTable main_page_table;
+/// Currently active page table
+static PageTable* current_page_table = &main_page_table;
+
+static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
+ LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, (base + size) * PAGE_SIZE);
+
+ u32 end = base + size;
+
+ while (base != end) {
+ ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
+
+ if (current_page_table->attributes[base] != PageType::Unmapped) {
+ LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
+ }
+ current_page_table->attributes[base] = type;
+ current_page_table->pointers[base] = memory;
+
+ base += 1;
+ memory += PAGE_SIZE;
+ }
+}
+
+void InitMemoryMap() {
+ main_page_table.pointers.fill(nullptr);
+ main_page_table.attributes.fill(PageType::Unmapped);
+}
+
+void MapMemoryRegion(VAddr base, u32 size, u8* target) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
+ MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
+}
+
+void MapIoRegion(VAddr base, u32 size) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
+ MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
+}
+
+template <typename T>
+T Read(const VAddr vaddr) {
+ const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer) {
+ return *reinterpret_cast<const T*>(page_pointer + (vaddr & PAGE_MASK));
+ }
+
+ PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ switch (type) {
+ case PageType::Unmapped:
+ LOG_ERROR(HW_Memory, "unmapped Read%lu @ 0x%08X", sizeof(T) * 8, vaddr);
+ return 0;
+ case PageType::Memory:
+ ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
+ case PageType::Special:
+ LOG_ERROR(HW_Memory, "I/O reads aren't implemented yet @ %08X", vaddr);
+ return 0;
+ default:
+ UNREACHABLE();
+ }
+}
+
+template <typename T>
+void Write(const VAddr vaddr, const T data) {
+ u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer) {
+ *reinterpret_cast<T*>(page_pointer + (vaddr & PAGE_MASK)) = data;
+ return;
+ }
+
+ PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ switch (type) {
+ case PageType::Unmapped:
+ LOG_ERROR(HW_Memory, "unmapped Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32) data, vaddr);
+ return;
+ case PageType::Memory:
+ ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
+ case PageType::Special:
+ LOG_ERROR(HW_Memory, "I/O writes aren't implemented yet @ %08X", vaddr);
+ return;
+ default:
+ UNREACHABLE();
+ }
+}
+
+u8* GetPointer(const VAddr vaddr) {
+ u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer) {
+ return page_pointer + (vaddr & PAGE_MASK);
+ }
+
+ LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr);
+ return nullptr;
+}
+
+u8* GetPhysicalPointer(PAddr address) {
+ return GetPointer(PhysicalToVirtualAddress(address));
+}
+
+u8 Read8(const VAddr addr) {
+ return Read<u8>(addr);
+}
+
+u16 Read16(const VAddr addr) {
+ return Read<u16_le>(addr);
+}
+
+u32 Read32(const VAddr addr) {
+ return Read<u32_le>(addr);
+}
+
+u64 Read64(const VAddr addr) {
+ return Read<u64_le>(addr);
+}
+
+void Write8(const VAddr addr, const u8 data) {
+ Write<u8>(addr, data);
+}
+
+void Write16(const VAddr addr, const u16 data) {
+ Write<u16_le>(addr, data);
+}
+
+void Write32(const VAddr addr, const u32 data) {
+ Write<u32_le>(addr, data);
+}
+
+void Write64(const VAddr addr, const u64 data) {
+ Write<u64_le>(addr, data);
+}
+
+void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
+ u32 offset = 0;
+ while (offset < (size & ~3)) {
+ Write32(addr + offset, *(u32*)&data[offset]);
+ offset += 4;
+ }
+
+ if (size & 2) {
+ Write16(addr + offset, *(u16*)&data[offset]);
+ offset += 2;
+ }
+
+ if (size & 1)
+ Write8(addr + offset, data[offset]);
+}
+
+} // namespace
diff --git a/src/core/memory.h b/src/core/memory.h
new file mode 100644
index 00000000..2d225801
--- /dev/null
+++ b/src/core/memory.h
@@ -0,0 +1,129 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Memory {
+
+/**
+ * Page size used by the ARM architecture. This is the smallest granularity with which memory can
+ * be mapped.
+ */
+const u32 PAGE_SIZE = 0x1000;
+
+/// Physical memory regions as seen from the ARM11
+enum : PAddr {
+ /// IO register area
+ IO_AREA_PADDR = 0x10100000,
+ IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB)
+ IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE,
+
+ /// MPCore internal memory region
+ MPCORE_RAM_PADDR = 0x17E00000,
+ MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB)
+ MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE,
+
+ /// Video memory
+ VRAM_PADDR = 0x18000000,
+ VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
+ VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE,
+
+ /// DSP memory
+ DSP_RAM_PADDR = 0x1FF00000,
+ DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
+ DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE,
+
+ /// AXI WRAM
+ AXI_WRAM_PADDR = 0x1FF80000,
+ AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB)
+ AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE,
+
+ /// Main FCRAM
+ FCRAM_PADDR = 0x20000000,
+ FCRAM_SIZE = 0x08000000, ///< FCRAM size (128MB)
+ FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE,
+};
+
+/// Virtual user-space memory regions
+enum : VAddr {
+ /// Where the application text, data and bss reside.
+ PROCESS_IMAGE_VADDR = 0x00100000,
+ PROCESS_IMAGE_MAX_SIZE = 0x03F00000,
+ PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
+
+ /// Area where IPC buffers are mapped onto.
+ IPC_MAPPING_VADDR = 0x04000000,
+ IPC_MAPPING_SIZE = 0x04000000,
+ IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE,
+
+ /// Application heap (includes stack).
+ HEAP_VADDR = 0x08000000,
+ HEAP_SIZE = 0x08000000,
+ HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
+
+ /// Area where shared memory buffers are mapped onto.
+ SHARED_MEMORY_VADDR = 0x10000000,
+ SHARED_MEMORY_SIZE = 0x04000000,
+ SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE,
+
+ /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical memory.
+ LINEAR_HEAP_VADDR = 0x14000000,
+ LINEAR_HEAP_SIZE = 0x08000000,
+ LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE,
+
+ /// Maps 1:1 to the IO register area.
+ IO_AREA_VADDR = 0x1EC00000,
+ IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE,
+
+ /// Maps 1:1 to VRAM.
+ VRAM_VADDR = 0x1F000000,
+ VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE,
+
+ /// Maps 1:1 to DSP memory.
+ DSP_RAM_VADDR = 0x1FF00000,
+ DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE,
+
+ /// Read-only page containing kernel and system configuration values.
+ CONFIG_MEMORY_VADDR = 0x1FF80000,
+ CONFIG_MEMORY_SIZE = 0x00001000,
+ CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE,
+
+ /// Usually read-only page containing mostly values read from hardware.
+ SHARED_PAGE_VADDR = 0x1FF81000,
+ SHARED_PAGE_SIZE = 0x00001000,
+ SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
+
+ // TODO(yuriks): The size of this area is dynamic, the kernel grows
+ // it as more and more threads are created. For now we'll just use a
+ // hardcoded value.
+ /// Area where TLS (Thread-Local Storage) buffers are allocated.
+ TLS_AREA_VADDR = 0x1FF82000,
+ TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads
+ TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
+};
+
+u8 Read8(VAddr addr);
+u16 Read16(VAddr addr);
+u32 Read32(VAddr addr);
+u64 Read64(VAddr addr);
+
+void Write8(VAddr addr, u8 data);
+void Write16(VAddr addr, u16 data);
+void Write32(VAddr addr, u32 data);
+void Write64(VAddr addr, u64 data);
+
+void WriteBlock(VAddr addr, const u8* data, size_t size);
+
+u8* GetPointer(VAddr virtual_address);
+
+/**
+ * Gets a pointer to the memory region beginning at the specified physical address.
+ *
+ * @note This is currently implemented using PhysicalToVirtualAddress().
+ */
+u8* GetPhysicalPointer(PAddr address);
+
+}
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
new file mode 100644
index 00000000..46263495
--- /dev/null
+++ b/src/core/memory_setup.h
@@ -0,0 +1,29 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Memory {
+
+void InitMemoryMap();
+
+/**
+ * Maps an allocated buffer onto a region of the emulated process address space.
+ *
+ * @param base The address to start mapping at. Must be page-aligned.
+ * @param size The amount of bytes to map. Must be page-aligned.
+ * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
+ */
+void MapMemoryRegion(VAddr base, u32 size, u8* target);
+
+/**
+ * Maps a region of the emulated process address space as a IO region.
+ * @note Currently this can only be used to mark a region as being IO, since actual memory-mapped
+ * IO isn't yet supported.
+ */
+void MapIoRegion(VAddr base, u32 size);
+
+}
diff --git a/src/core/settings.h b/src/core/settings.h
index 870eea95..0f470024 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -44,6 +44,11 @@ struct Values {
// System Region
int region_value;
+ // Renderer
+ float bg_red;
+ float bg_green;
+ float bg_blue;
+
std::string log_filter;
} extern values;
diff --git a/src/core/system.cpp b/src/core/system.cpp
index f4c2df1c..561ff82f 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -14,11 +14,6 @@
namespace System {
-volatile State g_state;
-
-void UpdateState(State state) {
-}
-
void Init(EmuWindow* emu_window) {
Core::Init();
CoreTiming::Init();
@@ -29,13 +24,6 @@ void Init(EmuWindow* emu_window) {
VideoCore::Init(emu_window);
}
-void RunLoopFor(int cycles) {
- RunLoopUntil(CoreTiming::GetTicks() + cycles);
-}
-
-void RunLoopUntil(u64 global_cycles) {
-}
-
void Shutdown() {
VideoCore::Shutdown();
HLE::Shutdown();
diff --git a/src/core/system.h b/src/core/system.h
index 05d83653..59a75ca1 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -4,30 +4,11 @@
#pragma once
-#include "common/emu_window.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
+class EmuWindow;
namespace System {
-// State of the full emulator
-enum State {
- STATE_NULL = 0, ///< System is in null state, nothing initialized
- STATE_IDLE, ///< System is in an initialized state, but not running
- STATE_RUNNING, ///< System is running
- STATE_LOADING, ///< System is loading a ROM
- STATE_HALTED, ///< System is halted (error)
- STATE_STALLED, ///< System is stalled (unused)
- STATE_DEBUG, ///< System is in a special debug mode (unused)
- STATE_DIE ///< System is shutting down
-};
-
-extern volatile State g_state;
-
-void UpdateState(State state);
void Init(EmuWindow* emu_window);
-void RunLoopFor(int cycles);
-void RunLoopUntil(u64 global_cycles);
void Shutdown();
}
diff --git a/src/video_core/color.h b/src/video_core/color.h
index 43d635e2..4d2026eb 100644
--- a/src/video_core/color.h
+++ b/src/video_core/color.h
@@ -5,6 +5,8 @@
#pragma once
#include "common/common_types.h"
+#include "common/swap.h"
+
#include "video_core/math.h"
namespace Color {
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index e031871e..1ea7cad0 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -27,6 +27,10 @@ static int float_regs_counter = 0;
static u32 uniform_write_buffer[4];
+static int default_attr_counter = 0;
+
+static u32 default_attr_write_buffer[3];
+
Common::Profiling::TimingCategory category_drawing("Drawing");
static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
@@ -71,12 +75,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
u32 vertex_attribute_sources[16];
boost::fill(vertex_attribute_sources, 0xdeadbeef);
u32 vertex_attribute_strides[16];
- u32 vertex_attribute_formats[16];
+ Regs::VertexAttributeFormat vertex_attribute_formats[16];
- // HACK: Initialize vertex_attribute_elements to zero to prevent infinite loops below.
- // This is one of the hacks required to deal with uninitalized vertex attributes.
- // TODO: Fix this properly.
- u32 vertex_attribute_elements[16] = {};
+ u32 vertex_attribute_elements[16];
u32 vertex_attribute_element_size[16];
// Setup attribute data from loaders
@@ -90,7 +91,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
u32 attribute_index = loader_config.GetComponent(component);
vertex_attribute_sources[attribute_index] = load_address;
vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
- vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index));
+ vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index);
load_address += attribute_config.GetStride(attribute_index);
@@ -101,7 +102,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed));
const auto& index_info = registers.index_array;
- const u8* index_address_8 = Memory::GetPointer(PAddrToVAddr(base_address + index_info.offset));
+ const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
const u16* index_address_16 = (u16*)index_address_8;
bool index_u16 = index_info.format != 0;
@@ -126,26 +127,29 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
input.attr[0].w = debug_token;
for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
- for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
- const u8* srcdata = Memory::GetPointer(PAddrToVAddr(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]));
-
- // TODO(neobrain): Ocarina of Time 3D has GetNumTotalAttributes return 8,
- // yet only provides 2 valid source data addresses. Need to figure out
- // what's wrong there, until then we just continue when address lookup fails
- if (srcdata == nullptr)
- continue;
-
- const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata :
- (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata :
- (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata :
- *(float*)srcdata;
- input.attr[i][comp] = float24::FromFloat32(srcval);
- LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
- comp, i, vertex, index,
- attribute_config.GetPhysicalBaseAddress(),
- vertex_attribute_sources[i] - base_address,
- vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
- input.attr[i][comp].ToFloat32());
+ if (attribute_config.IsDefaultAttribute(i)) {
+ input.attr[i] = VertexShader::GetDefaultAttribute(i);
+ LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
+ i, vertex, index,
+ input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
+ input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
+ } else {
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
+
+ const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
+ (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
+ (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata :
+ *(float*)srcdata;
+
+ input.attr[i][comp] = float24::FromFloat32(srcval);
+ LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
+ comp, i, vertex, index,
+ attribute_config.GetPhysicalBaseAddress(),
+ vertex_attribute_sources[i] - base_address,
+ vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
+ input.attr[i][comp].ToFloat32());
+ }
}
}
@@ -224,7 +228,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
// it directly write the values?
uniform_write_buffer[float_regs_counter++] = value;
- // Uniforms are written in a packed format such that 4 float24 values are encoded in
+ // Uniforms are written in a packed format such that four float24 values are encoded in
// three 32-bit numbers. We write to internal memory once a full such vector is
// written.
if ((float_regs_counter >= 4 && uniform_setup.IsFloat32()) ||
@@ -259,6 +263,46 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
}
break;
}
+
+ // Load default vertex input attributes
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
+ {
+ // TODO: Does actual hardware indeed keep an intermediate buffer or does
+ // it directly write the values?
+ default_attr_write_buffer[default_attr_counter++] = value;
+
+ // Default attributes are written in a packed format such that four float24 values are encoded in
+ // three 32-bit numbers. We write to internal memory once a full such vector is
+ // written.
+ if (default_attr_counter >= 3) {
+ default_attr_counter = 0;
+
+ auto& setup = registers.vs_default_attributes_setup;
+
+ if (setup.index >= 16) {
+ LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
+ break;
+ }
+
+ Math::Vec4<float24>& attribute = VertexShader::GetDefaultAttribute(setup.index);
+
+ // NOTE: The destination component order indeed is "backwards"
+ attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
+ attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
+ attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
+ attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
+
+ LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
+ attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
+ attribute.w.ToFloat32());
+
+ // TODO: Verify that this actually modifies the register!
+ setup.index = setup.index + 1;
+ }
+ break;
+ }
// Load shader program code
case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc):
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 83982b4f..883df48a 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -393,6 +393,17 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
}
}
+ case Regs::TextureFormat::I4:
+ {
+ u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1);
+ const u8* source_ptr = source + morton_offset / 2;
+
+ u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF);
+ i = Color::Convert4To8(i);
+
+ return { i, i, i, 255 };
+ }
+
case Regs::TextureFormat::A4:
{
u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1);
@@ -507,7 +518,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
// Add modifier
unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value();
- static const auto etc1_modifier_table = std::array<std::array<u8, 2>, 8>{{
+ static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
{ 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
{ 18, 60 }, { 24, 80 }, { 33, 106 }, { 47, 183 }
}};
@@ -597,7 +608,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
png_init_io(png_ptr, fp.GetHandle());
- // Write header (8 bit colour depth)
+ // Write header (8 bit color depth)
png_set_IHDR(png_ptr, info_ptr, texture_config.width, texture_config.height,
8, PNG_COLOR_TYPE_RGB /*_ALPHA*/, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index fe20cd77..3fbf9572 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -10,10 +10,11 @@
#include <map>
#include <vector>
+#include "common/assert.h"
#include "common/bit_field.h"
+#include "common/common_funcs.h"
#include "common/common_types.h"
-
-#include "core/mem_map.h"
+#include "common/logging/log.h"
namespace Pica {
@@ -153,7 +154,7 @@ struct Regs {
I8 = 7,
A8 = 8,
IA4 = 9,
-
+ I4 = 10,
A4 = 11,
ETC1 = 12, // compressed
ETC1A4 = 13, // compressed
@@ -223,7 +224,8 @@ struct Regs {
Texture1 = 0x4,
Texture2 = 0x5,
Texture3 = 0x6,
- // 0x7-0xc = primary color??
+
+ PreviousBuffer = 0xd,
Constant = 0xe,
Previous = 0xf,
};
@@ -296,7 +298,18 @@ struct Regs {
BitField<24, 8, u32> const_a;
};
- INSERT_PADDING_WORDS(0x1);
+ union {
+ BitField< 0, 2, u32> color_scale;
+ BitField<16, 2, u32> alpha_scale;
+ };
+
+ inline unsigned GetColorMultiplier() const {
+ return (color_scale < 3) ? (1 << color_scale) : 1;
+ }
+
+ inline unsigned GetAlphaMultiplier() const {
+ return (alpha_scale < 3) ? (1 << alpha_scale) : 1;
+ }
};
TevStageConfig tev_stage0;
@@ -306,11 +319,36 @@ struct Regs {
TevStageConfig tev_stage2;
INSERT_PADDING_WORDS(0x3);
TevStageConfig tev_stage3;
- INSERT_PADDING_WORDS(0x13);
+ INSERT_PADDING_WORDS(0x3);
+
+ union {
+ // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
+ // these masks are set
+ BitField< 8, 4, u32> update_mask_rgb;
+ BitField<12, 4, u32> update_mask_a;
+
+ bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
+ }
+
+ bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_a & (1 << stage_index));
+ }
+ } tev_combiner_buffer_input;
+
+ INSERT_PADDING_WORDS(0xf);
TevStageConfig tev_stage4;
INSERT_PADDING_WORDS(0x3);
TevStageConfig tev_stage5;
- INSERT_PADDING_WORDS(0x3);
+
+ union {
+ BitField< 0, 8, u32> r;
+ BitField< 8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ BitField<24, 8, u32> a;
+ } tev_combiner_buffer_color;
+
+ INSERT_PADDING_WORDS(0x2);
const std::array<Regs::TevStageConfig,6> GetTevStages() const {
return { tev_stage0, tev_stage1,
@@ -423,9 +461,7 @@ struct Regs {
D24S8 = 3
};
- /*
- * Returns the number of bytes in the specified depth format
- */
+ // Returns the number of bytes in the specified depth format
static u32 BytesPerDepthPixel(DepthFormat format) {
switch (format) {
case DepthFormat::D16:
@@ -440,6 +476,20 @@ struct Regs {
}
}
+ // Returns the number of bits per depth component of the specified depth format
+ static u32 DepthBitsPerPixel(DepthFormat format) {
+ switch (format) {
+ case DepthFormat::D16:
+ return 16;
+ case DepthFormat::D24:
+ case DepthFormat::D24S8:
+ return 24;
+ default:
+ LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
+ UNIMPLEMENTED();
+ }
+ }
+
struct {
// Components are laid out in reverse byte order, most significant bits first.
enum ColorFormat : u32 {
@@ -489,14 +539,14 @@ struct Regs {
INSERT_PADDING_WORDS(0xe0);
- struct {
- enum class Format : u64 {
- BYTE = 0,
- UBYTE = 1,
- SHORT = 2,
- FLOAT = 3,
- };
+ enum class VertexAttributeFormat : u64 {
+ BYTE = 0,
+ UBYTE = 1,
+ SHORT = 2,
+ FLOAT = 3,
+ };
+ struct {
BitField<0, 29, u32> base_address;
u32 GetPhysicalBaseAddress() const {
@@ -505,29 +555,29 @@ struct Regs {
// Descriptor for internal vertex attributes
union {
- BitField< 0, 2, Format> format0; // size of one element
+ BitField< 0, 2, VertexAttributeFormat> format0; // size of one element
BitField< 2, 2, u64> size0; // number of elements minus 1
- BitField< 4, 2, Format> format1;
+ BitField< 4, 2, VertexAttributeFormat> format1;
BitField< 6, 2, u64> size1;
- BitField< 8, 2, Format> format2;
+ BitField< 8, 2, VertexAttributeFormat> format2;
BitField<10, 2, u64> size2;
- BitField<12, 2, Format> format3;
+ BitField<12, 2, VertexAttributeFormat> format3;
BitField<14, 2, u64> size3;
- BitField<16, 2, Format> format4;
+ BitField<16, 2, VertexAttributeFormat> format4;
BitField<18, 2, u64> size4;
- BitField<20, 2, Format> format5;
+ BitField<20, 2, VertexAttributeFormat> format5;
BitField<22, 2, u64> size5;
- BitField<24, 2, Format> format6;
+ BitField<24, 2, VertexAttributeFormat> format6;
BitField<26, 2, u64> size6;
- BitField<28, 2, Format> format7;
+ BitField<28, 2, VertexAttributeFormat> format7;
BitField<30, 2, u64> size7;
- BitField<32, 2, Format> format8;
+ BitField<32, 2, VertexAttributeFormat> format8;
BitField<34, 2, u64> size8;
- BitField<36, 2, Format> format9;
+ BitField<36, 2, VertexAttributeFormat> format9;
BitField<38, 2, u64> size9;
- BitField<40, 2, Format> format10;
+ BitField<40, 2, VertexAttributeFormat> format10;
BitField<42, 2, u64> size10;
- BitField<44, 2, Format> format11;
+ BitField<44, 2, VertexAttributeFormat> format11;
BitField<46, 2, u64> size11;
BitField<48, 12, u64> attribute_mask;
@@ -536,8 +586,8 @@ struct Regs {
BitField<60, 4, u64> num_extra_attributes;
};
- inline Format GetFormat(int n) const {
- Format formats[] = {
+ inline VertexAttributeFormat GetFormat(int n) const {
+ VertexAttributeFormat formats[] = {
format0, format1, format2, format3,
format4, format5, format6, format7,
format8, format9, format10, format11
@@ -555,14 +605,18 @@ struct Regs {
}
inline int GetElementSizeInBytes(int n) const {
- return (GetFormat(n) == Format::FLOAT) ? 4 :
- (GetFormat(n) == Format::SHORT) ? 2 : 1;
+ return (GetFormat(n) == VertexAttributeFormat::FLOAT) ? 4 :
+ (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
}
inline int GetStride(int n) const {
return GetNumElements(n) * GetElementSizeInBytes(n);
}
+ inline bool IsDefaultAttribute(int id) const {
+ return (id >= 12) || (attribute_mask & (1 << id)) != 0;
+ }
+
inline int GetNumTotalAttributes() const {
return (int)num_extra_attributes+1;
}
@@ -625,7 +679,18 @@ struct Regs {
u32 trigger_draw;
u32 trigger_draw_indexed;
- INSERT_PADDING_WORDS(0x2e);
+ INSERT_PADDING_WORDS(0x2);
+
+ // These registers are used to setup the default "fall-back" vertex shader attributes
+ struct {
+ // Index of the current default attribute
+ u32 index;
+
+ // Writing to these registers sets the "current" default attribute.
+ u32 set_value[3];
+ } vs_default_attributes_setup;
+
+ INSERT_PADDING_WORDS(0x28);
enum class TriangleTopology : u32 {
List = 0,
@@ -669,7 +734,7 @@ struct Regs {
BitField<56, 4, u64> attribute14_register;
BitField<60, 4, u64> attribute15_register;
- int GetRegisterForAttribute(int attribute_index) {
+ int GetRegisterForAttribute(int attribute_index) const {
u64 fields[] = {
attribute0_register, attribute1_register, attribute2_register, attribute3_register,
attribute4_register, attribute5_register, attribute6_register, attribute7_register,
@@ -766,8 +831,10 @@ struct Regs {
ADD_FIELD(tev_stage1);
ADD_FIELD(tev_stage2);
ADD_FIELD(tev_stage3);
+ ADD_FIELD(tev_combiner_buffer_input);
ADD_FIELD(tev_stage4);
ADD_FIELD(tev_stage5);
+ ADD_FIELD(tev_combiner_buffer_color);
ADD_FIELD(output_merger);
ADD_FIELD(framebuffer);
ADD_FIELD(vertex_attributes);
@@ -775,6 +842,7 @@ struct Regs {
ADD_FIELD(num_vertices);
ADD_FIELD(trigger_draw);
ADD_FIELD(trigger_draw_indexed);
+ ADD_FIELD(vs_default_attributes_setup);
ADD_FIELD(triangle_topology);
ADD_FIELD(vs_bool_uniforms);
ADD_FIELD(vs_int_uniforms);
@@ -840,8 +908,10 @@ ASSERT_REG_POSITION(tev_stage0, 0xc0);
ASSERT_REG_POSITION(tev_stage1, 0xc8);
ASSERT_REG_POSITION(tev_stage2, 0xd0);
ASSERT_REG_POSITION(tev_stage3, 0xd8);
+ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
ASSERT_REG_POSITION(tev_stage4, 0xf0);
ASSERT_REG_POSITION(tev_stage5, 0xf8);
+ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
ASSERT_REG_POSITION(output_merger, 0x100);
ASSERT_REG_POSITION(framebuffer, 0x110);
ASSERT_REG_POSITION(vertex_attributes, 0x200);
@@ -849,6 +919,7 @@ ASSERT_REG_POSITION(index_array, 0x227);
ASSERT_REG_POSITION(num_vertices, 0x228);
ASSERT_REG_POSITION(trigger_draw, 0x22e);
ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
+ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
ASSERT_REG_POSITION(triangle_topology, 0x25e);
ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
@@ -978,15 +1049,4 @@ union CommandHeader {
BitField<31, 1, u32> group_commands;
};
-// TODO: Ugly, should fix PhysicalToVirtualAddress instead
-inline static u32 PAddrToVAddr(u32 addr) {
- if (addr >= Memory::VRAM_PADDR && addr < Memory::VRAM_PADDR + Memory::VRAM_SIZE) {
- return addr - Memory::VRAM_PADDR + Memory::VRAM_VADDR;
- } else if (addr >= Memory::FCRAM_PADDR && addr < Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
- return addr - Memory::FCRAM_PADDR + Memory::HEAP_LINEAR_VADDR;
- } else {
- return 0;
- }
-}
-
} // namespace
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index dd46f0ec..59eff48f 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -6,8 +6,11 @@
#include "common/common_types.h"
#include "common/math_util.h"
+#include "common/profiler.h"
#include "core/hw/gpu.h"
+#include "core/memory.h"
+
#include "debug_utils/debug_utils.h"
#include "math.h"
#include "color.h"
@@ -30,7 +33,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
const u32 coarse_y = y & ~7;
u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value()));
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel;
- u8* dst_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + dst_offset;
+ u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
switch (registers.framebuffer.color_format) {
case registers.framebuffer.RGBA8:
@@ -67,7 +70,7 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
const u32 coarse_y = y & ~7;
u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value()));
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel;
- u8* src_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + src_offset;
+ u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
switch (registers.framebuffer.color_format) {
case registers.framebuffer.RGBA8:
@@ -90,12 +93,12 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
UNIMPLEMENTED();
}
- return {};
+ return {0, 0, 0, 0};
}
static u32 GetDepth(int x, int y) {
const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress();
- u8* depth_buffer = Memory::GetPointer(PAddrToVAddr(addr));
+ u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = (registers.framebuffer.height - y);
@@ -122,7 +125,7 @@ static u32 GetDepth(int x, int y) {
static void SetDepth(int x, int y, u32 value) {
const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress();
- u8* depth_buffer = Memory::GetPointer(PAddrToVAddr(addr));
+ u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = (registers.framebuffer.height - y);
@@ -186,6 +189,8 @@ static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
return Math::Cross(vec1, vec2).z;
};
+static Common::Profiling::TimingCategory rasterization_category("Rasterization");
+
/**
* Helper function for ProcessTriangle with the "reversed" flag to allow for implementing
* culling via recursion.
@@ -195,6 +200,8 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
const VertexShader::OutputVertex& v2,
bool reversed = false)
{
+ Common::Profiling::ScopeTimer timer(rasterization_category);
+
// vertex positions in rasterizer coordinates
static auto FloatToFix = [](float24 flt) {
// TODO: Rounding here is necessary to prevent garbage pixels at
@@ -342,10 +349,10 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
case Regs::TextureConfig::MirroredRepeat:
{
- int coord = (int)((unsigned)val % (2 * size));
+ unsigned int coord = ((unsigned)val % (2 * size));
if (coord >= size)
coord = 2 * size - 1 - coord;
- return coord;
+ return (int)coord;
}
default:
@@ -361,7 +368,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
- u8* texture_data = Memory::GetPointer(PAddrToVAddr(texture.config.GetPhysicalAddress()));
+ u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
@@ -376,7 +383,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
// with some basic arithmetic. Alpha combiners can be configured separately but work
// analogously.
Math::Vec4<u8> combiner_output;
- for (const auto& tev_stage : tev_stages) {
+ Math::Vec4<u8> combiner_buffer = {
+ registers.tev_combiner_buffer_color.r, registers.tev_combiner_buffer_color.g,
+ registers.tev_combiner_buffer_color.b, registers.tev_combiner_buffer_color.a
+ };
+
+ for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
+ const auto& tev_stage = tev_stages[tev_stage_index];
using Source = Regs::TevStageConfig::Source;
using ColorModifier = Regs::TevStageConfig::ColorModifier;
using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
@@ -398,6 +411,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
case Source::Texture2:
return texture_color[2];
+ case Source::PreviousBuffer:
+ return combiner_buffer;
+
case Source::Constant:
return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b, tev_stage.const_a};
@@ -407,7 +423,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
default:
LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source);
UNIMPLEMENTED();
- return {};
+ return {0, 0, 0, 0};
}
};
@@ -490,6 +506,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
return result.Cast<u8>();
}
+ case Operation::AddSigned:
+ {
+ // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
+ auto result = input[0].Cast<int>() + input[1].Cast<int>() - Math::MakeVec<int>(128, 128, 128);
+ result.r() = MathUtil::Clamp<int>(result.r(), 0, 255);
+ result.g() = MathUtil::Clamp<int>(result.g(), 0, 255);
+ result.b() = MathUtil::Clamp<int>(result.b(), 0, 255);
+ return result.Cast<u8>();
+ }
+
case Operation::Lerp:
return ((input[0] * input[2] + input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) / 255).Cast<u8>();
@@ -524,7 +550,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
default:
LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
UNIMPLEMENTED();
- return {};
+ return {0, 0, 0};
}
};
@@ -578,7 +604,20 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
};
auto alpha_output = AlphaCombine(tev_stage.alpha_op, alpha_result);
- combiner_output = Math::MakeVec(color_output, alpha_output);
+ combiner_output[0] = std::min((unsigned)255, color_output.r() * tev_stage.GetColorMultiplier());
+ combiner_output[1] = std::min((unsigned)255, color_output.g() * tev_stage.GetColorMultiplier());
+ combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier());
+ combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier());
+
+ if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) {
+ combiner_buffer.r() = combiner_output.r();
+ combiner_buffer.g() = combiner_output.g();
+ combiner_buffer.b() = combiner_output.b();
+ }
+
+ if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) {
+ combiner_buffer.a() = combiner_output.a();
+ }
}
if (registers.output_merger.alpha_test.enable) {
@@ -624,9 +663,10 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
// TODO: Does depth indeed only get written even if depth testing is enabled?
if (registers.output_merger.depth_test_enable) {
- u16 z = (u16)((v0.screenpos[2].ToFloat32() * w0 +
- v1.screenpos[2].ToFloat32() * w1 +
- v2.screenpos[2].ToFloat32() * w2) * 65535.f / wsum);
+ unsigned num_bits = Pica::Regs::DepthBitsPerPixel(registers.framebuffer.depth_format);
+ u32 z = (u32)((v0.screenpos[2].ToFloat32() * w0 +
+ v1.screenpos[2].ToFloat32() * w1 +
+ v2.screenpos[2].ToFloat32() * w2) * ((1 << num_bits) - 1) / wsum);
u32 ref_z = GetDepth(x >> 4, y >> 4);
bool pass = false;
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index b77f29c1..b6240953 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -4,7 +4,7 @@
#pragma once
-#include "common/common.h"
+#include "common/common_types.h"
class RendererBase : NonCopyable {
public:
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 4273a177..71ceb021 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -5,9 +5,11 @@
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
+#include "core/settings.h"
#include "common/emu_window.h"
+#include "common/logging/log.h"
#include "common/profiler_reporting.h"
#include "video_core/video_core.h"
@@ -117,15 +119,15 @@ void RendererOpenGL::SwapBuffers() {
void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
const TextureInfo& texture) {
- const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress(
- framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2);
+ const PAddr framebuffer_addr = framebuffer.active_fb == 0 ?
+ framebuffer.address_left1 : framebuffer.address_left2;
LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
framebuffer.stride * framebuffer.height,
- framebuffer_vaddr, (int)framebuffer.width,
+ framebuffer_addr, (int)framebuffer.width,
(int)framebuffer.height, (int)framebuffer.format);
- const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
+ const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr);
int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
size_t pixel_stride = framebuffer.stride / bpp;
@@ -172,7 +174,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
* Initializes the OpenGL state and creates persistent objects.
*/
void RendererOpenGL::InitOpenGLObjects() {
- glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
+ glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);
glDisable(GL_DEPTH_TEST);
// Link shaders and get variable locations
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index bda793fa..ffb3e73a 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -13,10 +13,10 @@ namespace VideoCore {
/// Structure for the TGA texture format (for dumping)
struct TGAHeader {
char idlength;
- char colourmaptype;
+ char colormaptype;
char datatypecode;
- short int colourmaporigin;
- short int colourmaplength;
+ short int colormaporigin;
+ short int colormaplength;
short int x_origin;
short int y_origin;
short width;
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index e8d86517..981d1a35 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -8,10 +8,9 @@
#include <common/file_util.h>
-#include <core/mem_map.h>
-
#include <nihstro/shader_bytecode.h>
+#include "common/profiler.h"
#include "pica.h"
#include "vertex_shader.h"
@@ -35,6 +34,8 @@ static struct {
std::array<Math::Vec4<u8>,4> i;
} shader_uniforms;
+static Math::Vec4<float24> vs_default_attributes[16];
+
// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to!
// For now, we just keep these local arrays around.
static std::array<u32, 1024> shader_memory;
@@ -60,6 +61,10 @@ Math::Vec4<u8>& GetIntUniform(u32 index) {
return shader_uniforms.i[index];
}
+Math::Vec4<float24>& GetDefaultAttribute(u32 index) {
+ return vs_default_attributes[index];
+}
+
const std::array<u32, 1024>& GetShaderBinary() {
return shader_memory;
}
@@ -229,6 +234,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
break;
}
+ case OpCode::Id::FLR:
+ for (int i = 0; i < 4; ++i) {
+ if (!swizzle.DestComponentEnabled(i))
+ continue;
+
+ dest[i] = float24::FromFloat32(std::floor(src1[i].ToFloat32()));
+ }
+ break;
+
case OpCode::Id::MAX:
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
@@ -360,12 +374,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
case OpCode::Type::MultiplyAdd:
{
- if (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) {
+ if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
+ (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id];
- const float24* src1_ = LookupSourceRegister(instr.mad.src1);
- const float24* src2_ = LookupSourceRegister(instr.mad.src2);
- const float24* src3_ = LookupSourceRegister(instr.mad.src3);
+ bool is_inverted = (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI);
+
+ const float24* src1_ = LookupSourceRegister(instr.mad.GetSrc1(is_inverted));
+ const float24* src2_ = LookupSourceRegister(instr.mad.GetSrc2(is_inverted));
+ const float24* src3_ = LookupSourceRegister(instr.mad.GetSrc3(is_inverted));
const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
@@ -556,7 +573,11 @@ static void ProcessShaderCode(VertexShaderState& state) {
}
}
+static Common::Profiling::TimingCategory shader_category("Vertex Shader");
+
OutputVertex RunShader(const InputVertex& input, int num_attributes) {
+ Common::Profiling::ScopeTimer timer(shader_category);
+
VertexShaderState state;
const u32* main = &shader_memory[registers.vs_main_offset];
@@ -568,22 +589,23 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
const auto& attribute_register_map = registers.vs_input_register_map;
float24 dummy_register;
boost::fill(state.input_register_table, &dummy_register);
- if(num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
- if(num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
- if(num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;
- if(num_attributes > 3) state.input_register_table[attribute_register_map.attribute3_register] = &input.attr[3].x;
- if(num_attributes > 4) state.input_register_table[attribute_register_map.attribute4_register] = &input.attr[4].x;
- if(num_attributes > 5) state.input_register_table[attribute_register_map.attribute5_register] = &input.attr[5].x;
- if(num_attributes > 6) state.input_register_table[attribute_register_map.attribute6_register] = &input.attr[6].x;
- if(num_attributes > 7) state.input_register_table[attribute_register_map.attribute7_register] = &input.attr[7].x;
- if(num_attributes > 8) state.input_register_table[attribute_register_map.attribute8_register] = &input.attr[8].x;
- if(num_attributes > 9) state.input_register_table[attribute_register_map.attribute9_register] = &input.attr[9].x;
- if(num_attributes > 10) state.input_register_table[attribute_register_map.attribute10_register] = &input.attr[10].x;
- if(num_attributes > 11) state.input_register_table[attribute_register_map.attribute11_register] = &input.attr[11].x;
- if(num_attributes > 12) state.input_register_table[attribute_register_map.attribute12_register] = &input.attr[12].x;
- if(num_attributes > 13) state.input_register_table[attribute_register_map.attribute13_register] = &input.attr[13].x;
- if(num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x;
- if(num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x;
+
+ if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
+ if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
+ if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;
+ if (num_attributes > 3) state.input_register_table[attribute_register_map.attribute3_register] = &input.attr[3].x;
+ if (num_attributes > 4) state.input_register_table[attribute_register_map.attribute4_register] = &input.attr[4].x;
+ if (num_attributes > 5) state.input_register_table[attribute_register_map.attribute5_register] = &input.attr[5].x;
+ if (num_attributes > 6) state.input_register_table[attribute_register_map.attribute6_register] = &input.attr[6].x;
+ if (num_attributes > 7) state.input_register_table[attribute_register_map.attribute7_register] = &input.attr[7].x;
+ if (num_attributes > 8) state.input_register_table[attribute_register_map.attribute8_register] = &input.attr[8].x;
+ if (num_attributes > 9) state.input_register_table[attribute_register_map.attribute9_register] = &input.attr[9].x;
+ if (num_attributes > 10) state.input_register_table[attribute_register_map.attribute10_register] = &input.attr[10].x;
+ if (num_attributes > 11) state.input_register_table[attribute_register_map.attribute11_register] = &input.attr[11].x;
+ if (num_attributes > 12) state.input_register_table[attribute_register_map.attribute12_register] = &input.attr[12].x;
+ if (num_attributes > 13) state.input_register_table[attribute_register_map.attribute13_register] = &input.attr[13].x;
+ if (num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x;
+ if (num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x;
state.conditional_code[0] = false;
state.conditional_code[1] = false;
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 3a68a340..c26709bb 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -74,6 +74,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes);
Math::Vec4<float24>& GetFloatUniform(u32 index);
bool& GetBoolUniform(u32 index);
Math::Vec4<u8>& GetIntUniform(u32 index);
+Math::Vec4<float24>& GetDefaultAttribute(u32 index);
const std::array<u32, 1024>& GetShaderBinary();
const std::array<u32, 1024>& GetSwizzlePatterns();
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index b9d4ede3..42e3bdd5 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/logging/log.h"
#include "common/emu_window.h"
#include "core/core.h"
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 1b51d39b..f885bec2 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,7 +4,6 @@
#pragma once
-#include "common/common.h"
#include "common/emu_window.h"
#include "renderer_base.h"