From 63e46abdb8764bc97e91bae862c8d461e61b1965 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 8 Apr 2014 19:25:03 -0400 Subject: got rid of 'src' folders in each sub-project --- src/citra/citra.cpp | 71 + src/citra/citra.h | 35 + src/citra/emu_window/emu_window_glfw.cpp | 98 + src/citra/emu_window/emu_window_glfw.h | 53 + src/citra/src/citra.cpp | 71 - src/citra/src/citra.h | 35 - src/citra/src/emu_window/emu_window_glfw.cpp | 98 - src/citra/src/emu_window/emu_window_glfw.h | 53 - src/citra/src/version.h | 6 - src/citra/version.h | 6 + src/citra_qt/bootmanager.cpp | 206 + src/citra_qt/bootmanager.hxx | 112 + src/citra_qt/callstack.cpp | 36 + src/citra_qt/callstack.hxx | 20 + src/citra_qt/callstack.ui | 36 + src/citra_qt/config/controller_config.cpp | 91 + src/citra_qt/config/controller_config.hxx | 52 + src/citra_qt/config/controller_config.ui | 308 + src/citra_qt/config/controller_config_util.cpp | 121 + src/citra_qt/config/controller_config_util.hxx | 78 + src/citra_qt/config/ui_controller_config.h | 222 + src/citra_qt/cpu_regs.cpp | 63 + src/citra_qt/cpu_regs.hxx | 27 + src/citra_qt/cpu_regs.ui | 40 + src/citra_qt/disasm.cpp | 135 + src/citra_qt/disasm.hxx | 42 + src/citra_qt/disasm.ui | 78 + src/citra_qt/hotkeys.cpp | 111 + src/citra_qt/hotkeys.hxx | 50 + src/citra_qt/hotkeys.ui | 89 + src/citra_qt/main.cpp | 230 + src/citra_qt/main.hxx | 51 + src/citra_qt/main.ui | 168 + src/citra_qt/ramview.cpp | 13 + src/citra_qt/ramview.hxx | 12 + src/citra_qt/src/bootmanager.cpp | 206 - src/citra_qt/src/bootmanager.hxx | 112 - src/citra_qt/src/callstack.cpp | 36 - src/citra_qt/src/callstack.hxx | 20 - src/citra_qt/src/callstack.ui | 36 - src/citra_qt/src/config/controller_config.cpp | 91 - src/citra_qt/src/config/controller_config.hxx | 52 - src/citra_qt/src/config/controller_config.ui | 308 - src/citra_qt/src/config/controller_config_util.cpp | 121 - src/citra_qt/src/config/controller_config_util.hxx | 78 - src/citra_qt/src/config/ui_controller_config.h | 222 - src/citra_qt/src/cpu_regs.cpp | 63 - src/citra_qt/src/cpu_regs.hxx | 27 - src/citra_qt/src/cpu_regs.ui | 40 - src/citra_qt/src/disasm.cpp | 135 - src/citra_qt/src/disasm.hxx | 42 - src/citra_qt/src/disasm.ui | 78 - src/citra_qt/src/hotkeys.cpp | 111 - src/citra_qt/src/hotkeys.hxx | 50 - src/citra_qt/src/hotkeys.ui | 89 - src/citra_qt/src/main.cpp | 230 - src/citra_qt/src/main.hxx | 51 - src/citra_qt/src/main.ui | 168 - src/citra_qt/src/ramview.cpp | 13 - src/citra_qt/src/ramview.hxx | 12 - src/citra_qt/src/ui_callstack.h | 68 - src/citra_qt/src/ui_cpu_regs.h | 69 - src/citra_qt/src/ui_disasm.h | 112 - src/citra_qt/src/ui_gfx_fifo_player.h | 209 - src/citra_qt/src/ui_hotkeys.h | 77 - src/citra_qt/src/ui_image_info.h | 154 - src/citra_qt/src/ui_main.h | 148 - src/citra_qt/src/ui_welcome_wizard.h | 124 - src/citra_qt/src/version.h | 7 - src/citra_qt/ui_callstack.h | 68 + src/citra_qt/ui_cpu_regs.h | 69 + src/citra_qt/ui_disasm.h | 112 + src/citra_qt/ui_gfx_fifo_player.h | 209 + src/citra_qt/ui_hotkeys.h | 77 + src/citra_qt/ui_image_info.h | 154 + src/citra_qt/ui_main.h | 148 + src/citra_qt/ui_welcome_wizard.h | 124 + src/citra_qt/version.h | 7 + src/common/atomic.h | 19 + src/common/atomic_gcc.h | 113 + src/common/atomic_win32.h | 72 + src/common/break_points.cpp | 203 + src/common/break_points.h | 102 + src/common/chunk_file.h | 874 +++ src/common/common.h | 171 + src/common/common_funcs.h | 245 + src/common/common_paths.h | 79 + src/common/common_types.h | 125 + src/common/console_listener.cpp | 337 + src/common/console_listener.h | 41 + src/common/cpu_detect.h | 81 + src/common/debug_interface.h | 39 + src/common/emu_window.h | 102 + src/common/extended_trace.cpp | 433 ++ src/common/extended_trace.h | 53 + src/common/fifo_queue.h | 115 + src/common/file_search.cpp | 106 + src/common/file_search.h | 28 + src/common/file_util.cpp | 910 +++ src/common/file_util.h | 224 + src/common/fixed_size_queue.h | 75 + src/common/hash.cpp | 520 ++ src/common/hash.h | 20 + src/common/linear_disk_cache.h | 191 + src/common/log.h | 155 + src/common/log_manager.cpp | 200 + src/common/log_manager.h | 169 + src/common/math_util.cpp | 212 + src/common/math_util.h | 200 + src/common/mem_arena.cpp | 477 ++ src/common/mem_arena.h | 81 + src/common/memory_util.cpp | 197 + src/common/memory_util.h | 25 + src/common/misc.cpp | 37 + src/common/msg_handler.cpp | 107 + src/common/msg_handler.h | 73 + src/common/platform.h | 142 + src/common/scm_rev.h | 4 + src/common/src/atomic.h | 19 - src/common/src/atomic_gcc.h | 113 - src/common/src/atomic_win32.h | 72 - src/common/src/break_points.cpp | 203 - src/common/src/break_points.h | 102 - src/common/src/chunk_file.h | 874 --- src/common/src/common.h | 171 - src/common/src/common_funcs.h | 245 - src/common/src/common_paths.h | 79 - src/common/src/common_types.h | 125 - src/common/src/console_listener.cpp | 337 - src/common/src/console_listener.h | 41 - src/common/src/cpu_detect.h | 81 - src/common/src/debug_interface.h | 39 - src/common/src/emu_window.h | 102 - src/common/src/extended_trace.cpp | 433 -- src/common/src/extended_trace.h | 53 - src/common/src/fifo_queue.h | 115 - src/common/src/file_search.cpp | 106 - src/common/src/file_search.h | 28 - src/common/src/file_util.cpp | 910 --- src/common/src/file_util.h | 224 - src/common/src/fixed_size_queue.h | 75 - src/common/src/hash.cpp | 520 -- src/common/src/hash.h | 20 - src/common/src/linear_disk_cache.h | 191 - src/common/src/log.h | 155 - src/common/src/log_manager.cpp | 200 - src/common/src/log_manager.h | 169 - src/common/src/math_util.cpp | 212 - src/common/src/math_util.h | 200 - src/common/src/mem_arena.cpp | 477 -- src/common/src/mem_arena.h | 81 - src/common/src/memory_util.cpp | 197 - src/common/src/memory_util.h | 25 - src/common/src/misc.cpp | 37 - src/common/src/msg_handler.cpp | 107 - src/common/src/msg_handler.h | 73 - src/common/src/platform.h | 142 - src/common/src/scm_rev.h | 4 - src/common/src/std_condition_variable.h | 170 - src/common/src/std_mutex.h | 365 -- src/common/src/std_thread.h | 317 - src/common/src/string_util.cpp | 531 -- src/common/src/string_util.h | 111 - src/common/src/swap.h | 535 -- src/common/src/thread.cpp | 133 - src/common/src/thread.h | 156 - src/common/src/thunk.h | 46 - src/common/src/timer.cpp | 226 - src/common/src/timer.h | 46 - src/common/src/utf8.cpp | 463 -- src/common/src/utf8.h | 67 - src/common/src/version.cpp | 45 - src/common/std_condition_variable.h | 170 + src/common/std_mutex.h | 365 ++ src/common/std_thread.h | 317 + src/common/string_util.cpp | 531 ++ src/common/string_util.h | 111 + src/common/swap.h | 535 ++ src/common/thread.cpp | 133 + src/common/thread.h | 156 + src/common/thunk.h | 46 + src/common/timer.cpp | 226 + src/common/timer.h | 46 + src/common/utf8.cpp | 463 ++ src/common/utf8.h | 67 + src/common/version.cpp | 45 + src/core/arm/arm_interface.h | 68 + src/core/arm/disassembler/arm_disasm.cpp | 1003 +++ src/core/arm/disassembler/arm_disasm.h | 146 + src/core/arm/interpreter/arm_interpreter.cpp | 86 + src/core/arm/interpreter/arm_interpreter.h | 57 + src/core/arm/interpreter/arm_regformat.h | 103 + src/core/arm/interpreter/armcpu.h | 83 + src/core/arm/interpreter/armdefs.h | 934 +++ src/core/arm/interpreter/armemu.cpp | 6631 ++++++++++++++++++++ src/core/arm/interpreter/armemu.h | 659 ++ src/core/arm/interpreter/arminit.cpp | 579 ++ src/core/arm/interpreter/armmmu.cpp | 238 + src/core/arm/interpreter/armmmu.h | 254 + src/core/arm/interpreter/armos.cpp | 742 +++ src/core/arm/interpreter/armos.h | 138 + src/core/arm/interpreter/armsupp.cpp | 954 +++ src/core/arm/interpreter/armvirt.cpp | 680 ++ src/core/arm/interpreter/skyeye_defs.h | 111 + src/core/arm/interpreter/thumbemu.cpp | 513 ++ src/core/arm/mmu/arm1176jzf_s_mmu.cpp | 1132 ++++ src/core/arm/mmu/arm1176jzf_s_mmu.h | 37 + src/core/arm/mmu/cache.h | 168 + src/core/arm/mmu/rb.h | 55 + src/core/arm/mmu/tlb.h | 94 + src/core/arm/mmu/wb.h | 63 + src/core/core.cpp | 58 + src/core/core.h | 40 + src/core/core_timing.cpp | 623 ++ src/core/core_timing.h | 109 + src/core/elf/elf_reader.cpp | 239 + src/core/elf/elf_reader.h | 75 + src/core/elf/elf_types.h | 281 + src/core/file_sys/directory_file_system.cpp | 671 ++ src/core/file_sys/directory_file_system.h | 158 + src/core/file_sys/file_sys.h | 138 + src/core/file_sys/meta_file_system.cpp | 520 ++ src/core/file_sys/meta_file_system.h | 109 + src/core/hw/hw.cpp | 49 + src/core/hw/hw.h | 26 + src/core/hw/hw_lcd.cpp | 45 + src/core/hw/hw_lcd.h | 44 + src/core/loader.cpp | 168 + src/core/loader.h | 51 + src/core/mem_map.cpp | 83 + src/core/mem_map.h | 73 + src/core/mem_map_funcs.cpp | 198 + src/core/src/arm/arm_interface.h | 68 - src/core/src/arm/disassembler/arm_disasm.cpp | 1003 --- src/core/src/arm/disassembler/arm_disasm.h | 146 - src/core/src/arm/interpreter/arm_interpreter.cpp | 86 - src/core/src/arm/interpreter/arm_interpreter.h | 57 - src/core/src/arm/interpreter/arm_regformat.h | 103 - src/core/src/arm/interpreter/armcpu.h | 83 - src/core/src/arm/interpreter/armdefs.h | 934 --- src/core/src/arm/interpreter/armemu.cpp | 6631 -------------------- src/core/src/arm/interpreter/armemu.h | 659 -- src/core/src/arm/interpreter/arminit.cpp | 579 -- src/core/src/arm/interpreter/armmmu.cpp | 238 - src/core/src/arm/interpreter/armmmu.h | 254 - src/core/src/arm/interpreter/armos.cpp | 742 --- src/core/src/arm/interpreter/armos.h | 138 - src/core/src/arm/interpreter/armsupp.cpp | 954 --- src/core/src/arm/interpreter/armvirt.cpp | 680 -- src/core/src/arm/interpreter/skyeye_defs.h | 111 - src/core/src/arm/interpreter/thumbemu.cpp | 513 -- src/core/src/arm/mmu/arm1176jzf_s_mmu.cpp | 1132 ---- src/core/src/arm/mmu/arm1176jzf_s_mmu.h | 37 - src/core/src/arm/mmu/cache.h | 168 - src/core/src/arm/mmu/rb.h | 55 - src/core/src/arm/mmu/tlb.h | 94 - src/core/src/arm/mmu/wb.h | 63 - src/core/src/core.cpp | 58 - src/core/src/core.h | 40 - src/core/src/core_timing.cpp | 623 -- src/core/src/core_timing.h | 109 - src/core/src/elf/elf_reader.cpp | 239 - src/core/src/elf/elf_reader.h | 75 - src/core/src/elf/elf_types.h | 281 - src/core/src/file_sys/directory_file_system.cpp | 671 -- src/core/src/file_sys/directory_file_system.h | 158 - src/core/src/file_sys/file_sys.h | 138 - src/core/src/file_sys/meta_file_system.cpp | 520 -- src/core/src/file_sys/meta_file_system.h | 109 - src/core/src/hw/hw.cpp | 49 - src/core/src/hw/hw.h | 26 - src/core/src/hw/hw_lcd.cpp | 45 - src/core/src/hw/hw_lcd.h | 44 - src/core/src/loader.cpp | 168 - src/core/src/loader.h | 51 - src/core/src/mem_map.cpp | 83 - src/core/src/mem_map.h | 73 - src/core/src/mem_map_funcs.cpp | 198 - src/core/src/system.cpp | 42 - src/core/src/system.h | 35 - src/core/system.cpp | 42 + src/core/system.h | 35 + src/video_core/renderer_base.h | 58 + src/video_core/renderer_opengl/renderer_opengl.cpp | 279 + src/video_core/renderer_opengl/renderer_opengl.h | 91 + src/video_core/src/renderer_base.h | 58 - .../src/renderer_opengl/renderer_opengl.cpp | 279 - .../src/renderer_opengl/renderer_opengl.h | 91 - src/video_core/src/utils.cpp | 46 - src/video_core/src/utils.h | 64 - src/video_core/src/video_core.cpp | 49 - src/video_core/src/video_core.h | 39 - src/video_core/utils.cpp | 46 + src/video_core/utils.h | 64 + src/video_core/video_core.cpp | 49 + src/video_core/video_core.h | 39 + 296 files changed, 34179 insertions(+), 34179 deletions(-) create mode 100644 src/citra/citra.cpp create mode 100644 src/citra/citra.h create mode 100644 src/citra/emu_window/emu_window_glfw.cpp create mode 100644 src/citra/emu_window/emu_window_glfw.h delete mode 100644 src/citra/src/citra.cpp delete mode 100644 src/citra/src/citra.h delete mode 100644 src/citra/src/emu_window/emu_window_glfw.cpp delete mode 100644 src/citra/src/emu_window/emu_window_glfw.h delete mode 100644 src/citra/src/version.h create mode 100644 src/citra/version.h create mode 100644 src/citra_qt/bootmanager.cpp create mode 100644 src/citra_qt/bootmanager.hxx create mode 100644 src/citra_qt/callstack.cpp create mode 100644 src/citra_qt/callstack.hxx create mode 100644 src/citra_qt/callstack.ui create mode 100644 src/citra_qt/config/controller_config.cpp create mode 100644 src/citra_qt/config/controller_config.hxx create mode 100644 src/citra_qt/config/controller_config.ui create mode 100644 src/citra_qt/config/controller_config_util.cpp create mode 100644 src/citra_qt/config/controller_config_util.hxx create mode 100644 src/citra_qt/config/ui_controller_config.h create mode 100644 src/citra_qt/cpu_regs.cpp create mode 100644 src/citra_qt/cpu_regs.hxx create mode 100644 src/citra_qt/cpu_regs.ui create mode 100644 src/citra_qt/disasm.cpp create mode 100644 src/citra_qt/disasm.hxx create mode 100644 src/citra_qt/disasm.ui create mode 100644 src/citra_qt/hotkeys.cpp create mode 100644 src/citra_qt/hotkeys.hxx create mode 100644 src/citra_qt/hotkeys.ui create mode 100644 src/citra_qt/main.cpp create mode 100644 src/citra_qt/main.hxx create mode 100644 src/citra_qt/main.ui create mode 100644 src/citra_qt/ramview.cpp create mode 100644 src/citra_qt/ramview.hxx delete mode 100644 src/citra_qt/src/bootmanager.cpp delete mode 100644 src/citra_qt/src/bootmanager.hxx delete mode 100644 src/citra_qt/src/callstack.cpp delete mode 100644 src/citra_qt/src/callstack.hxx delete mode 100644 src/citra_qt/src/callstack.ui delete mode 100644 src/citra_qt/src/config/controller_config.cpp delete mode 100644 src/citra_qt/src/config/controller_config.hxx delete mode 100644 src/citra_qt/src/config/controller_config.ui delete mode 100644 src/citra_qt/src/config/controller_config_util.cpp delete mode 100644 src/citra_qt/src/config/controller_config_util.hxx delete mode 100644 src/citra_qt/src/config/ui_controller_config.h delete mode 100644 src/citra_qt/src/cpu_regs.cpp delete mode 100644 src/citra_qt/src/cpu_regs.hxx delete mode 100644 src/citra_qt/src/cpu_regs.ui delete mode 100644 src/citra_qt/src/disasm.cpp delete mode 100644 src/citra_qt/src/disasm.hxx delete mode 100644 src/citra_qt/src/disasm.ui delete mode 100644 src/citra_qt/src/hotkeys.cpp delete mode 100644 src/citra_qt/src/hotkeys.hxx delete mode 100644 src/citra_qt/src/hotkeys.ui delete mode 100644 src/citra_qt/src/main.cpp delete mode 100644 src/citra_qt/src/main.hxx delete mode 100644 src/citra_qt/src/main.ui delete mode 100644 src/citra_qt/src/ramview.cpp delete mode 100644 src/citra_qt/src/ramview.hxx delete mode 100644 src/citra_qt/src/ui_callstack.h delete mode 100644 src/citra_qt/src/ui_cpu_regs.h delete mode 100644 src/citra_qt/src/ui_disasm.h delete mode 100644 src/citra_qt/src/ui_gfx_fifo_player.h delete mode 100644 src/citra_qt/src/ui_hotkeys.h delete mode 100644 src/citra_qt/src/ui_image_info.h delete mode 100644 src/citra_qt/src/ui_main.h delete mode 100644 src/citra_qt/src/ui_welcome_wizard.h delete mode 100644 src/citra_qt/src/version.h create mode 100644 src/citra_qt/ui_callstack.h create mode 100644 src/citra_qt/ui_cpu_regs.h create mode 100644 src/citra_qt/ui_disasm.h create mode 100644 src/citra_qt/ui_gfx_fifo_player.h create mode 100644 src/citra_qt/ui_hotkeys.h create mode 100644 src/citra_qt/ui_image_info.h create mode 100644 src/citra_qt/ui_main.h create mode 100644 src/citra_qt/ui_welcome_wizard.h create mode 100644 src/citra_qt/version.h create mode 100644 src/common/atomic.h create mode 100644 src/common/atomic_gcc.h create mode 100644 src/common/atomic_win32.h create mode 100644 src/common/break_points.cpp create mode 100644 src/common/break_points.h create mode 100644 src/common/chunk_file.h create mode 100644 src/common/common.h create mode 100644 src/common/common_funcs.h create mode 100644 src/common/common_paths.h create mode 100644 src/common/common_types.h create mode 100644 src/common/console_listener.cpp create mode 100644 src/common/console_listener.h create mode 100644 src/common/cpu_detect.h create mode 100644 src/common/debug_interface.h create mode 100644 src/common/emu_window.h create mode 100644 src/common/extended_trace.cpp create mode 100644 src/common/extended_trace.h create mode 100644 src/common/fifo_queue.h create mode 100644 src/common/file_search.cpp create mode 100644 src/common/file_search.h create mode 100644 src/common/file_util.cpp create mode 100644 src/common/file_util.h create mode 100644 src/common/fixed_size_queue.h create mode 100644 src/common/hash.cpp create mode 100644 src/common/hash.h create mode 100644 src/common/linear_disk_cache.h create mode 100644 src/common/log.h create mode 100644 src/common/log_manager.cpp create mode 100644 src/common/log_manager.h create mode 100644 src/common/math_util.cpp create mode 100644 src/common/math_util.h create mode 100644 src/common/mem_arena.cpp create mode 100644 src/common/mem_arena.h create mode 100644 src/common/memory_util.cpp create mode 100644 src/common/memory_util.h create mode 100644 src/common/misc.cpp create mode 100644 src/common/msg_handler.cpp create mode 100644 src/common/msg_handler.h create mode 100644 src/common/platform.h create mode 100644 src/common/scm_rev.h delete mode 100644 src/common/src/atomic.h delete mode 100644 src/common/src/atomic_gcc.h delete mode 100644 src/common/src/atomic_win32.h delete mode 100644 src/common/src/break_points.cpp delete mode 100644 src/common/src/break_points.h delete mode 100644 src/common/src/chunk_file.h delete mode 100644 src/common/src/common.h delete mode 100644 src/common/src/common_funcs.h delete mode 100644 src/common/src/common_paths.h delete mode 100644 src/common/src/common_types.h delete mode 100644 src/common/src/console_listener.cpp delete mode 100644 src/common/src/console_listener.h delete mode 100644 src/common/src/cpu_detect.h delete mode 100644 src/common/src/debug_interface.h delete mode 100644 src/common/src/emu_window.h delete mode 100644 src/common/src/extended_trace.cpp delete mode 100644 src/common/src/extended_trace.h delete mode 100644 src/common/src/fifo_queue.h delete mode 100644 src/common/src/file_search.cpp delete mode 100644 src/common/src/file_search.h delete mode 100644 src/common/src/file_util.cpp delete mode 100644 src/common/src/file_util.h delete mode 100644 src/common/src/fixed_size_queue.h delete mode 100644 src/common/src/hash.cpp delete mode 100644 src/common/src/hash.h delete mode 100644 src/common/src/linear_disk_cache.h delete mode 100644 src/common/src/log.h delete mode 100644 src/common/src/log_manager.cpp delete mode 100644 src/common/src/log_manager.h delete mode 100644 src/common/src/math_util.cpp delete mode 100644 src/common/src/math_util.h delete mode 100644 src/common/src/mem_arena.cpp delete mode 100644 src/common/src/mem_arena.h delete mode 100644 src/common/src/memory_util.cpp delete mode 100644 src/common/src/memory_util.h delete mode 100644 src/common/src/misc.cpp delete mode 100644 src/common/src/msg_handler.cpp delete mode 100644 src/common/src/msg_handler.h delete mode 100644 src/common/src/platform.h delete mode 100644 src/common/src/scm_rev.h delete mode 100644 src/common/src/std_condition_variable.h delete mode 100644 src/common/src/std_mutex.h delete mode 100644 src/common/src/std_thread.h delete mode 100644 src/common/src/string_util.cpp delete mode 100644 src/common/src/string_util.h delete mode 100644 src/common/src/swap.h delete mode 100644 src/common/src/thread.cpp delete mode 100644 src/common/src/thread.h delete mode 100644 src/common/src/thunk.h delete mode 100644 src/common/src/timer.cpp delete mode 100644 src/common/src/timer.h delete mode 100644 src/common/src/utf8.cpp delete mode 100644 src/common/src/utf8.h delete mode 100644 src/common/src/version.cpp create mode 100644 src/common/std_condition_variable.h create mode 100644 src/common/std_mutex.h create mode 100644 src/common/std_thread.h create mode 100644 src/common/string_util.cpp create mode 100644 src/common/string_util.h create mode 100644 src/common/swap.h create mode 100644 src/common/thread.cpp create mode 100644 src/common/thread.h create mode 100644 src/common/thunk.h create mode 100644 src/common/timer.cpp create mode 100644 src/common/timer.h create mode 100644 src/common/utf8.cpp create mode 100644 src/common/utf8.h create mode 100644 src/common/version.cpp create mode 100644 src/core/arm/arm_interface.h create mode 100644 src/core/arm/disassembler/arm_disasm.cpp create mode 100644 src/core/arm/disassembler/arm_disasm.h create mode 100644 src/core/arm/interpreter/arm_interpreter.cpp create mode 100644 src/core/arm/interpreter/arm_interpreter.h create mode 100644 src/core/arm/interpreter/arm_regformat.h create mode 100644 src/core/arm/interpreter/armcpu.h create mode 100644 src/core/arm/interpreter/armdefs.h create mode 100644 src/core/arm/interpreter/armemu.cpp create mode 100644 src/core/arm/interpreter/armemu.h create mode 100644 src/core/arm/interpreter/arminit.cpp create mode 100644 src/core/arm/interpreter/armmmu.cpp create mode 100644 src/core/arm/interpreter/armmmu.h create mode 100644 src/core/arm/interpreter/armos.cpp create mode 100644 src/core/arm/interpreter/armos.h create mode 100644 src/core/arm/interpreter/armsupp.cpp create mode 100644 src/core/arm/interpreter/armvirt.cpp create mode 100644 src/core/arm/interpreter/skyeye_defs.h create mode 100644 src/core/arm/interpreter/thumbemu.cpp create mode 100644 src/core/arm/mmu/arm1176jzf_s_mmu.cpp create mode 100644 src/core/arm/mmu/arm1176jzf_s_mmu.h create mode 100644 src/core/arm/mmu/cache.h create mode 100644 src/core/arm/mmu/rb.h create mode 100644 src/core/arm/mmu/tlb.h create mode 100644 src/core/arm/mmu/wb.h create mode 100644 src/core/core.cpp create mode 100644 src/core/core.h create mode 100644 src/core/core_timing.cpp create mode 100644 src/core/core_timing.h create mode 100644 src/core/elf/elf_reader.cpp create mode 100644 src/core/elf/elf_reader.h create mode 100644 src/core/elf/elf_types.h create mode 100644 src/core/file_sys/directory_file_system.cpp create mode 100644 src/core/file_sys/directory_file_system.h create mode 100644 src/core/file_sys/file_sys.h create mode 100644 src/core/file_sys/meta_file_system.cpp create mode 100644 src/core/file_sys/meta_file_system.h create mode 100644 src/core/hw/hw.cpp create mode 100644 src/core/hw/hw.h create mode 100644 src/core/hw/hw_lcd.cpp create mode 100644 src/core/hw/hw_lcd.h create mode 100644 src/core/loader.cpp create mode 100644 src/core/loader.h create mode 100644 src/core/mem_map.cpp create mode 100644 src/core/mem_map.h create mode 100644 src/core/mem_map_funcs.cpp delete mode 100644 src/core/src/arm/arm_interface.h delete mode 100644 src/core/src/arm/disassembler/arm_disasm.cpp delete mode 100644 src/core/src/arm/disassembler/arm_disasm.h delete mode 100644 src/core/src/arm/interpreter/arm_interpreter.cpp delete mode 100644 src/core/src/arm/interpreter/arm_interpreter.h delete mode 100644 src/core/src/arm/interpreter/arm_regformat.h delete mode 100644 src/core/src/arm/interpreter/armcpu.h delete mode 100644 src/core/src/arm/interpreter/armdefs.h delete mode 100644 src/core/src/arm/interpreter/armemu.cpp delete mode 100644 src/core/src/arm/interpreter/armemu.h delete mode 100644 src/core/src/arm/interpreter/arminit.cpp delete mode 100644 src/core/src/arm/interpreter/armmmu.cpp delete mode 100644 src/core/src/arm/interpreter/armmmu.h delete mode 100644 src/core/src/arm/interpreter/armos.cpp delete mode 100644 src/core/src/arm/interpreter/armos.h delete mode 100644 src/core/src/arm/interpreter/armsupp.cpp delete mode 100644 src/core/src/arm/interpreter/armvirt.cpp delete mode 100644 src/core/src/arm/interpreter/skyeye_defs.h delete mode 100644 src/core/src/arm/interpreter/thumbemu.cpp delete mode 100644 src/core/src/arm/mmu/arm1176jzf_s_mmu.cpp delete mode 100644 src/core/src/arm/mmu/arm1176jzf_s_mmu.h delete mode 100644 src/core/src/arm/mmu/cache.h delete mode 100644 src/core/src/arm/mmu/rb.h delete mode 100644 src/core/src/arm/mmu/tlb.h delete mode 100644 src/core/src/arm/mmu/wb.h delete mode 100644 src/core/src/core.cpp delete mode 100644 src/core/src/core.h delete mode 100644 src/core/src/core_timing.cpp delete mode 100644 src/core/src/core_timing.h delete mode 100644 src/core/src/elf/elf_reader.cpp delete mode 100644 src/core/src/elf/elf_reader.h delete mode 100644 src/core/src/elf/elf_types.h delete mode 100644 src/core/src/file_sys/directory_file_system.cpp delete mode 100644 src/core/src/file_sys/directory_file_system.h delete mode 100644 src/core/src/file_sys/file_sys.h delete mode 100644 src/core/src/file_sys/meta_file_system.cpp delete mode 100644 src/core/src/file_sys/meta_file_system.h delete mode 100644 src/core/src/hw/hw.cpp delete mode 100644 src/core/src/hw/hw.h delete mode 100644 src/core/src/hw/hw_lcd.cpp delete mode 100644 src/core/src/hw/hw_lcd.h delete mode 100644 src/core/src/loader.cpp delete mode 100644 src/core/src/loader.h delete mode 100644 src/core/src/mem_map.cpp delete mode 100644 src/core/src/mem_map.h delete mode 100644 src/core/src/mem_map_funcs.cpp delete mode 100644 src/core/src/system.cpp delete mode 100644 src/core/src/system.h create mode 100644 src/core/system.cpp create mode 100644 src/core/system.h create mode 100644 src/video_core/renderer_base.h create mode 100644 src/video_core/renderer_opengl/renderer_opengl.cpp create mode 100644 src/video_core/renderer_opengl/renderer_opengl.h delete mode 100644 src/video_core/src/renderer_base.h delete mode 100644 src/video_core/src/renderer_opengl/renderer_opengl.cpp delete mode 100644 src/video_core/src/renderer_opengl/renderer_opengl.h delete mode 100644 src/video_core/src/utils.cpp delete mode 100644 src/video_core/src/utils.h delete mode 100644 src/video_core/src/video_core.cpp delete mode 100644 src/video_core/src/video_core.h create mode 100644 src/video_core/utils.cpp create mode 100644 src/video_core/utils.h create mode 100644 src/video_core/video_core.cpp create mode 100644 src/video_core/video_core.h (limited to 'src') diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp new file mode 100644 index 00000000..746cf083 --- /dev/null +++ b/src/citra/citra.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2013 citra Emulator + * + * @file citra.cpp + * @author ShizZy + * @date 2013-09-04 + * @brief Main entry point + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#include "common.h" +#include "log_manager.h" +#include "file_util.h" + +#include "system.h" +#include "core.h" +#include "loader.h" + +#include "emu_window/emu_window_glfw.h" + +#include "citra.h" + +#define E_ERR -1 + +//#define PLAY_FIFO_RECORDING + +/// Application entry point +int __cdecl main(int argc, char **argv) { + //u32 tight_loop; + + printf("citra starting...\n"); + + std::string program_dir = File::GetCurrentDir(); + + LogManager::Init(); + + EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; + + System::Init(emu_window); + + std::string boot_filename = "homebrew.elf"; + std::string error_str; + + bool res = Loader::LoadFile(boot_filename, &error_str); + + if (!res) { + ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str()); + } + + for (;;) { + Core::SingleStep(); + } + + delete emu_window; + + return 0; +} diff --git a/src/citra/citra.h b/src/citra/citra.h new file mode 100644 index 00000000..b3a07c00 --- /dev/null +++ b/src/citra/citra.h @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2013 Citra Emulator + * + * @file citra.h + * @author ShizZy + * @date 2013-09-04 + * @brief Main entry point + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#ifndef CITRA_CITRA_H +#define CITRA_CITRA_H + +#include "version.h" + +#define APP_NAME "citra" +#define APP_VERSION "0.01-" VERSION +#define APP_TITLE APP_NAME " " APP_VERSION +#define COPYRIGHT "Copyright (C) 2013 Citra Emulator" + +#endif // CITRA_CITRA_H diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp new file mode 100644 index 00000000..4cdb7fbb --- /dev/null +++ b/src/citra/emu_window/emu_window_glfw.cpp @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2013 Citra Emulator + * + * @file emu_window_glfw.cpp + * @author ShizZy + * @date 2013-09-04 + * @brief Implementation implementation of EmuWindow class for GLFW + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#include "common.h" +#include "video_core.h" +#include "emu_window_glfw.h" + +static void OnKeyEvent(GLFWwindow* win, int key, int action) { + // EmuWindow_GLFW* emuwin = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); + //input_common::GCController::GCButtonState state; + + //if (action == GLFW_PRESS) { + // state = input_common::GCController::PRESSED; + //} else { + // state = input_common::GCController::RELEASED; + //} + // for (int channel = 0; channel < 4 && emuwin->controller_interface(); ++channel) { + // emuwin->controller_interface()->SetControllerStatus(channel, key, state); + // } +} + +static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) { + EmuWindow_GLFW* emuwin = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); + emuwin->set_client_area_width(width); + emuwin->set_client_area_height(height); +} + +/// EmuWindow_GLFW constructor +EmuWindow_GLFW::EmuWindow_GLFW() { + // Initialize the window + if(glfwInit() != GL_TRUE) { + printf("Failed to initialize GLFW! Exiting..."); + exit(1); + } + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + render_window_ = glfwCreateWindow(VideoCore::kScreenTopWidth, + (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), "citra", NULL, NULL); + + // Setup callbacks + glfwSetWindowUserPointer(render_window_, this); + //glfwSetKeyCallback(render_window_, OnKeyEvent); + //glfwSetWindowSizeCallback(render_window_, OnWindowSizeEvent); + + DoneCurrent(); +} + +/// EmuWindow_GLFW destructor +EmuWindow_GLFW::~EmuWindow_GLFW() { + glfwTerminate(); +} + +/// Swap buffers to display the next frame +void EmuWindow_GLFW::SwapBuffers() { + glfwSwapBuffers(render_window_); +} + +/// Polls window events +void EmuWindow_GLFW::PollEvents() { + // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title + // from the main thread, but this should probably be in an event handler... + static char title[128]; + sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), 0.0f); + glfwSetWindowTitle(render_window_, title); + + glfwPollEvents(); +} + +/// Makes the GLFW OpenGL context current for the caller thread +void EmuWindow_GLFW::MakeCurrent() { + glfwMakeContextCurrent(render_window_); +} + +/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread +void EmuWindow_GLFW::DoneCurrent() { + glfwMakeContextCurrent(NULL); +} diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h new file mode 100644 index 00000000..abca9faa --- /dev/null +++ b/src/citra/emu_window/emu_window_glfw.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2013 Citra Emulator + * + * @file emu_window_glfw.h + * @author ShizZy + * @date 2013-09-04 + * @brief Implementation implementation of EmuWindow class for GLFW + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#pragma once + +#include +#include + +#include "emu_window.h" + +class EmuWindow_GLFW : public EmuWindow { +public: + EmuWindow_GLFW(); + ~EmuWindow_GLFW(); + + /// Swap buffers to display the next frame + void SwapBuffers(); + + /// Polls window events + void PollEvents(); + + /// Makes the graphics context current for the caller thread + void MakeCurrent(); + + /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread + void DoneCurrent(); + + GLFWwindow* render_window_; ///< Internal GLFW render window + +private: + +}; diff --git a/src/citra/src/citra.cpp b/src/citra/src/citra.cpp deleted file mode 100644 index 746cf083..00000000 --- a/src/citra/src/citra.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (C) 2013 citra Emulator - * - * @file citra.cpp - * @author ShizZy - * @date 2013-09-04 - * @brief Main entry point - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#include "common.h" -#include "log_manager.h" -#include "file_util.h" - -#include "system.h" -#include "core.h" -#include "loader.h" - -#include "emu_window/emu_window_glfw.h" - -#include "citra.h" - -#define E_ERR -1 - -//#define PLAY_FIFO_RECORDING - -/// Application entry point -int __cdecl main(int argc, char **argv) { - //u32 tight_loop; - - printf("citra starting...\n"); - - std::string program_dir = File::GetCurrentDir(); - - LogManager::Init(); - - EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; - - System::Init(emu_window); - - std::string boot_filename = "homebrew.elf"; - std::string error_str; - - bool res = Loader::LoadFile(boot_filename, &error_str); - - if (!res) { - ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str()); - } - - for (;;) { - Core::SingleStep(); - } - - delete emu_window; - - return 0; -} diff --git a/src/citra/src/citra.h b/src/citra/src/citra.h deleted file mode 100644 index b3a07c00..00000000 --- a/src/citra/src/citra.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (C) 2013 Citra Emulator - * - * @file citra.h - * @author ShizZy - * @date 2013-09-04 - * @brief Main entry point - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#ifndef CITRA_CITRA_H -#define CITRA_CITRA_H - -#include "version.h" - -#define APP_NAME "citra" -#define APP_VERSION "0.01-" VERSION -#define APP_TITLE APP_NAME " " APP_VERSION -#define COPYRIGHT "Copyright (C) 2013 Citra Emulator" - -#endif // CITRA_CITRA_H diff --git a/src/citra/src/emu_window/emu_window_glfw.cpp b/src/citra/src/emu_window/emu_window_glfw.cpp deleted file mode 100644 index 4cdb7fbb..00000000 --- a/src/citra/src/emu_window/emu_window_glfw.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (C) 2013 Citra Emulator - * - * @file emu_window_glfw.cpp - * @author ShizZy - * @date 2013-09-04 - * @brief Implementation implementation of EmuWindow class for GLFW - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#include "common.h" -#include "video_core.h" -#include "emu_window_glfw.h" - -static void OnKeyEvent(GLFWwindow* win, int key, int action) { - // EmuWindow_GLFW* emuwin = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); - //input_common::GCController::GCButtonState state; - - //if (action == GLFW_PRESS) { - // state = input_common::GCController::PRESSED; - //} else { - // state = input_common::GCController::RELEASED; - //} - // for (int channel = 0; channel < 4 && emuwin->controller_interface(); ++channel) { - // emuwin->controller_interface()->SetControllerStatus(channel, key, state); - // } -} - -static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) { - EmuWindow_GLFW* emuwin = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); - emuwin->set_client_area_width(width); - emuwin->set_client_area_height(height); -} - -/// EmuWindow_GLFW constructor -EmuWindow_GLFW::EmuWindow_GLFW() { - // Initialize the window - if(glfwInit() != GL_TRUE) { - printf("Failed to initialize GLFW! Exiting..."); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - render_window_ = glfwCreateWindow(VideoCore::kScreenTopWidth, - (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), "citra", NULL, NULL); - - // Setup callbacks - glfwSetWindowUserPointer(render_window_, this); - //glfwSetKeyCallback(render_window_, OnKeyEvent); - //glfwSetWindowSizeCallback(render_window_, OnWindowSizeEvent); - - DoneCurrent(); -} - -/// EmuWindow_GLFW destructor -EmuWindow_GLFW::~EmuWindow_GLFW() { - glfwTerminate(); -} - -/// Swap buffers to display the next frame -void EmuWindow_GLFW::SwapBuffers() { - glfwSwapBuffers(render_window_); -} - -/// Polls window events -void EmuWindow_GLFW::PollEvents() { - // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title - // from the main thread, but this should probably be in an event handler... - static char title[128]; - sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), 0.0f); - glfwSetWindowTitle(render_window_, title); - - glfwPollEvents(); -} - -/// Makes the GLFW OpenGL context current for the caller thread -void EmuWindow_GLFW::MakeCurrent() { - glfwMakeContextCurrent(render_window_); -} - -/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread -void EmuWindow_GLFW::DoneCurrent() { - glfwMakeContextCurrent(NULL); -} diff --git a/src/citra/src/emu_window/emu_window_glfw.h b/src/citra/src/emu_window/emu_window_glfw.h deleted file mode 100644 index abca9faa..00000000 --- a/src/citra/src/emu_window/emu_window_glfw.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (C) 2013 Citra Emulator - * - * @file emu_window_glfw.h - * @author ShizZy - * @date 2013-09-04 - * @brief Implementation implementation of EmuWindow class for GLFW - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#pragma once - -#include -#include - -#include "emu_window.h" - -class EmuWindow_GLFW : public EmuWindow { -public: - EmuWindow_GLFW(); - ~EmuWindow_GLFW(); - - /// Swap buffers to display the next frame - void SwapBuffers(); - - /// Polls window events - void PollEvents(); - - /// Makes the graphics context current for the caller thread - void MakeCurrent(); - - /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - void DoneCurrent(); - - GLFWwindow* render_window_; ///< Internal GLFW render window - -private: - -}; diff --git a/src/citra/src/version.h b/src/citra/src/version.h deleted file mode 100644 index 07b88c64..00000000 --- a/src/citra/src/version.h +++ /dev/null @@ -1,6 +0,0 @@ -// GENERATED - Do not edit! -#ifndef VERSION_H_ -#define VERSION_H_ -#define __BUILD__ "122" -#define VERSION __BUILD__ -#endif // VERSION_H_ diff --git a/src/citra/version.h b/src/citra/version.h new file mode 100644 index 00000000..07b88c64 --- /dev/null +++ b/src/citra/version.h @@ -0,0 +1,6 @@ +// GENERATED - Do not edit! +#ifndef VERSION_H_ +#define VERSION_H_ +#define __BUILD__ "122" +#define VERSION __BUILD__ +#endif // VERSION_H_ diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp new file mode 100644 index 00000000..095856dc --- /dev/null +++ b/src/citra_qt/bootmanager.cpp @@ -0,0 +1,206 @@ +#include +#include + +#include "common.h" +#include "bootmanager.hxx" + +#include "core.h" +#include "loader.h" + +#include "version.h" + +#define APP_NAME "citra" +#define APP_VERSION "0.1-" VERSION +#define APP_TITLE APP_NAME " " APP_VERSION +#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" + +EmuThread::EmuThread(GRenderWindow* render_window) : exec_cpu_step(false), cpu_running(false), render_window(render_window) +{ +} + +void EmuThread::SetFilename(const char* filename) +{ + strcpy(this->filename, filename); +} + +void EmuThread::run() +{ + while (true) + { + for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) + { + if (cpu_running || exec_cpu_step) + { + if (exec_cpu_step) + exec_cpu_step = false; + + Core::SingleStep(); + emit CPUStepped(); + } + } + } + + Core::Stop(); +} + +void EmuThread::Stop() +{ + if (!isRunning()) + { + INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning..."); + return; + } + + //core::g_state = core::SYS_DIE; + + wait(1000); + if (isRunning()) + { + WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); + terminate(); + wait(1000); + if (isRunning()) + WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); + } + INFO_LOG(MASTER_LOG, "EmuThread stopped"); +} + + +// 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 +{ +public: + GGLWidgetInternal(GRenderWindow* parent) : QGLWidget(parent) + { + setAutoBufferSwap(false); + doneCurrent(); + parent_ = parent; + } + + void paintEvent(QPaintEvent* ev) + { + // Apparently, Windows doesn't display anything if we don't call this here. + // TODO: Breaks linux though because we aren't calling doneCurrent() ... -.- +// makeCurrent(); + } + void resizeEvent(QResizeEvent* ev) { + parent_->set_client_area_width(size().width()); + parent_->set_client_area_height(size().height()); + } +private: + GRenderWindow* parent_; +}; + + +EmuThread& GRenderWindow::GetEmuThread() +{ + return emu_thread; +} + +GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this) +{ + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose + + child = new GGLWidgetInternal(this); + + QBoxLayout* layout = new QHBoxLayout(this); + resize(640, 480); // TODO: Load size from config instead + layout->addWidget(child); + layout->setMargin(0); + setLayout(layout); + + BackupGeometry(); +} + +GRenderWindow::~GRenderWindow() +{ + emu_thread.Stop(); +} + +void GRenderWindow::SwapBuffers() +{ + child->makeCurrent(); // TODO: Not necessary? + child->swapBuffers(); +} + +void GRenderWindow::closeEvent(QCloseEvent* event) +{ + emu_thread.Stop(); + QWidget::closeEvent(event); +} + +void GRenderWindow::MakeCurrent() +{ + child->makeCurrent(); +} + +void GRenderWindow::DoneCurrent() +{ + child->doneCurrent(); +} + +void GRenderWindow::PollEvents() { + // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title + // from the main thread, but this should probably be in an event handler... + /* + static char title[128]; + sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), + video_core::g_renderer->current_fps()); + setWindowTitle(title); + */ +} + +void GRenderWindow::BackupGeometry() +{ + geometry = ((QGLWidget*)this)->saveGeometry(); +} + +void GRenderWindow::RestoreGeometry() +{ + // We don't want to back up the geometry here (obviously) + QWidget::restoreGeometry(geometry); +} + +void GRenderWindow::restoreGeometry(const QByteArray& geometry) +{ + // Make sure users of this class don't need to deal with backing up the geometry themselves + QWidget::restoreGeometry(geometry); + BackupGeometry(); +} + +QByteArray GRenderWindow::saveGeometry() +{ + // If we are a top-level widget, store the current geometry + // otherwise, store the last backup + if (parent() == NULL) + return ((QGLWidget*)this)->saveGeometry(); + else + return geometry; +} + +void GRenderWindow::keyPressEvent(QKeyEvent* event) +{ + /* + bool key_processed = false; + for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) + if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) + key_processed = true; + + if (!key_processed) + QWidget::keyPressEvent(event); + */ +} + +void GRenderWindow::keyReleaseEvent(QKeyEvent* event) +{ + /* + bool key_processed = false; + for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) + if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED)) + key_processed = true; + + if (!key_processed) + QWidget::keyPressEvent(event); + */ +} \ No newline at end of file diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx new file mode 100644 index 00000000..b3aa1cf3 --- /dev/null +++ b/src/citra_qt/bootmanager.hxx @@ -0,0 +1,112 @@ +#include +#include +#include "common.h" +#include "emu_window.h" + +class GRenderWindow; +class QKeyEvent; + +class EmuThread : public QThread +{ + Q_OBJECT + +public: + /** + * Set image filename + * + * @param filename + * @warning Only call when not running! + */ + void SetFilename(const char* filename); + + /** + * Start emulation (on new thread) + * + * @warning Only call when not running! + */ + void run(); + + /** + * Allow the CPU to process a single instruction (if cpu is not running) + * + * @note This function is thread-safe + */ + void ExecStep() { exec_cpu_step = true; } + + /** + * Allow the CPU to continue processing instructions without interruption + * + * @note This function is thread-safe + */ + void SetCpuRunning(bool running) { cpu_running = running; } + + /** + * Allow the CPU to continue processing instructions without interruption + * + * @note This function is thread-safe + */ + bool IsCpuRunning() { return cpu_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. + */ + void Stop(); + +private: + friend class GRenderWindow; + + EmuThread(GRenderWindow* render_window); + + char filename[MAX_PATH]; + + bool exec_cpu_step; + bool cpu_running; + + GRenderWindow* render_window; + +signals: + /** + * Emitted when CPU when we've finished processing a single Gekko instruction + * + * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false)) + * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) + */ + void CPUStepped(); +}; + +class GRenderWindow : public QWidget, public EmuWindow +{ +public: + GRenderWindow(QWidget* parent = NULL); + ~GRenderWindow(); + + void closeEvent(QCloseEvent*); + + // EmuWindow implementation + void SwapBuffers(); + void MakeCurrent(); + void DoneCurrent(); + void PollEvents(); + + void BackupGeometry(); + void RestoreGeometry(); + void restoreGeometry(const QByteArray& geometry); // overridden + QByteArray saveGeometry(); // overridden + + EmuThread& GetEmuThread(); + + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + +private: + QGLWidget* child; + + EmuThread emu_thread; + + QByteArray geometry; +}; diff --git a/src/citra_qt/callstack.cpp b/src/citra_qt/callstack.cpp new file mode 100644 index 00000000..2d62cb0d --- /dev/null +++ b/src/citra_qt/callstack.cpp @@ -0,0 +1,36 @@ +#include +#include "callstack.hxx" + +//#include "debugger/debugger.h" + +GCallstackView::GCallstackView(QWidget* parent): QDockWidget(parent) +{ + ui.setupUi(this); + + callstack_model = new QStandardItemModel(this); + callstack_model->setColumnCount(3); + callstack_model->setHeaderData(0, Qt::Horizontal, "Depth"); + callstack_model->setHeaderData(1, Qt::Horizontal, "Address"); + callstack_model->setHeaderData(2, Qt::Horizontal, "Function Name"); + ui.treeView->setModel(callstack_model); + + // TODO: Make single clicking a callstack entry jump to the corresponding disassembly position +} + +void GCallstackView::OnCPUStepped() +{ + /* + Debugger::Callstack callstack; + Debugger::GetCallstack(callstack); + callstack_model->setRowCount(callstack.size()); + + for (int i = 0; i < callstack.size(); ++i) + for (Debugger::CallstackIterator it = callstack.begin(); it != callstack.end(); ++it) + { + Debugger::CallstackEntry entry = callstack[i]; + callstack_model->setItem(i, 0, new QStandardItem(QString("%1").arg(i+1))); + callstack_model->setItem(i, 1, new QStandardItem(QString("0x%1").arg(entry.addr, 8, 16, QLatin1Char('0')))); + callstack_model->setItem(i, 2, new QStandardItem(QString::fromStdString(entry.name))); + } + */ +} \ No newline at end of file diff --git a/src/citra_qt/callstack.hxx b/src/citra_qt/callstack.hxx new file mode 100644 index 00000000..60b24f23 --- /dev/null +++ b/src/citra_qt/callstack.hxx @@ -0,0 +1,20 @@ +#include +#include "ui_callstack.h" +#include "platform.h" + +class QStandardItemModel; + +class GCallstackView : public QDockWidget +{ + Q_OBJECT + +public: + GCallstackView(QWidget* parent = 0); + +public slots: + void OnCPUStepped(); + +private: + Ui::CallStack ui; + QStandardItemModel* callstack_model; +}; diff --git a/src/citra_qt/callstack.ui b/src/citra_qt/callstack.ui new file mode 100644 index 00000000..b3c4db63 --- /dev/null +++ b/src/citra_qt/callstack.ui @@ -0,0 +1,36 @@ + + + CallStack + + + + 0 + 0 + 400 + 300 + + + + Call stack + + + + + + + true + + + false + + + false + + + + + + + + + diff --git a/src/citra_qt/config/controller_config.cpp b/src/citra_qt/config/controller_config.cpp new file mode 100644 index 00000000..52dfb627 --- /dev/null +++ b/src/citra_qt/config/controller_config.cpp @@ -0,0 +1,91 @@ +#include + +#include "controller_config.hxx" +#include "controller_config_util.hxx" + +/* TODO(bunnei): ImplementMe + +using common::Config; + +GControllerConfig::GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent) : QWidget(parent) +{ + ui.setupUi(this); + ((QGridLayout*)ui.mainStickTab->layout())->addWidget(new GStickConfig(Config::ANALOG_LEFT, Config::ANALOG_RIGHT, Config::ANALOG_UP, Config::ANALOG_DOWN, this, this), 1, 1); + ((QGridLayout*)ui.cStickTab->layout())->addWidget(new GStickConfig(Config::C_LEFT, Config::C_RIGHT, Config::C_UP, Config::C_DOWN, this, this), 1, 1); + ((QGridLayout*)ui.dPadTab->layout())->addWidget(new GStickConfig(Config::DPAD_LEFT, Config::DPAD_RIGHT, Config::DPAD_UP, Config::DPAD_DOWN, this, this), 1, 1); + + // TODO: Arrange these more compactly? + QVBoxLayout* layout = (QVBoxLayout*)ui.buttonsTab->layout(); + layout->addWidget(new GButtonConfigGroup("A Button", Config::BUTTON_A, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("B Button", Config::BUTTON_B, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("X Button", Config::BUTTON_X, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("Y Button", Config::BUTTON_Y, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("Z Button", Config::BUTTON_Z, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("L Trigger", Config::TRIGGER_L, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("R Trigger", Config::TRIGGER_R, this, ui.buttonsTab)); + layout->addWidget(new GButtonConfigGroup("Start Button", Config::BUTTON_START, this, ui.buttonsTab)); + + memcpy(config, initial_config, sizeof(config)); + + emit ActivePortChanged(config[0]); +} + +void GControllerConfig::OnKeyConfigChanged(common::Config::Control id, int key, const QString& name) +{ + if (InputSourceJoypad()) + { + config[GetActiveController()].pads.key_code[id] = key; + } + else + { + config[GetActiveController()].keys.key_code[id] = key; + } + emit ActivePortChanged(config[GetActiveController()]); +} + +int GControllerConfig::GetActiveController() +{ + return ui.activeControllerCB->currentIndex(); +} + +bool GControllerConfig::InputSourceJoypad() +{ + return ui.inputSourceCB->currentIndex() == 1; +} + +GControllerConfigDialog::GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent) : QDialog(parent), config_ptr(controller_ports) +{ + setWindowTitle(tr("Input configuration")); + + QVBoxLayout* layout = new QVBoxLayout(this); + config_widget = new GControllerConfig(controller_ports, this); + layout->addWidget(config_widget); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + layout->addWidget(buttons); + + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + + connect(this, SIGNAL(accepted()), this, SLOT(EnableChanges())); + + layout->setSizeConstraint(QLayout::SetFixedSize); + setLayout(layout); + setModal(true); + show(); +} + +void GControllerConfigDialog::EnableChanges() +{ + for (unsigned int i = 0; i < 4; ++i) + { + memcpy(&config_ptr[i], &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort)); + + if (common::g_config) { + // Apply changes if running a game + memcpy(&common::g_config->controller_ports(i), &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort)); + } + } +} + +*/ \ No newline at end of file diff --git a/src/citra_qt/config/controller_config.hxx b/src/citra_qt/config/controller_config.hxx new file mode 100644 index 00000000..9ff86a11 --- /dev/null +++ b/src/citra_qt/config/controller_config.hxx @@ -0,0 +1,52 @@ +#ifndef _CONTROLLER_CONFIG_HXX_ +#define _CONTROLLER_CONFIG_HXX_ + +#include + +#include "ui_controller_config.h" + +/* TODO(bunnei): ImplementMe + +#include "config.h" + +class GControllerConfig : public QWidget +{ + Q_OBJECT + +public: + GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent = NULL); + + const common::Config::ControllerPort& GetControllerConfig(int index) const { return config[index]; } + +signals: + void ActivePortChanged(const common::Config::ControllerPort&); + +public slots: + void OnKeyConfigChanged(common::Config::Control id, int key, const QString& name); + +private: + int GetActiveController(); + bool InputSourceJoypad(); + + Ui::ControllerConfig ui; + common::Config::ControllerPort config[4]; +}; + +class GControllerConfigDialog : public QDialog +{ + Q_OBJECT + +public: + GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent = NULL); + +public slots: + void EnableChanges(); + +private: + GControllerConfig* config_widget; + common::Config::ControllerPort* config_ptr; +}; + +*/ + +#endif // _CONTROLLER_CONFIG_HXX_ diff --git a/src/citra_qt/config/controller_config.ui b/src/citra_qt/config/controller_config.ui new file mode 100644 index 00000000..9f650047 --- /dev/null +++ b/src/citra_qt/config/controller_config.ui @@ -0,0 +1,308 @@ + + + ControllerConfig + + + + 0 + 0 + 503 + 293 + + + + + 0 + 0 + + + + Controller Configuration + + + + QLayout::SetFixedSize + + + + + + + + Controller 1 + + + + + Controller 2 + + + + + Controller 3 + + + + + Controller 4 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enabled + + + + + + + + Keyboard + + + + + Joypad + + + + + + + + Active Controller: + + + + + + + Input Source: + + + + + + + + + 0 + + + + Main Stick + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + C-Stick + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + D-Pad + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Buttons + + + + + + + + + + + ControlsChanged() + MainStickCleared() + CStickCleared() + DPadCleared() + ButtonsCleared() + OnControlsChanged() + OnMainStickCleared() + OnCStickCleared() + OnDPadCleared() + OnButtonsCleared() + + diff --git a/src/citra_qt/config/controller_config_util.cpp b/src/citra_qt/config/controller_config_util.cpp new file mode 100644 index 00000000..c5426570 --- /dev/null +++ b/src/citra_qt/config/controller_config_util.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +#include "controller_config_util.hxx" + +/* TODO(bunnei): ImplementMe +GStickConfig::GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent) : QWidget(parent) +{ + left = new GKeyConfigButton(leftid, style()->standardIcon(QStyle::SP_ArrowLeft), QString(), change_receiver, this); + right = new GKeyConfigButton(rightid, style()->standardIcon(QStyle::SP_ArrowRight), QString(), change_receiver, this); + up = new GKeyConfigButton(upid, style()->standardIcon(QStyle::SP_ArrowUp), QString(), change_receiver, this); + down = new GKeyConfigButton(downid, style()->standardIcon(QStyle::SP_ArrowDown), QString(), change_receiver, this); + clear = new QPushButton(tr("Clear"), this); + + QGridLayout* layout = new QGridLayout(this); + layout->addWidget(left, 1, 0); + layout->addWidget(right, 1, 2); + layout->addWidget(up, 0, 1); + layout->addWidget(down, 2, 1); + layout->addWidget(clear, 1, 1); + + setLayout(layout); +} + +GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(icon, text, parent), id(id), inputGrabbed(false) +{ + connect(this, SIGNAL(clicked()), this, SLOT(OnClicked())); + connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&))); + connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&))); +} + +GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(text, parent), id(id), inputGrabbed(false) +{ + connect(this, SIGNAL(clicked()), this, SLOT(OnClicked())); + connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&))); + connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&))); +} + +void GKeyConfigButton::OnActivePortChanged(const common::Config::ControllerPort& config) +{ + // TODO: Doesn't use joypad struct if that's the input source... + QString text = QKeySequence(config.keys.key_code[id]).toString(); // has a nicer format + if (config.keys.key_code[id] == Qt::Key_Shift) text = tr("Shift"); + else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control"); + else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt"); + else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta"); + setText(text); +} + +void GKeyConfigButton::OnClicked() +{ + grabKeyboard(); + grabMouse(); + inputGrabbed = true; + + old_text = text(); + setText(tr("Input...")); +} + +void GKeyConfigButton::keyPressEvent(QKeyEvent* event) +{ + if (inputGrabbed) + { + releaseKeyboard(); + releaseMouse(); + setText(QString()); + + // TODO: Doesn't capture "return" key + // TODO: This doesn't quite work well, yet... find a better way + QString text = QKeySequence(event->key()).toString(); // has a nicer format than event->text() + int key = event->key(); + if (event->modifiers() == Qt::ShiftModifier) { text = tr("Shift"); key = Qt::Key_Shift; } + else if (event->modifiers() == Qt::ControlModifier) { text = tr("Ctrl"); key = Qt::Key_Control; } + else if (event->modifiers() == Qt::AltModifier) { text = tr("Alt"); key = Qt::Key_Alt; } + else if (event->modifiers() == Qt::MetaModifier) { text = tr("Meta"); key = Qt::Key_Meta; } + + setText(old_text); + emit KeyAssigned(id, key, text); + + inputGrabbed = false; + + // TODO: Keys like "return" cause another keyPressEvent to be generated after this one... + } + + QPushButton::keyPressEvent(event); // TODO: Necessary? +} + +void GKeyConfigButton::mousePressEvent(QMouseEvent* event) +{ + // Abort key assignment + if (inputGrabbed) + { + releaseKeyboard(); + releaseMouse(); + setText(old_text); + inputGrabbed = false; + } + + QAbstractButton::mousePressEvent(event); +} + +GButtonConfigGroup::GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent) : QWidget(parent), id(id) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + + QPushButton* clear_button = new QPushButton(tr("Clear")); + + layout->addWidget(new QLabel(name, this)); + layout->addWidget(config_button = new GKeyConfigButton(id, QString(), change_receiver, this)); + layout->addWidget(clear_button); + + // TODO: connect config_button, clear_button + + setLayout(layout); +} + +*/ \ No newline at end of file diff --git a/src/citra_qt/config/controller_config_util.hxx b/src/citra_qt/config/controller_config_util.hxx new file mode 100644 index 00000000..af38f126 --- /dev/null +++ b/src/citra_qt/config/controller_config_util.hxx @@ -0,0 +1,78 @@ +#ifndef _CONTROLLER_CONFIG_UTIL_HXX_ +#define _CONTROLLER_CONFIG_UTIL_HXX_ + +#include +#include + +/* TODO(bunnei): ImplementMe + +#include "config.h" + +class GStickConfig : public QWidget +{ + Q_OBJECT + +public: + // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! + GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent = NULL); + +signals: + void LeftChanged(); + void RightChanged(); + void UpChanged(); + void DownChanged(); + +private: + QPushButton* left; + QPushButton* right; + QPushButton* up; + QPushButton* down; + + QPushButton* clear; +}; + +class GKeyConfigButton : public QPushButton +{ + Q_OBJECT + +public: + // TODO: change_receiver also needs to have an ActivePortChanged(const common::Config::ControllerPort&) signal + // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! + GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent); + GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent); + +signals: + void KeyAssigned(common::Config::Control id, int key, const QString& text); + +private slots: + void OnActivePortChanged(const common::Config::ControllerPort& config); + + void OnClicked(); + + void keyPressEvent(QKeyEvent* event); // TODO: bGrabbed? + void mousePressEvent(QMouseEvent* event); + +private: + common::Config::Control id; + bool inputGrabbed; + + QString old_text; +}; + +class GButtonConfigGroup : public QWidget +{ + Q_OBJECT + +public: + // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! + GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent = NULL); + +private: + GKeyConfigButton* config_button; + + common::Config::Control id; +}; + +*/ + +#endif // _CONTROLLER_CONFIG_HXX_ diff --git a/src/citra_qt/config/ui_controller_config.h b/src/citra_qt/config/ui_controller_config.h new file mode 100644 index 00000000..f84364a7 --- /dev/null +++ b/src/citra_qt/config/ui_controller_config.h @@ -0,0 +1,222 @@ +/******************************************************************************** +** Form generated from reading UI file 'controller_config.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_CONTROLLER_CONFIG_H +#define UI_CONTROLLER_CONFIG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_ControllerConfig +{ +public: + QVBoxLayout *verticalLayout; + QGridLayout *gridLayout; + QComboBox *activeControllerCB; + QSpacerItem *horizontalSpacer; + QCheckBox *checkBox; + QComboBox *inputSourceCB; + QLabel *label_2; + QLabel *label; + QTabWidget *tabWidget; + QWidget *mainStickTab; + QGridLayout *gridLayout_3; + QSpacerItem *verticalSpacer_2; + QSpacerItem *verticalSpacer_3; + QSpacerItem *horizontalSpacer_4; + QSpacerItem *horizontalSpacer_3; + QWidget *cStickTab; + QGridLayout *gridLayout_4; + QSpacerItem *horizontalSpacer_6; + QSpacerItem *verticalSpacer_5; + QSpacerItem *verticalSpacer_4; + QSpacerItem *horizontalSpacer_5; + QWidget *dPadTab; + QGridLayout *gridLayout_5; + QSpacerItem *horizontalSpacer_7; + QSpacerItem *verticalSpacer_7; + QSpacerItem *verticalSpacer_6; + QSpacerItem *horizontalSpacer_8; + QWidget *buttonsTab; + QVBoxLayout *verticalLayout_2; + + void setupUi(QWidget *ControllerConfig) + { + if (ControllerConfig->objectName().isEmpty()) + ControllerConfig->setObjectName(QString::fromUtf8("ControllerConfig")); + ControllerConfig->resize(503, 293); + QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(ControllerConfig->sizePolicy().hasHeightForWidth()); + ControllerConfig->setSizePolicy(sizePolicy); + verticalLayout = new QVBoxLayout(ControllerConfig); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + verticalLayout->setSizeConstraint(QLayout::SetFixedSize); + gridLayout = new QGridLayout(); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + activeControllerCB = new QComboBox(ControllerConfig); + activeControllerCB->setObjectName(QString::fromUtf8("activeControllerCB")); + + gridLayout->addWidget(activeControllerCB, 1, 1, 1, 1); + + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout->addItem(horizontalSpacer, 0, 2, 1, 1); + + checkBox = new QCheckBox(ControllerConfig); + checkBox->setObjectName(QString::fromUtf8("checkBox")); + + gridLayout->addWidget(checkBox, 1, 2, 1, 1); + + inputSourceCB = new QComboBox(ControllerConfig); + inputSourceCB->setObjectName(QString::fromUtf8("inputSourceCB")); + + gridLayout->addWidget(inputSourceCB, 0, 1, 1, 1); + + label_2 = new QLabel(ControllerConfig); + label_2->setObjectName(QString::fromUtf8("label_2")); + + gridLayout->addWidget(label_2, 1, 0, 1, 1); + + label = new QLabel(ControllerConfig); + label->setObjectName(QString::fromUtf8("label")); + + gridLayout->addWidget(label, 0, 0, 1, 1); + + + verticalLayout->addLayout(gridLayout); + + tabWidget = new QTabWidget(ControllerConfig); + tabWidget->setObjectName(QString::fromUtf8("tabWidget")); + mainStickTab = new QWidget(); + mainStickTab->setObjectName(QString::fromUtf8("mainStickTab")); + gridLayout_3 = new QGridLayout(mainStickTab); + gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3")); + verticalSpacer_2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_3->addItem(verticalSpacer_2, 2, 2, 1, 1); + + verticalSpacer_3 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_3->addItem(verticalSpacer_3, 0, 2, 1, 1); + + horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_3->addItem(horizontalSpacer_4, 1, 0, 1, 1); + + horizontalSpacer_3 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_3->addItem(horizontalSpacer_3, 1, 4, 1, 1); + + tabWidget->addTab(mainStickTab, QString()); + cStickTab = new QWidget(); + cStickTab->setObjectName(QString::fromUtf8("cStickTab")); + gridLayout_4 = new QGridLayout(cStickTab); + gridLayout_4->setObjectName(QString::fromUtf8("gridLayout_4")); + horizontalSpacer_6 = new QSpacerItem(40, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_4->addItem(horizontalSpacer_6, 1, 0, 1, 1); + + verticalSpacer_5 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_4->addItem(verticalSpacer_5, 0, 1, 1, 1); + + verticalSpacer_4 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_4->addItem(verticalSpacer_4, 2, 1, 1, 1); + + horizontalSpacer_5 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_4->addItem(horizontalSpacer_5, 1, 2, 1, 1); + + tabWidget->addTab(cStickTab, QString()); + dPadTab = new QWidget(); + dPadTab->setObjectName(QString::fromUtf8("dPadTab")); + gridLayout_5 = new QGridLayout(dPadTab); + gridLayout_5->setObjectName(QString::fromUtf8("gridLayout_5")); + horizontalSpacer_7 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_5->addItem(horizontalSpacer_7, 1, 2, 1, 1); + + verticalSpacer_7 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_5->addItem(verticalSpacer_7, 0, 1, 1, 1); + + verticalSpacer_6 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + gridLayout_5->addItem(verticalSpacer_6, 2, 1, 1, 1); + + horizontalSpacer_8 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + gridLayout_5->addItem(horizontalSpacer_8, 1, 0, 1, 1); + + tabWidget->addTab(dPadTab, QString()); + buttonsTab = new QWidget(); + buttonsTab->setObjectName(QString::fromUtf8("buttonsTab")); + verticalLayout_2 = new QVBoxLayout(buttonsTab); + verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); + tabWidget->addTab(buttonsTab, QString()); + + verticalLayout->addWidget(tabWidget); + + + retranslateUi(ControllerConfig); + + tabWidget->setCurrentIndex(0); + + + QMetaObject::connectSlotsByName(ControllerConfig); + } // setupUi + + void retranslateUi(QWidget *ControllerConfig) + { + ControllerConfig->setWindowTitle(QApplication::translate("ControllerConfig", "Controller Configuration", 0, QApplication::UnicodeUTF8)); + activeControllerCB->clear(); + activeControllerCB->insertItems(0, QStringList() + << QApplication::translate("ControllerConfig", "Controller 1", 0, QApplication::UnicodeUTF8) + << QApplication::translate("ControllerConfig", "Controller 2", 0, QApplication::UnicodeUTF8) + << QApplication::translate("ControllerConfig", "Controller 3", 0, QApplication::UnicodeUTF8) + << QApplication::translate("ControllerConfig", "Controller 4", 0, QApplication::UnicodeUTF8) + ); + checkBox->setText(QApplication::translate("ControllerConfig", "Enabled", 0, QApplication::UnicodeUTF8)); + inputSourceCB->clear(); + inputSourceCB->insertItems(0, QStringList() + << QApplication::translate("ControllerConfig", "Keyboard", 0, QApplication::UnicodeUTF8) + << QApplication::translate("ControllerConfig", "Joypad", 0, QApplication::UnicodeUTF8) + ); + label_2->setText(QApplication::translate("ControllerConfig", "Active Controller:", 0, QApplication::UnicodeUTF8)); + label->setText(QApplication::translate("ControllerConfig", "Input Source:", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(mainStickTab), QApplication::translate("ControllerConfig", "Main Stick", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(cStickTab), QApplication::translate("ControllerConfig", "C-Stick", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(dPadTab), QApplication::translate("ControllerConfig", "D-Pad", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(buttonsTab), QApplication::translate("ControllerConfig", "Buttons", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class ControllerConfig: public Ui_ControllerConfig {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_CONTROLLER_CONFIG_H diff --git a/src/citra_qt/cpu_regs.cpp b/src/citra_qt/cpu_regs.cpp new file mode 100644 index 00000000..f2859f69 --- /dev/null +++ b/src/citra_qt/cpu_regs.cpp @@ -0,0 +1,63 @@ +#include "cpu_regs.hxx" + +#include "core.h" +#include "arm/interpreter/armdefs.h" + +GARM11RegsView::GARM11RegsView(QWidget* parent) : QDockWidget(parent) +{ + cpu_regs_ui.setupUi(this); + + tree = cpu_regs_ui.treeWidget; + tree->addTopLevelItem(registers = new QTreeWidgetItem(QStringList("Registers"))); + tree->addTopLevelItem(CSPR = new QTreeWidgetItem(QStringList("CSPR"))); + + registers->setExpanded(true); + CSPR->setExpanded(true); + + for (int i = 0; i < 16; ++i) + { + QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0')))); + registers->addChild(child); + } + + CSPR->addChild(new QTreeWidgetItem(QStringList("M"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("T"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("F"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("I"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("A"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("E"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("IT"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("GE"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("DNM"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("J"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("Q"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("V"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("C"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("Z"))); + CSPR->addChild(new QTreeWidgetItem(QStringList("N"))); +} + +void GARM11RegsView::OnCPUStepped() +{ + ARM_Interface* app_core = Core::g_app_core; + + for (int i = 0; i < 16; ++i) + registers->child(i)->setText(1, QString("0x%1").arg(app_core->Reg(i), 8, 16, QLatin1Char('0'))); + + CSPR->setText(1, QString("0x%1").arg(app_core->CPSR(), 8, 16, QLatin1Char('0'))); + CSPR->child(0)->setText(1, QString("b%1").arg(app_core->CPSR() & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode + CSPR->child(1)->setText(1, QString("%1").arg((app_core->CPSR() >> 5) & 0x1)); // T - State + CSPR->child(2)->setText(1, QString("%1").arg((app_core->CPSR() >> 6) & 0x1)); // F - FIQ disable + CSPR->child(3)->setText(1, QString("%1").arg((app_core->CPSR() >> 7) & 0x1)); // I - IRQ disable + CSPR->child(4)->setText(1, QString("%1").arg((app_core->CPSR() >> 8) & 0x1)); // A - Imprecise abort + CSPR->child(5)->setText(1, QString("%1").arg((app_core->CPSR() >> 9) & 0x1)); // E - Data endianess + CSPR->child(6)->setText(1, QString("%1").arg((app_core->CPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM) + CSPR->child(7)->setText(1, QString("%1").arg((app_core->CPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal + CSPR->child(8)->setText(1, QString("%1").arg((app_core->CPSR() >> 20) & 0xF)); // DNM - Do not modify + CSPR->child(9)->setText(1, QString("%1").arg((app_core->CPSR() >> 24) & 0x1)); // J - Java state + CSPR->child(10)->setText(1, QString("%1").arg((app_core->CPSR() >> 27) & 0x1)); // Q - Sticky overflow + CSPR->child(11)->setText(1, QString("%1").arg((app_core->CPSR() >> 28) & 0x1)); // V - Overflow + CSPR->child(12)->setText(1, QString("%1").arg((app_core->CPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend + CSPR->child(13)->setText(1, QString("%1").arg((app_core->CPSR() >> 30) & 0x1)); // Z - Zero + CSPR->child(14)->setText(1, QString("%1").arg((app_core->CPSR() >> 31) & 0x1)); // N - Negative/Less than +} diff --git a/src/citra_qt/cpu_regs.hxx b/src/citra_qt/cpu_regs.hxx new file mode 100644 index 00000000..27c194bd --- /dev/null +++ b/src/citra_qt/cpu_regs.hxx @@ -0,0 +1,27 @@ +#include "ui_cpu_regs.h" + +#include +#include + +//#include "ui_gekko_regs.h" + +class QTreeWidget; + +class GARM11RegsView : public QDockWidget +{ + Q_OBJECT + +public: + GARM11RegsView(QWidget* parent = NULL); + +public slots: + void OnCPUStepped(); + +private: + Ui::ARMRegisters cpu_regs_ui; + + QTreeWidget* tree; + + QTreeWidgetItem* registers; + QTreeWidgetItem* CSPR; +}; diff --git a/src/citra_qt/cpu_regs.ui b/src/citra_qt/cpu_regs.ui new file mode 100644 index 00000000..6537c9cd --- /dev/null +++ b/src/citra_qt/cpu_regs.ui @@ -0,0 +1,40 @@ + + + ARMRegisters + + + + 0 + 0 + 400 + 300 + + + + ARM registers + + + + + + + true + + + + Register + + + + + Value + + + + + + + + + + diff --git a/src/citra_qt/disasm.cpp b/src/citra_qt/disasm.cpp new file mode 100644 index 00000000..ddcbf69d --- /dev/null +++ b/src/citra_qt/disasm.cpp @@ -0,0 +1,135 @@ +#include +#include "ui_disasm.h" +#include "disasm.hxx" + +#include "bootmanager.hxx" +#include "hotkeys.hxx" + +#include "common.h" +#include "mem_map.h" + +#include "core.h" +#include "break_points.h" +#include "arm/interpreter/armdefs.h" +#include "arm/disassembler/arm_disasm.h" + +GDisAsmView::GDisAsmView(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) +{ + disasm_ui.setupUi(this); + + breakpoints = new BreakPoints(); + + model = new QStandardItemModel(this); + model->setColumnCount(2); + disasm_ui.treeView->setModel(model); + + 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()), this, SLOT(OnSetBreakpoint())); + 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(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()), this, SLOT(OnSetBreakpoint())); +} + +void GDisAsmView::Init() +{ + ARM_Disasm* disasm = new ARM_Disasm(); + + base_addr = Core::g_app_core->PC(); + unsigned int curInstAddr = base_addr; + char result[255]; + + for (int i = 0; i < 10000; i++) // fixed for now + { + disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); + model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); + model->setItem(i, 1, new QStandardItem(QString(result))); + curInstAddr += 4; + } + disasm_ui.treeView->resizeColumnToContents(0); + disasm_ui.treeView->resizeColumnToContents(1); + + QModelIndex model_index = model->index(0, 0); + disasm_ui.treeView->scrollTo(model_index); + disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); +} + +void GDisAsmView::OnSetBreakpoint() +{ + int selected_row = SelectedRow(); + + if (selected_row == -1) + return; + + u32 address = base_addr + (selected_row * 4); + if (breakpoints->IsAddressBreakPoint(address)) + { + breakpoints->Remove(address); + model->item(selected_row, 0)->setBackground(QBrush()); + model->item(selected_row, 1)->setBackground(QBrush()); + } + else + { + breakpoints->Add(address); + model->item(selected_row, 0)->setBackground(QBrush(QColor(0xFF, 0x99, 0x99))); + model->item(selected_row, 1)->setBackground(QBrush(QColor(0xFF, 0x99, 0x99))); + } +} + +void GDisAsmView::OnContinue() +{ + emu_thread.SetCpuRunning(true); +} + +void GDisAsmView::OnStep() +{ + OnStepInto(); // change later +} + +void GDisAsmView::OnStepInto() +{ + emu_thread.SetCpuRunning(false); + emu_thread.ExecStep(); +} + +void GDisAsmView::OnPause() +{ + emu_thread.SetCpuRunning(false); +} + +void GDisAsmView::OnToggleStartStop() +{ + emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning()); +} + +void GDisAsmView::OnCPUStepped() +{ + ARMword next_instr = Core::g_app_core->PC(); + + if (breakpoints->IsAddressBreakPoint(next_instr)) + { + emu_thread.SetCpuRunning(false); + } + + unsigned int index = (next_instr - base_addr) / 4; + QModelIndex model_index = model->index(index, 0); + disasm_ui.treeView->scrollTo(model_index); + disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); +} + +int GDisAsmView::SelectedRow() +{ + QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); + if (!index.isValid()) + return -1; + + return model->itemFromIndex(disasm_ui.treeView->selectionModel()->currentIndex())->row(); +} \ No newline at end of file diff --git a/src/citra_qt/disasm.hxx b/src/citra_qt/disasm.hxx new file mode 100644 index 00000000..0e4a0fc3 --- /dev/null +++ b/src/citra_qt/disasm.hxx @@ -0,0 +1,42 @@ +#include +#include "ui_disasm.h" + +#include "common.h" +#include "break_points.h" + +class QAction; +class QStandardItemModel; +class EmuThread; + +class GDisAsmView : public QDockWidget +{ + Q_OBJECT + +public: + GDisAsmView(QWidget* parent, EmuThread& emu_thread); + + void Init(); + +public slots: + void OnSetBreakpoint(); + void OnContinue(); + void OnStep(); + void OnStepInto(); + void OnPause(); + void OnToggleStartStop(); + + void OnCPUStepped(); + +private: + // returns -1 if no row is selected + int SelectedRow(); + + Ui::DockWidget disasm_ui; + QStandardItemModel* model; + + u32 base_addr; + + BreakPoints* breakpoints; + + EmuThread& emu_thread; +}; diff --git a/src/citra_qt/disasm.ui b/src/citra_qt/disasm.ui new file mode 100644 index 00000000..fb384516 --- /dev/null +++ b/src/citra_qt/disasm.ui @@ -0,0 +1,78 @@ + + + DockWidget + + + + 0 + 0 + 430 + 401 + + + + Disassembly + + + + + + + + + Step + + + + + + + Pause + + + + + + + Continue + + + + + + + Step Into + + + + + + + Set Breakpoint + + + + + + + + + true + + + 20 + + + false + + + false + + + + + + + + + diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp new file mode 100644 index 00000000..1aa1e8b9 --- /dev/null +++ b/src/citra_qt/hotkeys.cpp @@ -0,0 +1,111 @@ +#include +#include +#include "hotkeys.hxx" +#include + +struct Hotkey +{ + Hotkey() : shortcut(NULL), context(Qt::WindowShortcut) {} + + QKeySequence keyseq; + QShortcut* shortcut; + Qt::ShortcutContext context; +}; + +typedef std::map HotkeyMap; +typedef std::map HotkeyGroupMap; + +HotkeyGroupMap hotkey_groups; + +void SaveHotkeys(QSettings& settings) +{ + settings.beginGroup("Shortcuts"); + + for (HotkeyGroupMap::iterator group = hotkey_groups.begin(); group != hotkey_groups.end(); ++group) + { + settings.beginGroup(group->first); + for (HotkeyMap::iterator hotkey = group->second.begin(); hotkey != group->second.end(); ++hotkey) + { + settings.beginGroup(hotkey->first); + settings.setValue(QString("KeySeq"), hotkey->second.keyseq.toString()); + settings.setValue(QString("Context"), hotkey->second.context); + settings.endGroup(); + } + settings.endGroup(); + } + settings.endGroup(); +} + +void LoadHotkeys(QSettings& settings) +{ + settings.beginGroup("Shortcuts"); + + // Make sure NOT to use a reference here because it would become invalid once we call beginGroup() + QStringList groups = settings.childGroups(); + for (QList::iterator group = groups.begin(); group != groups.end(); ++group) + { + settings.beginGroup(*group); + + QStringList hotkeys = settings.childGroups(); + for (QList::iterator hotkey = hotkeys.begin(); hotkey != hotkeys.end(); ++hotkey) + { + settings.beginGroup(*hotkey); + + // RegisterHotkey assigns default keybindings, so use old values as default parameters + Hotkey& hk = hotkey_groups[*group][*hotkey]; + hk.keyseq = QKeySequence::fromString(settings.value("KeySeq", hk.keyseq.toString()).toString()); + hk.context = (Qt::ShortcutContext)settings.value("Context", hk.context).toInt(); + if (hk.shortcut) + hk.shortcut->setKey(hk.keyseq); + + settings.endGroup(); + } + + settings.endGroup(); + } + + settings.endGroup(); +} + +void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, Qt::ShortcutContext default_context) +{ + if (hotkey_groups[group].find(action) == hotkey_groups[group].end()) + { + hotkey_groups[group][action].keyseq = default_keyseq; + hotkey_groups[group][action].context = default_context; + } +} + +QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget) +{ + Hotkey& hk = hotkey_groups[group][action]; + + if (!hk.shortcut) + hk.shortcut = new QShortcut(hk.keyseq, widget, NULL, NULL, hk.context); + + return hk.shortcut; +} + + +GHotkeysDialog::GHotkeysDialog(QWidget* parent): QDialog(parent) +{ + ui.setupUi(this); + + for (HotkeyGroupMap::iterator group = hotkey_groups.begin(); group != hotkey_groups.end(); ++group) + { + QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group->first)); + for (HotkeyMap::iterator hotkey = group->second.begin(); hotkey != group->second.end(); ++hotkey) + { + QStringList columns; + columns << hotkey->first << hotkey->second.keyseq.toString(); + QTreeWidgetItem* item = new QTreeWidgetItem(columns); + toplevel_item->addChild(item); + } + ui.treeWidget->addTopLevelItem(toplevel_item); + } + // TODO: Make context configurable as well (hiding the column for now) + ui.treeWidget->setColumnCount(2); + + ui.treeWidget->resizeColumnToContents(0); + ui.treeWidget->resizeColumnToContents(1); +} diff --git a/src/citra_qt/hotkeys.hxx b/src/citra_qt/hotkeys.hxx new file mode 100644 index 00000000..66ef7bb4 --- /dev/null +++ b/src/citra_qt/hotkeys.hxx @@ -0,0 +1,50 @@ +#include +#include +#include "ui_hotkeys.h" + +class QKeySequence; +class QSettings; + +/** + * Register a hotkey. + * + * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") + * @param action Name of the action (e.g. "Start Emulation", "Load Image") + * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the settings file before + * @param default_context Default context to assign if the hotkey wasn't present in the settings file before + * @warning Both the group and action strings will be displayed in the hotkey settings dialog + */ +void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq = QKeySequence(), Qt::ShortcutContext default_context = Qt::WindowShortcut); + +/** + * Returns a QShortcut object whose activated() signal can be connected to other QObjects' slots. + * + * @param widget Parent widget of the returned QShortcut. + * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut will be the same. Thus, you shouldn't rely on the caller really being the QShortcut's parent. + */ +QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); + +/** + * Saves all registered hotkeys to the settings file. + * + * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a settings group will be created to store the key sequence and the hotkey context. + */ +void SaveHotkeys(QSettings& settings); + +/** + * Loads hotkeys from the settings file. + * + * @note Yet unregistered hotkeys which are present in the settings will automatically be registered. + */ +void LoadHotkeys(QSettings& settings); + +class GHotkeysDialog : public QDialog +{ + Q_OBJECT + +public: + GHotkeysDialog(QWidget* parent = NULL); + +private: + Ui::hotkeys ui; +}; diff --git a/src/citra_qt/hotkeys.ui b/src/citra_qt/hotkeys.ui new file mode 100644 index 00000000..38a9a14d --- /dev/null +++ b/src/citra_qt/hotkeys.ui @@ -0,0 +1,89 @@ + + + hotkeys + + + + 0 + 0 + 363 + 388 + + + + Hotkey Settings + + + + + + QAbstractItemView::SelectItems + + + false + + + + Action + + + + + Hotkey + + + + + Context + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + buttonBox + accepted() + hotkeys + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + hotkeys + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp new file mode 100644 index 00000000..d7104eb0 --- /dev/null +++ b/src/citra_qt/main.cpp @@ -0,0 +1,230 @@ +#include +#include +#include +#include "qhexedit.h" +#include "main.hxx" + +#include "common.h" +#include "platform.h" +#if EMU_PLATFORM == PLATFORM_LINUX +#include +#endif + +#include "bootmanager.hxx" +#include "hotkeys.hxx" + +//debugger +#include "disasm.hxx" +#include "cpu_regs.hxx" +#include "callstack.hxx" +#include "ramview.hxx" + +#include "system.h" +#include "loader.h" +#include "core.h" +#include "version.h" + + +GMainWindow::GMainWindow() +{ + ui.setupUi(this); + statusBar()->hide(); + + render_window = new GRenderWindow; + render_window->hide(); + + disasm = new GDisAsmView(this, render_window->GetEmuThread()); + addDockWidget(Qt::BottomDockWidgetArea, disasm); + disasm->hide(); + + arm_regs = new GARM11RegsView(this); + addDockWidget(Qt::RightDockWidgetArea, arm_regs); + arm_regs->hide(); + + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); + debug_menu->addAction(disasm->toggleViewAction()); + debug_menu->addAction(arm_regs->toggleViewAction()); + + // Set default UI state + // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half + QDesktopWidget* desktop = ((QApplication*)QApplication::instance())->desktop(); + QRect screenRect = desktop->screenGeometry(this); + int x, y, w, h; + w = screenRect.width() * 2 / 3; + h = screenRect.height() / 2; + x = (screenRect.x() + screenRect.width()) / 2 - w / 2; + y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100; + setGeometry(x, y, w, h); + + + // Restore UI state + QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); + restoreGeometry(settings.value("geometry").toByteArray()); + restoreState(settings.value("state").toByteArray()); + render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray()); + + ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", false).toBool()); + SetupEmuWindowMode(); + + // Setup connections + connect(ui.action_load_elf, SIGNAL(triggered()), this, SLOT(OnMenuLoadELF())); + connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); + connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); + connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); + connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(SetupEmuWindowMode())); + 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(CPUStepped()), disasm, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), arm_regs, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); + + // Setup hotkeys + RegisterHotkey("Main Window", "Load Image", QKeySequence::Open); + RegisterHotkey("Main Window", "Start Emulation"); + LoadHotkeys(settings); + + connect(GetHotkey("Main Window", "Load Image", this), SIGNAL(activated()), this, SLOT(OnMenuLoadImage())); + connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); + + show(); + + System::Init(render_window); +} + +GMainWindow::~GMainWindow() +{ + // will get automatically deleted otherwise + if (render_window->parent() == NULL) + delete render_window; +} + +void GMainWindow::BootGame(const char* filename) +{ + render_window->DoneCurrent(); // make sure EmuThread can access GL context + render_window->GetEmuThread().SetFilename(filename); + + NOTICE_LOG(MASTER_LOG, "citra starting...\n"); + + if (Core::Init(/*render_window*/)) { + ERROR_LOG(MASTER_LOG, "core initialization failed, exiting..."); + Core::Stop(); + exit(1); + } + + // Load a game or die... + std::string boot_filename = filename; + std::string error_str; + bool res = Loader::LoadFile(boot_filename, &error_str); + + if (!res) { + ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str()); + } + + disasm->Init(); + arm_regs->OnCPUStepped(); + + render_window->GetEmuThread().start(); + + SetupEmuWindowMode(); + render_window->show(); +} + +void GMainWindow::OnMenuLoadELF() +{ + QString filename = QFileDialog::getOpenFileName(this, tr("Load ELF"), QString(), QString()); + if (filename.size()) + BootGame(filename.toLatin1().data()); +} + +void GMainWindow::OnStartGame() +{ + render_window->show(); + render_window->GetEmuThread().SetCpuRunning(true); + + ui.action_Start->setEnabled(false); + ui.action_Pause->setEnabled(true); + ui.action_Stop->setEnabled(true); +} + +void GMainWindow::OnPauseGame() +{ + render_window->GetEmuThread().SetCpuRunning(false); + + ui.action_Start->setEnabled(true); + ui.action_Pause->setEnabled(false); + ui.action_Stop->setEnabled(true); +} + +void GMainWindow::OnStopGame() +{ + render_window->GetEmuThread().SetCpuRunning(false); + + ui.action_Start->setEnabled(true); + ui.action_Pause->setEnabled(false); + ui.action_Stop->setEnabled(false); +} + +void GMainWindow::OnOpenHotkeysDialog() +{ + GHotkeysDialog dialog(this); + dialog.exec(); +} + + +void GMainWindow::SetupEmuWindowMode() +{ + //if (!render_window->GetEmuThread().isRunning()) + // return; + + bool enable = ui.action_Single_Window_Mode->isChecked(); + if (enable && render_window->parent() == NULL) // switch to single window mode + { + render_window->BackupGeometry(); + ui.horizontalLayout->addWidget(render_window); + render_window->setVisible(true); + render_window->DoneCurrent(); + } + else if (!enable && render_window->parent() != NULL) // switch to multiple windows mode + { + ui.horizontalLayout->removeWidget(render_window); + render_window->setParent(NULL); + render_window->setVisible(true); + render_window->DoneCurrent(); + render_window->RestoreGeometry(); + } +} + +void GMainWindow::OnConfigure() +{ + //GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this); +} + +void GMainWindow::closeEvent(QCloseEvent* event) +{ + // Save window layout + QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); + settings.setValue("geometry", saveGeometry()); + settings.setValue("state", saveState()); + settings.setValue("geometryRenderWindow", render_window->saveGeometry()); + settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); + settings.setValue("firstStart", false); + SaveHotkeys(settings); + + render_window->close(); + + QWidget::closeEvent(event); +} + +#ifdef main +#undef main +#endif + +int __cdecl main(int argc, char* argv[]) +{ + QApplication::setAttribute(Qt::AA_X11InitThreads); + QApplication app(argc, argv); + GMainWindow main_window; + + main_window.show(); + return app.exec(); +} diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx new file mode 100644 index 00000000..34bd2c3a --- /dev/null +++ b/src/citra_qt/main.hxx @@ -0,0 +1,51 @@ +#ifndef _CITRA_QT_MAIN_HXX_ +#define _CITRA_QT_MAIN_HXX_ + +#include + +#include "ui_main.h" + +class GImageInfo; +class GRenderWindow; +class GDisAsmView; +class GARM11RegsView; + +class GMainWindow : public QMainWindow +{ + Q_OBJECT + + // TODO: Make use of this! + enum { + UI_IDLE, + UI_EMU_BOOTING, + UI_EMU_RUNNING, + UI_EMU_STOPPING, + }; + +public: + GMainWindow(); + ~GMainWindow(); + +private: + void BootGame(const char* filename); + + void closeEvent(QCloseEvent* event); + +private slots: + void OnStartGame(); + void OnPauseGame(); + void OnStopGame(); + void OnMenuLoadELF(); + void OnOpenHotkeysDialog(); + void SetupEmuWindowMode(); + void OnConfigure(); + +private: + Ui::MainWindow ui; + + GRenderWindow* render_window; + GDisAsmView* disasm; + GARM11RegsView* arm_regs; +}; + +#endif // _CITRA_QT_MAIN_HXX_ diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui new file mode 100644 index 00000000..bc895d89 --- /dev/null +++ b/src/citra_qt/main.ui @@ -0,0 +1,168 @@ + + + MainWindow + + + + 0 + 0 + 1081 + 730 + + + + Citra + + + + src/pcafe/res/icon3_64x64.icosrc/pcafe/res/icon3_64x64.ico + + + QTabWidget::Rounded + + + true + + + + + + + + 0 + 0 + 1081 + 20 + + + + + &File + + + + + + + + &Emulation + + + + + + + + + + &View + + + + + + + &Help + + + + + + + + + + + + Load ELF ... + + + + + E&xit + + + + + &Start + + + + + false + + + &Pause + + + + + false + + + &Stop + + + + + About Citra + + + + + true + + + Single Window Mode + + + + + Configure &Hotkeys ... + + + + + Configure ... + + + + + + + action_Exit + triggered() + MainWindow + close() + + + -1 + -1 + + + 367 + 314 + + + + + action_Configure + triggered() + MainWindow + OnConfigure() + + + -1 + -1 + + + 540 + 364 + + + + + + OnConfigure() + + diff --git a/src/citra_qt/ramview.cpp b/src/citra_qt/ramview.cpp new file mode 100644 index 00000000..8cc252af --- /dev/null +++ b/src/citra_qt/ramview.cpp @@ -0,0 +1,13 @@ +#include "ramview.hxx" + +#include "common.h" +#include "memory.h" +GRamView::GRamView(QWidget* parent) : QHexEdit(parent) +{ +} + +void GRamView::OnCPUStepped() +{ + // TODO: QHexEdit doesn't show vertical scroll bars for > 10MB data streams... + //setData(QByteArray((const char*)Mem_RAM,sizeof(Mem_RAM)/8)); +} \ No newline at end of file diff --git a/src/citra_qt/ramview.hxx b/src/citra_qt/ramview.hxx new file mode 100644 index 00000000..1db1546a --- /dev/null +++ b/src/citra_qt/ramview.hxx @@ -0,0 +1,12 @@ +#include "qhexedit.h" + +class GRamView : public QHexEdit +{ + Q_OBJECT + +public: + GRamView(QWidget* parent = NULL); + +public slots: + void OnCPUStepped(); +}; diff --git a/src/citra_qt/src/bootmanager.cpp b/src/citra_qt/src/bootmanager.cpp deleted file mode 100644 index 095856dc..00000000 --- a/src/citra_qt/src/bootmanager.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include -#include - -#include "common.h" -#include "bootmanager.hxx" - -#include "core.h" -#include "loader.h" - -#include "version.h" - -#define APP_NAME "citra" -#define APP_VERSION "0.1-" VERSION -#define APP_TITLE APP_NAME " " APP_VERSION -#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" - -EmuThread::EmuThread(GRenderWindow* render_window) : exec_cpu_step(false), cpu_running(false), render_window(render_window) -{ -} - -void EmuThread::SetFilename(const char* filename) -{ - strcpy(this->filename, filename); -} - -void EmuThread::run() -{ - while (true) - { - for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) - { - if (cpu_running || exec_cpu_step) - { - if (exec_cpu_step) - exec_cpu_step = false; - - Core::SingleStep(); - emit CPUStepped(); - } - } - } - - Core::Stop(); -} - -void EmuThread::Stop() -{ - if (!isRunning()) - { - INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning..."); - return; - } - - //core::g_state = core::SYS_DIE; - - wait(1000); - if (isRunning()) - { - WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); - terminate(); - wait(1000); - if (isRunning()) - WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); - } - INFO_LOG(MASTER_LOG, "EmuThread stopped"); -} - - -// 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 -{ -public: - GGLWidgetInternal(GRenderWindow* parent) : QGLWidget(parent) - { - setAutoBufferSwap(false); - doneCurrent(); - parent_ = parent; - } - - void paintEvent(QPaintEvent* ev) - { - // Apparently, Windows doesn't display anything if we don't call this here. - // TODO: Breaks linux though because we aren't calling doneCurrent() ... -.- -// makeCurrent(); - } - void resizeEvent(QResizeEvent* ev) { - parent_->set_client_area_width(size().width()); - parent_->set_client_area_height(size().height()); - } -private: - GRenderWindow* parent_; -}; - - -EmuThread& GRenderWindow::GetEmuThread() -{ - return emu_thread; -} - -GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this) -{ - // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose - - child = new GGLWidgetInternal(this); - - QBoxLayout* layout = new QHBoxLayout(this); - resize(640, 480); // TODO: Load size from config instead - layout->addWidget(child); - layout->setMargin(0); - setLayout(layout); - - BackupGeometry(); -} - -GRenderWindow::~GRenderWindow() -{ - emu_thread.Stop(); -} - -void GRenderWindow::SwapBuffers() -{ - child->makeCurrent(); // TODO: Not necessary? - child->swapBuffers(); -} - -void GRenderWindow::closeEvent(QCloseEvent* event) -{ - emu_thread.Stop(); - QWidget::closeEvent(event); -} - -void GRenderWindow::MakeCurrent() -{ - child->makeCurrent(); -} - -void GRenderWindow::DoneCurrent() -{ - child->doneCurrent(); -} - -void GRenderWindow::PollEvents() { - // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title - // from the main thread, but this should probably be in an event handler... - /* - static char title[128]; - sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), - video_core::g_renderer->current_fps()); - setWindowTitle(title); - */ -} - -void GRenderWindow::BackupGeometry() -{ - geometry = ((QGLWidget*)this)->saveGeometry(); -} - -void GRenderWindow::RestoreGeometry() -{ - // We don't want to back up the geometry here (obviously) - QWidget::restoreGeometry(geometry); -} - -void GRenderWindow::restoreGeometry(const QByteArray& geometry) -{ - // Make sure users of this class don't need to deal with backing up the geometry themselves - QWidget::restoreGeometry(geometry); - BackupGeometry(); -} - -QByteArray GRenderWindow::saveGeometry() -{ - // If we are a top-level widget, store the current geometry - // otherwise, store the last backup - if (parent() == NULL) - return ((QGLWidget*)this)->saveGeometry(); - else - return geometry; -} - -void GRenderWindow::keyPressEvent(QKeyEvent* event) -{ - /* - bool key_processed = false; - for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) - key_processed = true; - - if (!key_processed) - QWidget::keyPressEvent(event); - */ -} - -void GRenderWindow::keyReleaseEvent(QKeyEvent* event) -{ - /* - bool key_processed = false; - for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED)) - key_processed = true; - - if (!key_processed) - QWidget::keyPressEvent(event); - */ -} \ No newline at end of file diff --git a/src/citra_qt/src/bootmanager.hxx b/src/citra_qt/src/bootmanager.hxx deleted file mode 100644 index b3aa1cf3..00000000 --- a/src/citra_qt/src/bootmanager.hxx +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include "common.h" -#include "emu_window.h" - -class GRenderWindow; -class QKeyEvent; - -class EmuThread : public QThread -{ - Q_OBJECT - -public: - /** - * Set image filename - * - * @param filename - * @warning Only call when not running! - */ - void SetFilename(const char* filename); - - /** - * Start emulation (on new thread) - * - * @warning Only call when not running! - */ - void run(); - - /** - * Allow the CPU to process a single instruction (if cpu is not running) - * - * @note This function is thread-safe - */ - void ExecStep() { exec_cpu_step = true; } - - /** - * Allow the CPU to continue processing instructions without interruption - * - * @note This function is thread-safe - */ - void SetCpuRunning(bool running) { cpu_running = running; } - - /** - * Allow the CPU to continue processing instructions without interruption - * - * @note This function is thread-safe - */ - bool IsCpuRunning() { return cpu_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. - */ - void Stop(); - -private: - friend class GRenderWindow; - - EmuThread(GRenderWindow* render_window); - - char filename[MAX_PATH]; - - bool exec_cpu_step; - bool cpu_running; - - GRenderWindow* render_window; - -signals: - /** - * Emitted when CPU when we've finished processing a single Gekko instruction - * - * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false)) - * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) - */ - void CPUStepped(); -}; - -class GRenderWindow : public QWidget, public EmuWindow -{ -public: - GRenderWindow(QWidget* parent = NULL); - ~GRenderWindow(); - - void closeEvent(QCloseEvent*); - - // EmuWindow implementation - void SwapBuffers(); - void MakeCurrent(); - void DoneCurrent(); - void PollEvents(); - - void BackupGeometry(); - void RestoreGeometry(); - void restoreGeometry(const QByteArray& geometry); // overridden - QByteArray saveGeometry(); // overridden - - EmuThread& GetEmuThread(); - - void keyPressEvent(QKeyEvent* event); - void keyReleaseEvent(QKeyEvent* event); - -private: - QGLWidget* child; - - EmuThread emu_thread; - - QByteArray geometry; -}; diff --git a/src/citra_qt/src/callstack.cpp b/src/citra_qt/src/callstack.cpp deleted file mode 100644 index 2d62cb0d..00000000 --- a/src/citra_qt/src/callstack.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include "callstack.hxx" - -//#include "debugger/debugger.h" - -GCallstackView::GCallstackView(QWidget* parent): QDockWidget(parent) -{ - ui.setupUi(this); - - callstack_model = new QStandardItemModel(this); - callstack_model->setColumnCount(3); - callstack_model->setHeaderData(0, Qt::Horizontal, "Depth"); - callstack_model->setHeaderData(1, Qt::Horizontal, "Address"); - callstack_model->setHeaderData(2, Qt::Horizontal, "Function Name"); - ui.treeView->setModel(callstack_model); - - // TODO: Make single clicking a callstack entry jump to the corresponding disassembly position -} - -void GCallstackView::OnCPUStepped() -{ - /* - Debugger::Callstack callstack; - Debugger::GetCallstack(callstack); - callstack_model->setRowCount(callstack.size()); - - for (int i = 0; i < callstack.size(); ++i) - for (Debugger::CallstackIterator it = callstack.begin(); it != callstack.end(); ++it) - { - Debugger::CallstackEntry entry = callstack[i]; - callstack_model->setItem(i, 0, new QStandardItem(QString("%1").arg(i+1))); - callstack_model->setItem(i, 1, new QStandardItem(QString("0x%1").arg(entry.addr, 8, 16, QLatin1Char('0')))); - callstack_model->setItem(i, 2, new QStandardItem(QString::fromStdString(entry.name))); - } - */ -} \ No newline at end of file diff --git a/src/citra_qt/src/callstack.hxx b/src/citra_qt/src/callstack.hxx deleted file mode 100644 index 60b24f23..00000000 --- a/src/citra_qt/src/callstack.hxx +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "ui_callstack.h" -#include "platform.h" - -class QStandardItemModel; - -class GCallstackView : public QDockWidget -{ - Q_OBJECT - -public: - GCallstackView(QWidget* parent = 0); - -public slots: - void OnCPUStepped(); - -private: - Ui::CallStack ui; - QStandardItemModel* callstack_model; -}; diff --git a/src/citra_qt/src/callstack.ui b/src/citra_qt/src/callstack.ui deleted file mode 100644 index b3c4db63..00000000 --- a/src/citra_qt/src/callstack.ui +++ /dev/null @@ -1,36 +0,0 @@ - - - CallStack - - - - 0 - 0 - 400 - 300 - - - - Call stack - - - - - - - true - - - false - - - false - - - - - - - - - diff --git a/src/citra_qt/src/config/controller_config.cpp b/src/citra_qt/src/config/controller_config.cpp deleted file mode 100644 index 52dfb627..00000000 --- a/src/citra_qt/src/config/controller_config.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include - -#include "controller_config.hxx" -#include "controller_config_util.hxx" - -/* TODO(bunnei): ImplementMe - -using common::Config; - -GControllerConfig::GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent) : QWidget(parent) -{ - ui.setupUi(this); - ((QGridLayout*)ui.mainStickTab->layout())->addWidget(new GStickConfig(Config::ANALOG_LEFT, Config::ANALOG_RIGHT, Config::ANALOG_UP, Config::ANALOG_DOWN, this, this), 1, 1); - ((QGridLayout*)ui.cStickTab->layout())->addWidget(new GStickConfig(Config::C_LEFT, Config::C_RIGHT, Config::C_UP, Config::C_DOWN, this, this), 1, 1); - ((QGridLayout*)ui.dPadTab->layout())->addWidget(new GStickConfig(Config::DPAD_LEFT, Config::DPAD_RIGHT, Config::DPAD_UP, Config::DPAD_DOWN, this, this), 1, 1); - - // TODO: Arrange these more compactly? - QVBoxLayout* layout = (QVBoxLayout*)ui.buttonsTab->layout(); - layout->addWidget(new GButtonConfigGroup("A Button", Config::BUTTON_A, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("B Button", Config::BUTTON_B, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("X Button", Config::BUTTON_X, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("Y Button", Config::BUTTON_Y, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("Z Button", Config::BUTTON_Z, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("L Trigger", Config::TRIGGER_L, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("R Trigger", Config::TRIGGER_R, this, ui.buttonsTab)); - layout->addWidget(new GButtonConfigGroup("Start Button", Config::BUTTON_START, this, ui.buttonsTab)); - - memcpy(config, initial_config, sizeof(config)); - - emit ActivePortChanged(config[0]); -} - -void GControllerConfig::OnKeyConfigChanged(common::Config::Control id, int key, const QString& name) -{ - if (InputSourceJoypad()) - { - config[GetActiveController()].pads.key_code[id] = key; - } - else - { - config[GetActiveController()].keys.key_code[id] = key; - } - emit ActivePortChanged(config[GetActiveController()]); -} - -int GControllerConfig::GetActiveController() -{ - return ui.activeControllerCB->currentIndex(); -} - -bool GControllerConfig::InputSourceJoypad() -{ - return ui.inputSourceCB->currentIndex() == 1; -} - -GControllerConfigDialog::GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent) : QDialog(parent), config_ptr(controller_ports) -{ - setWindowTitle(tr("Input configuration")); - - QVBoxLayout* layout = new QVBoxLayout(this); - config_widget = new GControllerConfig(controller_ports, this); - layout->addWidget(config_widget); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - layout->addWidget(buttons); - - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - - connect(this, SIGNAL(accepted()), this, SLOT(EnableChanges())); - - layout->setSizeConstraint(QLayout::SetFixedSize); - setLayout(layout); - setModal(true); - show(); -} - -void GControllerConfigDialog::EnableChanges() -{ - for (unsigned int i = 0; i < 4; ++i) - { - memcpy(&config_ptr[i], &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort)); - - if (common::g_config) { - // Apply changes if running a game - memcpy(&common::g_config->controller_ports(i), &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort)); - } - } -} - -*/ \ No newline at end of file diff --git a/src/citra_qt/src/config/controller_config.hxx b/src/citra_qt/src/config/controller_config.hxx deleted file mode 100644 index 9ff86a11..00000000 --- a/src/citra_qt/src/config/controller_config.hxx +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _CONTROLLER_CONFIG_HXX_ -#define _CONTROLLER_CONFIG_HXX_ - -#include - -#include "ui_controller_config.h" - -/* TODO(bunnei): ImplementMe - -#include "config.h" - -class GControllerConfig : public QWidget -{ - Q_OBJECT - -public: - GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent = NULL); - - const common::Config::ControllerPort& GetControllerConfig(int index) const { return config[index]; } - -signals: - void ActivePortChanged(const common::Config::ControllerPort&); - -public slots: - void OnKeyConfigChanged(common::Config::Control id, int key, const QString& name); - -private: - int GetActiveController(); - bool InputSourceJoypad(); - - Ui::ControllerConfig ui; - common::Config::ControllerPort config[4]; -}; - -class GControllerConfigDialog : public QDialog -{ - Q_OBJECT - -public: - GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent = NULL); - -public slots: - void EnableChanges(); - -private: - GControllerConfig* config_widget; - common::Config::ControllerPort* config_ptr; -}; - -*/ - -#endif // _CONTROLLER_CONFIG_HXX_ diff --git a/src/citra_qt/src/config/controller_config.ui b/src/citra_qt/src/config/controller_config.ui deleted file mode 100644 index 9f650047..00000000 --- a/src/citra_qt/src/config/controller_config.ui +++ /dev/null @@ -1,308 +0,0 @@ - - - ControllerConfig - - - - 0 - 0 - 503 - 293 - - - - - 0 - 0 - - - - Controller Configuration - - - - QLayout::SetFixedSize - - - - - - - - Controller 1 - - - - - Controller 2 - - - - - Controller 3 - - - - - Controller 4 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Enabled - - - - - - - - Keyboard - - - - - Joypad - - - - - - - - Active Controller: - - - - - - - Input Source: - - - - - - - - - 0 - - - - Main Stick - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - C-Stick - - - - - - Qt::Horizontal - - - - 40 - 0 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - D-Pad - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Buttons - - - - - - - - - - - ControlsChanged() - MainStickCleared() - CStickCleared() - DPadCleared() - ButtonsCleared() - OnControlsChanged() - OnMainStickCleared() - OnCStickCleared() - OnDPadCleared() - OnButtonsCleared() - - diff --git a/src/citra_qt/src/config/controller_config_util.cpp b/src/citra_qt/src/config/controller_config_util.cpp deleted file mode 100644 index c5426570..00000000 --- a/src/citra_qt/src/config/controller_config_util.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "controller_config_util.hxx" - -/* TODO(bunnei): ImplementMe -GStickConfig::GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent) : QWidget(parent) -{ - left = new GKeyConfigButton(leftid, style()->standardIcon(QStyle::SP_ArrowLeft), QString(), change_receiver, this); - right = new GKeyConfigButton(rightid, style()->standardIcon(QStyle::SP_ArrowRight), QString(), change_receiver, this); - up = new GKeyConfigButton(upid, style()->standardIcon(QStyle::SP_ArrowUp), QString(), change_receiver, this); - down = new GKeyConfigButton(downid, style()->standardIcon(QStyle::SP_ArrowDown), QString(), change_receiver, this); - clear = new QPushButton(tr("Clear"), this); - - QGridLayout* layout = new QGridLayout(this); - layout->addWidget(left, 1, 0); - layout->addWidget(right, 1, 2); - layout->addWidget(up, 0, 1); - layout->addWidget(down, 2, 1); - layout->addWidget(clear, 1, 1); - - setLayout(layout); -} - -GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(icon, text, parent), id(id), inputGrabbed(false) -{ - connect(this, SIGNAL(clicked()), this, SLOT(OnClicked())); - connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&))); - connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&))); -} - -GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(text, parent), id(id), inputGrabbed(false) -{ - connect(this, SIGNAL(clicked()), this, SLOT(OnClicked())); - connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&))); - connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&))); -} - -void GKeyConfigButton::OnActivePortChanged(const common::Config::ControllerPort& config) -{ - // TODO: Doesn't use joypad struct if that's the input source... - QString text = QKeySequence(config.keys.key_code[id]).toString(); // has a nicer format - if (config.keys.key_code[id] == Qt::Key_Shift) text = tr("Shift"); - else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control"); - else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt"); - else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta"); - setText(text); -} - -void GKeyConfigButton::OnClicked() -{ - grabKeyboard(); - grabMouse(); - inputGrabbed = true; - - old_text = text(); - setText(tr("Input...")); -} - -void GKeyConfigButton::keyPressEvent(QKeyEvent* event) -{ - if (inputGrabbed) - { - releaseKeyboard(); - releaseMouse(); - setText(QString()); - - // TODO: Doesn't capture "return" key - // TODO: This doesn't quite work well, yet... find a better way - QString text = QKeySequence(event->key()).toString(); // has a nicer format than event->text() - int key = event->key(); - if (event->modifiers() == Qt::ShiftModifier) { text = tr("Shift"); key = Qt::Key_Shift; } - else if (event->modifiers() == Qt::ControlModifier) { text = tr("Ctrl"); key = Qt::Key_Control; } - else if (event->modifiers() == Qt::AltModifier) { text = tr("Alt"); key = Qt::Key_Alt; } - else if (event->modifiers() == Qt::MetaModifier) { text = tr("Meta"); key = Qt::Key_Meta; } - - setText(old_text); - emit KeyAssigned(id, key, text); - - inputGrabbed = false; - - // TODO: Keys like "return" cause another keyPressEvent to be generated after this one... - } - - QPushButton::keyPressEvent(event); // TODO: Necessary? -} - -void GKeyConfigButton::mousePressEvent(QMouseEvent* event) -{ - // Abort key assignment - if (inputGrabbed) - { - releaseKeyboard(); - releaseMouse(); - setText(old_text); - inputGrabbed = false; - } - - QAbstractButton::mousePressEvent(event); -} - -GButtonConfigGroup::GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent) : QWidget(parent), id(id) -{ - QHBoxLayout* layout = new QHBoxLayout(this); - - QPushButton* clear_button = new QPushButton(tr("Clear")); - - layout->addWidget(new QLabel(name, this)); - layout->addWidget(config_button = new GKeyConfigButton(id, QString(), change_receiver, this)); - layout->addWidget(clear_button); - - // TODO: connect config_button, clear_button - - setLayout(layout); -} - -*/ \ No newline at end of file diff --git a/src/citra_qt/src/config/controller_config_util.hxx b/src/citra_qt/src/config/controller_config_util.hxx deleted file mode 100644 index af38f126..00000000 --- a/src/citra_qt/src/config/controller_config_util.hxx +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef _CONTROLLER_CONFIG_UTIL_HXX_ -#define _CONTROLLER_CONFIG_UTIL_HXX_ - -#include -#include - -/* TODO(bunnei): ImplementMe - -#include "config.h" - -class GStickConfig : public QWidget -{ - Q_OBJECT - -public: - // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! - GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent = NULL); - -signals: - void LeftChanged(); - void RightChanged(); - void UpChanged(); - void DownChanged(); - -private: - QPushButton* left; - QPushButton* right; - QPushButton* up; - QPushButton* down; - - QPushButton* clear; -}; - -class GKeyConfigButton : public QPushButton -{ - Q_OBJECT - -public: - // TODO: change_receiver also needs to have an ActivePortChanged(const common::Config::ControllerPort&) signal - // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! - GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent); - GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent); - -signals: - void KeyAssigned(common::Config::Control id, int key, const QString& text); - -private slots: - void OnActivePortChanged(const common::Config::ControllerPort& config); - - void OnClicked(); - - void keyPressEvent(QKeyEvent* event); // TODO: bGrabbed? - void mousePressEvent(QMouseEvent* event); - -private: - common::Config::Control id; - bool inputGrabbed; - - QString old_text; -}; - -class GButtonConfigGroup : public QWidget -{ - Q_OBJECT - -public: - // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot! - GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent = NULL); - -private: - GKeyConfigButton* config_button; - - common::Config::Control id; -}; - -*/ - -#endif // _CONTROLLER_CONFIG_HXX_ diff --git a/src/citra_qt/src/config/ui_controller_config.h b/src/citra_qt/src/config/ui_controller_config.h deleted file mode 100644 index f84364a7..00000000 --- a/src/citra_qt/src/config/ui_controller_config.h +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'controller_config.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_CONTROLLER_CONFIG_H -#define UI_CONTROLLER_CONFIG_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_ControllerConfig -{ -public: - QVBoxLayout *verticalLayout; - QGridLayout *gridLayout; - QComboBox *activeControllerCB; - QSpacerItem *horizontalSpacer; - QCheckBox *checkBox; - QComboBox *inputSourceCB; - QLabel *label_2; - QLabel *label; - QTabWidget *tabWidget; - QWidget *mainStickTab; - QGridLayout *gridLayout_3; - QSpacerItem *verticalSpacer_2; - QSpacerItem *verticalSpacer_3; - QSpacerItem *horizontalSpacer_4; - QSpacerItem *horizontalSpacer_3; - QWidget *cStickTab; - QGridLayout *gridLayout_4; - QSpacerItem *horizontalSpacer_6; - QSpacerItem *verticalSpacer_5; - QSpacerItem *verticalSpacer_4; - QSpacerItem *horizontalSpacer_5; - QWidget *dPadTab; - QGridLayout *gridLayout_5; - QSpacerItem *horizontalSpacer_7; - QSpacerItem *verticalSpacer_7; - QSpacerItem *verticalSpacer_6; - QSpacerItem *horizontalSpacer_8; - QWidget *buttonsTab; - QVBoxLayout *verticalLayout_2; - - void setupUi(QWidget *ControllerConfig) - { - if (ControllerConfig->objectName().isEmpty()) - ControllerConfig->setObjectName(QString::fromUtf8("ControllerConfig")); - ControllerConfig->resize(503, 293); - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(ControllerConfig->sizePolicy().hasHeightForWidth()); - ControllerConfig->setSizePolicy(sizePolicy); - verticalLayout = new QVBoxLayout(ControllerConfig); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - verticalLayout->setSizeConstraint(QLayout::SetFixedSize); - gridLayout = new QGridLayout(); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - activeControllerCB = new QComboBox(ControllerConfig); - activeControllerCB->setObjectName(QString::fromUtf8("activeControllerCB")); - - gridLayout->addWidget(activeControllerCB, 1, 1, 1, 1); - - horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout->addItem(horizontalSpacer, 0, 2, 1, 1); - - checkBox = new QCheckBox(ControllerConfig); - checkBox->setObjectName(QString::fromUtf8("checkBox")); - - gridLayout->addWidget(checkBox, 1, 2, 1, 1); - - inputSourceCB = new QComboBox(ControllerConfig); - inputSourceCB->setObjectName(QString::fromUtf8("inputSourceCB")); - - gridLayout->addWidget(inputSourceCB, 0, 1, 1, 1); - - label_2 = new QLabel(ControllerConfig); - label_2->setObjectName(QString::fromUtf8("label_2")); - - gridLayout->addWidget(label_2, 1, 0, 1, 1); - - label = new QLabel(ControllerConfig); - label->setObjectName(QString::fromUtf8("label")); - - gridLayout->addWidget(label, 0, 0, 1, 1); - - - verticalLayout->addLayout(gridLayout); - - tabWidget = new QTabWidget(ControllerConfig); - tabWidget->setObjectName(QString::fromUtf8("tabWidget")); - mainStickTab = new QWidget(); - mainStickTab->setObjectName(QString::fromUtf8("mainStickTab")); - gridLayout_3 = new QGridLayout(mainStickTab); - gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3")); - verticalSpacer_2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_3->addItem(verticalSpacer_2, 2, 2, 1, 1); - - verticalSpacer_3 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_3->addItem(verticalSpacer_3, 0, 2, 1, 1); - - horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_3->addItem(horizontalSpacer_4, 1, 0, 1, 1); - - horizontalSpacer_3 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_3->addItem(horizontalSpacer_3, 1, 4, 1, 1); - - tabWidget->addTab(mainStickTab, QString()); - cStickTab = new QWidget(); - cStickTab->setObjectName(QString::fromUtf8("cStickTab")); - gridLayout_4 = new QGridLayout(cStickTab); - gridLayout_4->setObjectName(QString::fromUtf8("gridLayout_4")); - horizontalSpacer_6 = new QSpacerItem(40, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_4->addItem(horizontalSpacer_6, 1, 0, 1, 1); - - verticalSpacer_5 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_4->addItem(verticalSpacer_5, 0, 1, 1, 1); - - verticalSpacer_4 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_4->addItem(verticalSpacer_4, 2, 1, 1, 1); - - horizontalSpacer_5 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_4->addItem(horizontalSpacer_5, 1, 2, 1, 1); - - tabWidget->addTab(cStickTab, QString()); - dPadTab = new QWidget(); - dPadTab->setObjectName(QString::fromUtf8("dPadTab")); - gridLayout_5 = new QGridLayout(dPadTab); - gridLayout_5->setObjectName(QString::fromUtf8("gridLayout_5")); - horizontalSpacer_7 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_5->addItem(horizontalSpacer_7, 1, 2, 1, 1); - - verticalSpacer_7 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_5->addItem(verticalSpacer_7, 0, 1, 1, 1); - - verticalSpacer_6 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - gridLayout_5->addItem(verticalSpacer_6, 2, 1, 1, 1); - - horizontalSpacer_8 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - gridLayout_5->addItem(horizontalSpacer_8, 1, 0, 1, 1); - - tabWidget->addTab(dPadTab, QString()); - buttonsTab = new QWidget(); - buttonsTab->setObjectName(QString::fromUtf8("buttonsTab")); - verticalLayout_2 = new QVBoxLayout(buttonsTab); - verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); - tabWidget->addTab(buttonsTab, QString()); - - verticalLayout->addWidget(tabWidget); - - - retranslateUi(ControllerConfig); - - tabWidget->setCurrentIndex(0); - - - QMetaObject::connectSlotsByName(ControllerConfig); - } // setupUi - - void retranslateUi(QWidget *ControllerConfig) - { - ControllerConfig->setWindowTitle(QApplication::translate("ControllerConfig", "Controller Configuration", 0, QApplication::UnicodeUTF8)); - activeControllerCB->clear(); - activeControllerCB->insertItems(0, QStringList() - << QApplication::translate("ControllerConfig", "Controller 1", 0, QApplication::UnicodeUTF8) - << QApplication::translate("ControllerConfig", "Controller 2", 0, QApplication::UnicodeUTF8) - << QApplication::translate("ControllerConfig", "Controller 3", 0, QApplication::UnicodeUTF8) - << QApplication::translate("ControllerConfig", "Controller 4", 0, QApplication::UnicodeUTF8) - ); - checkBox->setText(QApplication::translate("ControllerConfig", "Enabled", 0, QApplication::UnicodeUTF8)); - inputSourceCB->clear(); - inputSourceCB->insertItems(0, QStringList() - << QApplication::translate("ControllerConfig", "Keyboard", 0, QApplication::UnicodeUTF8) - << QApplication::translate("ControllerConfig", "Joypad", 0, QApplication::UnicodeUTF8) - ); - label_2->setText(QApplication::translate("ControllerConfig", "Active Controller:", 0, QApplication::UnicodeUTF8)); - label->setText(QApplication::translate("ControllerConfig", "Input Source:", 0, QApplication::UnicodeUTF8)); - tabWidget->setTabText(tabWidget->indexOf(mainStickTab), QApplication::translate("ControllerConfig", "Main Stick", 0, QApplication::UnicodeUTF8)); - tabWidget->setTabText(tabWidget->indexOf(cStickTab), QApplication::translate("ControllerConfig", "C-Stick", 0, QApplication::UnicodeUTF8)); - tabWidget->setTabText(tabWidget->indexOf(dPadTab), QApplication::translate("ControllerConfig", "D-Pad", 0, QApplication::UnicodeUTF8)); - tabWidget->setTabText(tabWidget->indexOf(buttonsTab), QApplication::translate("ControllerConfig", "Buttons", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class ControllerConfig: public Ui_ControllerConfig {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_CONTROLLER_CONFIG_H diff --git a/src/citra_qt/src/cpu_regs.cpp b/src/citra_qt/src/cpu_regs.cpp deleted file mode 100644 index f2859f69..00000000 --- a/src/citra_qt/src/cpu_regs.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "cpu_regs.hxx" - -#include "core.h" -#include "arm/interpreter/armdefs.h" - -GARM11RegsView::GARM11RegsView(QWidget* parent) : QDockWidget(parent) -{ - cpu_regs_ui.setupUi(this); - - tree = cpu_regs_ui.treeWidget; - tree->addTopLevelItem(registers = new QTreeWidgetItem(QStringList("Registers"))); - tree->addTopLevelItem(CSPR = new QTreeWidgetItem(QStringList("CSPR"))); - - registers->setExpanded(true); - CSPR->setExpanded(true); - - for (int i = 0; i < 16; ++i) - { - QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0')))); - registers->addChild(child); - } - - CSPR->addChild(new QTreeWidgetItem(QStringList("M"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("T"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("F"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("I"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("A"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("E"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("IT"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("GE"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("DNM"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("J"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("Q"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("V"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("C"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("Z"))); - CSPR->addChild(new QTreeWidgetItem(QStringList("N"))); -} - -void GARM11RegsView::OnCPUStepped() -{ - ARM_Interface* app_core = Core::g_app_core; - - for (int i = 0; i < 16; ++i) - registers->child(i)->setText(1, QString("0x%1").arg(app_core->Reg(i), 8, 16, QLatin1Char('0'))); - - CSPR->setText(1, QString("0x%1").arg(app_core->CPSR(), 8, 16, QLatin1Char('0'))); - CSPR->child(0)->setText(1, QString("b%1").arg(app_core->CPSR() & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode - CSPR->child(1)->setText(1, QString("%1").arg((app_core->CPSR() >> 5) & 0x1)); // T - State - CSPR->child(2)->setText(1, QString("%1").arg((app_core->CPSR() >> 6) & 0x1)); // F - FIQ disable - CSPR->child(3)->setText(1, QString("%1").arg((app_core->CPSR() >> 7) & 0x1)); // I - IRQ disable - CSPR->child(4)->setText(1, QString("%1").arg((app_core->CPSR() >> 8) & 0x1)); // A - Imprecise abort - CSPR->child(5)->setText(1, QString("%1").arg((app_core->CPSR() >> 9) & 0x1)); // E - Data endianess - CSPR->child(6)->setText(1, QString("%1").arg((app_core->CPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM) - CSPR->child(7)->setText(1, QString("%1").arg((app_core->CPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal - CSPR->child(8)->setText(1, QString("%1").arg((app_core->CPSR() >> 20) & 0xF)); // DNM - Do not modify - CSPR->child(9)->setText(1, QString("%1").arg((app_core->CPSR() >> 24) & 0x1)); // J - Java state - CSPR->child(10)->setText(1, QString("%1").arg((app_core->CPSR() >> 27) & 0x1)); // Q - Sticky overflow - CSPR->child(11)->setText(1, QString("%1").arg((app_core->CPSR() >> 28) & 0x1)); // V - Overflow - CSPR->child(12)->setText(1, QString("%1").arg((app_core->CPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend - CSPR->child(13)->setText(1, QString("%1").arg((app_core->CPSR() >> 30) & 0x1)); // Z - Zero - CSPR->child(14)->setText(1, QString("%1").arg((app_core->CPSR() >> 31) & 0x1)); // N - Negative/Less than -} diff --git a/src/citra_qt/src/cpu_regs.hxx b/src/citra_qt/src/cpu_regs.hxx deleted file mode 100644 index 27c194bd..00000000 --- a/src/citra_qt/src/cpu_regs.hxx +++ /dev/null @@ -1,27 +0,0 @@ -#include "ui_cpu_regs.h" - -#include -#include - -//#include "ui_gekko_regs.h" - -class QTreeWidget; - -class GARM11RegsView : public QDockWidget -{ - Q_OBJECT - -public: - GARM11RegsView(QWidget* parent = NULL); - -public slots: - void OnCPUStepped(); - -private: - Ui::ARMRegisters cpu_regs_ui; - - QTreeWidget* tree; - - QTreeWidgetItem* registers; - QTreeWidgetItem* CSPR; -}; diff --git a/src/citra_qt/src/cpu_regs.ui b/src/citra_qt/src/cpu_regs.ui deleted file mode 100644 index 6537c9cd..00000000 --- a/src/citra_qt/src/cpu_regs.ui +++ /dev/null @@ -1,40 +0,0 @@ - - - ARMRegisters - - - - 0 - 0 - 400 - 300 - - - - ARM registers - - - - - - - true - - - - Register - - - - - Value - - - - - - - - - - diff --git a/src/citra_qt/src/disasm.cpp b/src/citra_qt/src/disasm.cpp deleted file mode 100644 index ddcbf69d..00000000 --- a/src/citra_qt/src/disasm.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include "ui_disasm.h" -#include "disasm.hxx" - -#include "bootmanager.hxx" -#include "hotkeys.hxx" - -#include "common.h" -#include "mem_map.h" - -#include "core.h" -#include "break_points.h" -#include "arm/interpreter/armdefs.h" -#include "arm/disassembler/arm_disasm.h" - -GDisAsmView::GDisAsmView(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) -{ - disasm_ui.setupUi(this); - - breakpoints = new BreakPoints(); - - model = new QStandardItemModel(this); - model->setColumnCount(2); - disasm_ui.treeView->setModel(model); - - 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()), this, SLOT(OnSetBreakpoint())); - 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(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()), this, SLOT(OnSetBreakpoint())); -} - -void GDisAsmView::Init() -{ - ARM_Disasm* disasm = new ARM_Disasm(); - - base_addr = Core::g_app_core->PC(); - unsigned int curInstAddr = base_addr; - char result[255]; - - for (int i = 0; i < 10000; i++) // fixed for now - { - disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); - model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); - model->setItem(i, 1, new QStandardItem(QString(result))); - curInstAddr += 4; - } - disasm_ui.treeView->resizeColumnToContents(0); - disasm_ui.treeView->resizeColumnToContents(1); - - QModelIndex model_index = model->index(0, 0); - disasm_ui.treeView->scrollTo(model_index); - disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); -} - -void GDisAsmView::OnSetBreakpoint() -{ - int selected_row = SelectedRow(); - - if (selected_row == -1) - return; - - u32 address = base_addr + (selected_row * 4); - if (breakpoints->IsAddressBreakPoint(address)) - { - breakpoints->Remove(address); - model->item(selected_row, 0)->setBackground(QBrush()); - model->item(selected_row, 1)->setBackground(QBrush()); - } - else - { - breakpoints->Add(address); - model->item(selected_row, 0)->setBackground(QBrush(QColor(0xFF, 0x99, 0x99))); - model->item(selected_row, 1)->setBackground(QBrush(QColor(0xFF, 0x99, 0x99))); - } -} - -void GDisAsmView::OnContinue() -{ - emu_thread.SetCpuRunning(true); -} - -void GDisAsmView::OnStep() -{ - OnStepInto(); // change later -} - -void GDisAsmView::OnStepInto() -{ - emu_thread.SetCpuRunning(false); - emu_thread.ExecStep(); -} - -void GDisAsmView::OnPause() -{ - emu_thread.SetCpuRunning(false); -} - -void GDisAsmView::OnToggleStartStop() -{ - emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning()); -} - -void GDisAsmView::OnCPUStepped() -{ - ARMword next_instr = Core::g_app_core->PC(); - - if (breakpoints->IsAddressBreakPoint(next_instr)) - { - emu_thread.SetCpuRunning(false); - } - - unsigned int index = (next_instr - base_addr) / 4; - QModelIndex model_index = model->index(index, 0); - disasm_ui.treeView->scrollTo(model_index); - disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); -} - -int GDisAsmView::SelectedRow() -{ - QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); - if (!index.isValid()) - return -1; - - return model->itemFromIndex(disasm_ui.treeView->selectionModel()->currentIndex())->row(); -} \ No newline at end of file diff --git a/src/citra_qt/src/disasm.hxx b/src/citra_qt/src/disasm.hxx deleted file mode 100644 index 0e4a0fc3..00000000 --- a/src/citra_qt/src/disasm.hxx +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include "ui_disasm.h" - -#include "common.h" -#include "break_points.h" - -class QAction; -class QStandardItemModel; -class EmuThread; - -class GDisAsmView : public QDockWidget -{ - Q_OBJECT - -public: - GDisAsmView(QWidget* parent, EmuThread& emu_thread); - - void Init(); - -public slots: - void OnSetBreakpoint(); - void OnContinue(); - void OnStep(); - void OnStepInto(); - void OnPause(); - void OnToggleStartStop(); - - void OnCPUStepped(); - -private: - // returns -1 if no row is selected - int SelectedRow(); - - Ui::DockWidget disasm_ui; - QStandardItemModel* model; - - u32 base_addr; - - BreakPoints* breakpoints; - - EmuThread& emu_thread; -}; diff --git a/src/citra_qt/src/disasm.ui b/src/citra_qt/src/disasm.ui deleted file mode 100644 index fb384516..00000000 --- a/src/citra_qt/src/disasm.ui +++ /dev/null @@ -1,78 +0,0 @@ - - - DockWidget - - - - 0 - 0 - 430 - 401 - - - - Disassembly - - - - - - - - - Step - - - - - - - Pause - - - - - - - Continue - - - - - - - Step Into - - - - - - - Set Breakpoint - - - - - - - - - true - - - 20 - - - false - - - false - - - - - - - - - diff --git a/src/citra_qt/src/hotkeys.cpp b/src/citra_qt/src/hotkeys.cpp deleted file mode 100644 index 1aa1e8b9..00000000 --- a/src/citra_qt/src/hotkeys.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include -#include "hotkeys.hxx" -#include - -struct Hotkey -{ - Hotkey() : shortcut(NULL), context(Qt::WindowShortcut) {} - - QKeySequence keyseq; - QShortcut* shortcut; - Qt::ShortcutContext context; -}; - -typedef std::map HotkeyMap; -typedef std::map HotkeyGroupMap; - -HotkeyGroupMap hotkey_groups; - -void SaveHotkeys(QSettings& settings) -{ - settings.beginGroup("Shortcuts"); - - for (HotkeyGroupMap::iterator group = hotkey_groups.begin(); group != hotkey_groups.end(); ++group) - { - settings.beginGroup(group->first); - for (HotkeyMap::iterator hotkey = group->second.begin(); hotkey != group->second.end(); ++hotkey) - { - settings.beginGroup(hotkey->first); - settings.setValue(QString("KeySeq"), hotkey->second.keyseq.toString()); - settings.setValue(QString("Context"), hotkey->second.context); - settings.endGroup(); - } - settings.endGroup(); - } - settings.endGroup(); -} - -void LoadHotkeys(QSettings& settings) -{ - settings.beginGroup("Shortcuts"); - - // Make sure NOT to use a reference here because it would become invalid once we call beginGroup() - QStringList groups = settings.childGroups(); - for (QList::iterator group = groups.begin(); group != groups.end(); ++group) - { - settings.beginGroup(*group); - - QStringList hotkeys = settings.childGroups(); - for (QList::iterator hotkey = hotkeys.begin(); hotkey != hotkeys.end(); ++hotkey) - { - settings.beginGroup(*hotkey); - - // RegisterHotkey assigns default keybindings, so use old values as default parameters - Hotkey& hk = hotkey_groups[*group][*hotkey]; - hk.keyseq = QKeySequence::fromString(settings.value("KeySeq", hk.keyseq.toString()).toString()); - hk.context = (Qt::ShortcutContext)settings.value("Context", hk.context).toInt(); - if (hk.shortcut) - hk.shortcut->setKey(hk.keyseq); - - settings.endGroup(); - } - - settings.endGroup(); - } - - settings.endGroup(); -} - -void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, Qt::ShortcutContext default_context) -{ - if (hotkey_groups[group].find(action) == hotkey_groups[group].end()) - { - hotkey_groups[group][action].keyseq = default_keyseq; - hotkey_groups[group][action].context = default_context; - } -} - -QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget) -{ - Hotkey& hk = hotkey_groups[group][action]; - - if (!hk.shortcut) - hk.shortcut = new QShortcut(hk.keyseq, widget, NULL, NULL, hk.context); - - return hk.shortcut; -} - - -GHotkeysDialog::GHotkeysDialog(QWidget* parent): QDialog(parent) -{ - ui.setupUi(this); - - for (HotkeyGroupMap::iterator group = hotkey_groups.begin(); group != hotkey_groups.end(); ++group) - { - QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group->first)); - for (HotkeyMap::iterator hotkey = group->second.begin(); hotkey != group->second.end(); ++hotkey) - { - QStringList columns; - columns << hotkey->first << hotkey->second.keyseq.toString(); - QTreeWidgetItem* item = new QTreeWidgetItem(columns); - toplevel_item->addChild(item); - } - ui.treeWidget->addTopLevelItem(toplevel_item); - } - // TODO: Make context configurable as well (hiding the column for now) - ui.treeWidget->setColumnCount(2); - - ui.treeWidget->resizeColumnToContents(0); - ui.treeWidget->resizeColumnToContents(1); -} diff --git a/src/citra_qt/src/hotkeys.hxx b/src/citra_qt/src/hotkeys.hxx deleted file mode 100644 index 66ef7bb4..00000000 --- a/src/citra_qt/src/hotkeys.hxx +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include "ui_hotkeys.h" - -class QKeySequence; -class QSettings; - -/** - * Register a hotkey. - * - * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") - * @param action Name of the action (e.g. "Start Emulation", "Load Image") - * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the settings file before - * @param default_context Default context to assign if the hotkey wasn't present in the settings file before - * @warning Both the group and action strings will be displayed in the hotkey settings dialog - */ -void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq = QKeySequence(), Qt::ShortcutContext default_context = Qt::WindowShortcut); - -/** - * Returns a QShortcut object whose activated() signal can be connected to other QObjects' slots. - * - * @param widget Parent widget of the returned QShortcut. - * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut will be the same. Thus, you shouldn't rely on the caller really being the QShortcut's parent. - */ -QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); - -/** - * Saves all registered hotkeys to the settings file. - * - * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a settings group will be created to store the key sequence and the hotkey context. - */ -void SaveHotkeys(QSettings& settings); - -/** - * Loads hotkeys from the settings file. - * - * @note Yet unregistered hotkeys which are present in the settings will automatically be registered. - */ -void LoadHotkeys(QSettings& settings); - -class GHotkeysDialog : public QDialog -{ - Q_OBJECT - -public: - GHotkeysDialog(QWidget* parent = NULL); - -private: - Ui::hotkeys ui; -}; diff --git a/src/citra_qt/src/hotkeys.ui b/src/citra_qt/src/hotkeys.ui deleted file mode 100644 index 38a9a14d..00000000 --- a/src/citra_qt/src/hotkeys.ui +++ /dev/null @@ -1,89 +0,0 @@ - - - hotkeys - - - - 0 - 0 - 363 - 388 - - - - Hotkey Settings - - - - - - QAbstractItemView::SelectItems - - - false - - - - Action - - - - - Hotkey - - - - - Context - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset - - - - - - - - - buttonBox - accepted() - hotkeys - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - hotkeys - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/citra_qt/src/main.cpp b/src/citra_qt/src/main.cpp deleted file mode 100644 index d7104eb0..00000000 --- a/src/citra_qt/src/main.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include -#include "qhexedit.h" -#include "main.hxx" - -#include "common.h" -#include "platform.h" -#if EMU_PLATFORM == PLATFORM_LINUX -#include -#endif - -#include "bootmanager.hxx" -#include "hotkeys.hxx" - -//debugger -#include "disasm.hxx" -#include "cpu_regs.hxx" -#include "callstack.hxx" -#include "ramview.hxx" - -#include "system.h" -#include "loader.h" -#include "core.h" -#include "version.h" - - -GMainWindow::GMainWindow() -{ - ui.setupUi(this); - statusBar()->hide(); - - render_window = new GRenderWindow; - render_window->hide(); - - disasm = new GDisAsmView(this, render_window->GetEmuThread()); - addDockWidget(Qt::BottomDockWidgetArea, disasm); - disasm->hide(); - - arm_regs = new GARM11RegsView(this); - addDockWidget(Qt::RightDockWidgetArea, arm_regs); - arm_regs->hide(); - - QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); - debug_menu->addAction(disasm->toggleViewAction()); - debug_menu->addAction(arm_regs->toggleViewAction()); - - // Set default UI state - // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half - QDesktopWidget* desktop = ((QApplication*)QApplication::instance())->desktop(); - QRect screenRect = desktop->screenGeometry(this); - int x, y, w, h; - w = screenRect.width() * 2 / 3; - h = screenRect.height() / 2; - x = (screenRect.x() + screenRect.width()) / 2 - w / 2; - y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100; - setGeometry(x, y, w, h); - - - // Restore UI state - QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); - restoreGeometry(settings.value("geometry").toByteArray()); - restoreState(settings.value("state").toByteArray()); - render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray()); - - ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", false).toBool()); - SetupEmuWindowMode(); - - // Setup connections - connect(ui.action_load_elf, SIGNAL(triggered()), this, SLOT(OnMenuLoadELF())); - connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); - connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); - connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); - connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(SetupEmuWindowMode())); - 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(CPUStepped()), disasm, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); - connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), arm_regs, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); - - // Setup hotkeys - RegisterHotkey("Main Window", "Load Image", QKeySequence::Open); - RegisterHotkey("Main Window", "Start Emulation"); - LoadHotkeys(settings); - - connect(GetHotkey("Main Window", "Load Image", this), SIGNAL(activated()), this, SLOT(OnMenuLoadImage())); - connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); - - show(); - - System::Init(render_window); -} - -GMainWindow::~GMainWindow() -{ - // will get automatically deleted otherwise - if (render_window->parent() == NULL) - delete render_window; -} - -void GMainWindow::BootGame(const char* filename) -{ - render_window->DoneCurrent(); // make sure EmuThread can access GL context - render_window->GetEmuThread().SetFilename(filename); - - NOTICE_LOG(MASTER_LOG, "citra starting...\n"); - - if (Core::Init(/*render_window*/)) { - ERROR_LOG(MASTER_LOG, "core initialization failed, exiting..."); - Core::Stop(); - exit(1); - } - - // Load a game or die... - std::string boot_filename = filename; - std::string error_str; - bool res = Loader::LoadFile(boot_filename, &error_str); - - if (!res) { - ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str()); - } - - disasm->Init(); - arm_regs->OnCPUStepped(); - - render_window->GetEmuThread().start(); - - SetupEmuWindowMode(); - render_window->show(); -} - -void GMainWindow::OnMenuLoadELF() -{ - QString filename = QFileDialog::getOpenFileName(this, tr("Load ELF"), QString(), QString()); - if (filename.size()) - BootGame(filename.toLatin1().data()); -} - -void GMainWindow::OnStartGame() -{ - render_window->show(); - render_window->GetEmuThread().SetCpuRunning(true); - - ui.action_Start->setEnabled(false); - ui.action_Pause->setEnabled(true); - ui.action_Stop->setEnabled(true); -} - -void GMainWindow::OnPauseGame() -{ - render_window->GetEmuThread().SetCpuRunning(false); - - ui.action_Start->setEnabled(true); - ui.action_Pause->setEnabled(false); - ui.action_Stop->setEnabled(true); -} - -void GMainWindow::OnStopGame() -{ - render_window->GetEmuThread().SetCpuRunning(false); - - ui.action_Start->setEnabled(true); - ui.action_Pause->setEnabled(false); - ui.action_Stop->setEnabled(false); -} - -void GMainWindow::OnOpenHotkeysDialog() -{ - GHotkeysDialog dialog(this); - dialog.exec(); -} - - -void GMainWindow::SetupEmuWindowMode() -{ - //if (!render_window->GetEmuThread().isRunning()) - // return; - - bool enable = ui.action_Single_Window_Mode->isChecked(); - if (enable && render_window->parent() == NULL) // switch to single window mode - { - render_window->BackupGeometry(); - ui.horizontalLayout->addWidget(render_window); - render_window->setVisible(true); - render_window->DoneCurrent(); - } - else if (!enable && render_window->parent() != NULL) // switch to multiple windows mode - { - ui.horizontalLayout->removeWidget(render_window); - render_window->setParent(NULL); - render_window->setVisible(true); - render_window->DoneCurrent(); - render_window->RestoreGeometry(); - } -} - -void GMainWindow::OnConfigure() -{ - //GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this); -} - -void GMainWindow::closeEvent(QCloseEvent* event) -{ - // Save window layout - QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); - settings.setValue("geometry", saveGeometry()); - settings.setValue("state", saveState()); - settings.setValue("geometryRenderWindow", render_window->saveGeometry()); - settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); - settings.setValue("firstStart", false); - SaveHotkeys(settings); - - render_window->close(); - - QWidget::closeEvent(event); -} - -#ifdef main -#undef main -#endif - -int __cdecl main(int argc, char* argv[]) -{ - QApplication::setAttribute(Qt::AA_X11InitThreads); - QApplication app(argc, argv); - GMainWindow main_window; - - main_window.show(); - return app.exec(); -} diff --git a/src/citra_qt/src/main.hxx b/src/citra_qt/src/main.hxx deleted file mode 100644 index 34bd2c3a..00000000 --- a/src/citra_qt/src/main.hxx +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _CITRA_QT_MAIN_HXX_ -#define _CITRA_QT_MAIN_HXX_ - -#include - -#include "ui_main.h" - -class GImageInfo; -class GRenderWindow; -class GDisAsmView; -class GARM11RegsView; - -class GMainWindow : public QMainWindow -{ - Q_OBJECT - - // TODO: Make use of this! - enum { - UI_IDLE, - UI_EMU_BOOTING, - UI_EMU_RUNNING, - UI_EMU_STOPPING, - }; - -public: - GMainWindow(); - ~GMainWindow(); - -private: - void BootGame(const char* filename); - - void closeEvent(QCloseEvent* event); - -private slots: - void OnStartGame(); - void OnPauseGame(); - void OnStopGame(); - void OnMenuLoadELF(); - void OnOpenHotkeysDialog(); - void SetupEmuWindowMode(); - void OnConfigure(); - -private: - Ui::MainWindow ui; - - GRenderWindow* render_window; - GDisAsmView* disasm; - GARM11RegsView* arm_regs; -}; - -#endif // _CITRA_QT_MAIN_HXX_ diff --git a/src/citra_qt/src/main.ui b/src/citra_qt/src/main.ui deleted file mode 100644 index bc895d89..00000000 --- a/src/citra_qt/src/main.ui +++ /dev/null @@ -1,168 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1081 - 730 - - - - Citra - - - - src/pcafe/res/icon3_64x64.icosrc/pcafe/res/icon3_64x64.ico - - - QTabWidget::Rounded - - - true - - - - - - - - 0 - 0 - 1081 - 20 - - - - - &File - - - - - - - - &Emulation - - - - - - - - - - &View - - - - - - - &Help - - - - - - - - - - - - Load ELF ... - - - - - E&xit - - - - - &Start - - - - - false - - - &Pause - - - - - false - - - &Stop - - - - - About Citra - - - - - true - - - Single Window Mode - - - - - Configure &Hotkeys ... - - - - - Configure ... - - - - - - - action_Exit - triggered() - MainWindow - close() - - - -1 - -1 - - - 367 - 314 - - - - - action_Configure - triggered() - MainWindow - OnConfigure() - - - -1 - -1 - - - 540 - 364 - - - - - - OnConfigure() - - diff --git a/src/citra_qt/src/ramview.cpp b/src/citra_qt/src/ramview.cpp deleted file mode 100644 index 8cc252af..00000000 --- a/src/citra_qt/src/ramview.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "ramview.hxx" - -#include "common.h" -#include "memory.h" -GRamView::GRamView(QWidget* parent) : QHexEdit(parent) -{ -} - -void GRamView::OnCPUStepped() -{ - // TODO: QHexEdit doesn't show vertical scroll bars for > 10MB data streams... - //setData(QByteArray((const char*)Mem_RAM,sizeof(Mem_RAM)/8)); -} \ No newline at end of file diff --git a/src/citra_qt/src/ramview.hxx b/src/citra_qt/src/ramview.hxx deleted file mode 100644 index 1db1546a..00000000 --- a/src/citra_qt/src/ramview.hxx +++ /dev/null @@ -1,12 +0,0 @@ -#include "qhexedit.h" - -class GRamView : public QHexEdit -{ - Q_OBJECT - -public: - GRamView(QWidget* parent = NULL); - -public slots: - void OnCPUStepped(); -}; diff --git a/src/citra_qt/src/ui_callstack.h b/src/citra_qt/src/ui_callstack.h deleted file mode 100644 index 75d10253..00000000 --- a/src/citra_qt/src/ui_callstack.h +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'callstack.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_CALLSTACK_H -#define UI_CALLSTACK_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_CallStack -{ -public: - QWidget *dockWidgetContents; - QVBoxLayout *verticalLayout; - QTreeView *treeView; - - void setupUi(QDockWidget *CallStack) - { - if (CallStack->objectName().isEmpty()) - CallStack->setObjectName(QString::fromUtf8("CallStack")); - CallStack->resize(400, 300); - dockWidgetContents = new QWidget(); - dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); - verticalLayout = new QVBoxLayout(dockWidgetContents); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - treeView = new QTreeView(dockWidgetContents); - treeView->setObjectName(QString::fromUtf8("treeView")); - treeView->setAlternatingRowColors(true); - treeView->setRootIsDecorated(false); - treeView->setItemsExpandable(false); - - verticalLayout->addWidget(treeView); - - CallStack->setWidget(dockWidgetContents); - - retranslateUi(CallStack); - - QMetaObject::connectSlotsByName(CallStack); - } // setupUi - - void retranslateUi(QDockWidget *CallStack) - { - CallStack->setWindowTitle(QApplication::translate("CallStack", "Call stack", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class CallStack: public Ui_CallStack {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_CALLSTACK_H diff --git a/src/citra_qt/src/ui_cpu_regs.h b/src/citra_qt/src/ui_cpu_regs.h deleted file mode 100644 index b8a80b3f..00000000 --- a/src/citra_qt/src/ui_cpu_regs.h +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'cpu_regs.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_CPU_REGS_H -#define UI_CPU_REGS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_ARMRegisters -{ -public: - QWidget *dockWidgetContents; - QVBoxLayout *verticalLayout; - QTreeWidget *treeWidget; - - void setupUi(QDockWidget *ARMRegisters) - { - if (ARMRegisters->objectName().isEmpty()) - ARMRegisters->setObjectName(QString::fromUtf8("ARMRegisters")); - ARMRegisters->resize(400, 300); - dockWidgetContents = new QWidget(); - dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); - verticalLayout = new QVBoxLayout(dockWidgetContents); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - treeWidget = new QTreeWidget(dockWidgetContents); - treeWidget->setObjectName(QString::fromUtf8("treeWidget")); - treeWidget->setAlternatingRowColors(true); - - verticalLayout->addWidget(treeWidget); - - ARMRegisters->setWidget(dockWidgetContents); - - retranslateUi(ARMRegisters); - - QMetaObject::connectSlotsByName(ARMRegisters); - } // setupUi - - void retranslateUi(QDockWidget *ARMRegisters) - { - ARMRegisters->setWindowTitle(QApplication::translate("ARMRegisters", "ARM registers", 0, QApplication::UnicodeUTF8)); - QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); - ___qtreewidgetitem->setText(1, QApplication::translate("ARMRegisters", "Value", 0, QApplication::UnicodeUTF8)); - ___qtreewidgetitem->setText(0, QApplication::translate("ARMRegisters", "Register", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class ARMRegisters: public Ui_ARMRegisters {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_CPU_REGS_H diff --git a/src/citra_qt/src/ui_disasm.h b/src/citra_qt/src/ui_disasm.h deleted file mode 100644 index 697a224c..00000000 --- a/src/citra_qt/src/ui_disasm.h +++ /dev/null @@ -1,112 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'disasm.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_DISASM_H -#define UI_DISASM_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_DockWidget -{ -public: - QWidget *dockWidgetContents; - QVBoxLayout *verticalLayout; - QHBoxLayout *horizontalLayout; - QPushButton *button_step; - QPushButton *button_pause; - QPushButton *button_continue; - QPushButton *pushButton; - QPushButton *button_breakpoint; - QTreeView *treeView; - - void setupUi(QDockWidget *DockWidget) - { - if (DockWidget->objectName().isEmpty()) - DockWidget->setObjectName(QString::fromUtf8("DockWidget")); - DockWidget->resize(430, 401); - dockWidgetContents = new QWidget(); - dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); - verticalLayout = new QVBoxLayout(dockWidgetContents); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - horizontalLayout = new QHBoxLayout(); - horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); - button_step = new QPushButton(dockWidgetContents); - button_step->setObjectName(QString::fromUtf8("button_step")); - - horizontalLayout->addWidget(button_step); - - button_pause = new QPushButton(dockWidgetContents); - button_pause->setObjectName(QString::fromUtf8("button_pause")); - - horizontalLayout->addWidget(button_pause); - - button_continue = new QPushButton(dockWidgetContents); - button_continue->setObjectName(QString::fromUtf8("button_continue")); - - horizontalLayout->addWidget(button_continue); - - pushButton = new QPushButton(dockWidgetContents); - pushButton->setObjectName(QString::fromUtf8("pushButton")); - - horizontalLayout->addWidget(pushButton); - - button_breakpoint = new QPushButton(dockWidgetContents); - button_breakpoint->setObjectName(QString::fromUtf8("button_breakpoint")); - - horizontalLayout->addWidget(button_breakpoint); - - - verticalLayout->addLayout(horizontalLayout); - - treeView = new QTreeView(dockWidgetContents); - treeView->setObjectName(QString::fromUtf8("treeView")); - treeView->setAlternatingRowColors(true); - treeView->setIndentation(20); - treeView->setRootIsDecorated(false); - treeView->header()->setVisible(false); - - verticalLayout->addWidget(treeView); - - DockWidget->setWidget(dockWidgetContents); - - retranslateUi(DockWidget); - - QMetaObject::connectSlotsByName(DockWidget); - } // setupUi - - void retranslateUi(QDockWidget *DockWidget) - { - DockWidget->setWindowTitle(QApplication::translate("DockWidget", "Disassembly", 0, QApplication::UnicodeUTF8)); - button_step->setText(QApplication::translate("DockWidget", "Step", 0, QApplication::UnicodeUTF8)); - button_pause->setText(QApplication::translate("DockWidget", "Pause", 0, QApplication::UnicodeUTF8)); - button_continue->setText(QApplication::translate("DockWidget", "Continue", 0, QApplication::UnicodeUTF8)); - pushButton->setText(QApplication::translate("DockWidget", "Step Into", 0, QApplication::UnicodeUTF8)); - button_breakpoint->setText(QApplication::translate("DockWidget", "Set Breakpoint", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class DockWidget: public Ui_DockWidget {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_DISASM_H diff --git a/src/citra_qt/src/ui_gfx_fifo_player.h b/src/citra_qt/src/ui_gfx_fifo_player.h deleted file mode 100644 index a65f56ab..00000000 --- a/src/citra_qt/src/ui_gfx_fifo_player.h +++ /dev/null @@ -1,209 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'gfx_fifo_player.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_GFX_FIFO_PLAYER_H -#define UI_GFX_FIFO_PLAYER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_GfxFifoPlayerControl -{ -public: - QWidget *recordingGroup; - QVBoxLayout *verticalLayout; - QGroupBox *groupBox; - QVBoxLayout *verticalLayout_2; - QRadioButton *stopManuallyButton; - QHBoxLayout *horizontalLayout; - QRadioButton *radioButton_2; - QSpinBox *spinBox; - QComboBox *comboBox; - QSpacerItem *horizontalSpacer_2; - QSpacerItem *horizontalSpacer; - QCheckBox *pauseWhenDoneCheckbox; - QHBoxLayout *horizontalLayout_2; - QPushButton *startStopRecordingButton; - QPushButton *saveRecordingButton; - QGroupBox *playbackGroup; - QVBoxLayout *verticalLayout_3; - QHBoxLayout *horizontalLayout_3; - QLabel *label; - QComboBox *playbackSourceCombobox; - QCheckBox *checkBox_2; - QPushButton *startPlaybackButton; - QSpacerItem *verticalSpacer; - - void setupUi(QDockWidget *GfxFifoPlayerControl) - { - if (GfxFifoPlayerControl->objectName().isEmpty()) - GfxFifoPlayerControl->setObjectName(QString::fromUtf8("GfxFifoPlayerControl")); - GfxFifoPlayerControl->resize(275, 297); - recordingGroup = new QWidget(); - recordingGroup->setObjectName(QString::fromUtf8("recordingGroup")); - verticalLayout = new QVBoxLayout(recordingGroup); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - groupBox = new QGroupBox(recordingGroup); - groupBox->setObjectName(QString::fromUtf8("groupBox")); - verticalLayout_2 = new QVBoxLayout(groupBox); - verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); - stopManuallyButton = new QRadioButton(groupBox); - stopManuallyButton->setObjectName(QString::fromUtf8("stopManuallyButton")); - stopManuallyButton->setChecked(true); - - verticalLayout_2->addWidget(stopManuallyButton); - - horizontalLayout = new QHBoxLayout(); - horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); - radioButton_2 = new QRadioButton(groupBox); - radioButton_2->setObjectName(QString::fromUtf8("radioButton_2")); - - horizontalLayout->addWidget(radioButton_2); - - spinBox = new QSpinBox(groupBox); - spinBox->setObjectName(QString::fromUtf8("spinBox")); - spinBox->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - spinBox->setMinimum(1); - spinBox->setMaximum(99999); - - horizontalLayout->addWidget(spinBox); - - comboBox = new QComboBox(groupBox); - comboBox->setObjectName(QString::fromUtf8("comboBox")); - - horizontalLayout->addWidget(comboBox); - - horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - horizontalLayout->addItem(horizontalSpacer_2); - - horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - horizontalLayout->addItem(horizontalSpacer); - - - verticalLayout_2->addLayout(horizontalLayout); - - pauseWhenDoneCheckbox = new QCheckBox(groupBox); - pauseWhenDoneCheckbox->setObjectName(QString::fromUtf8("pauseWhenDoneCheckbox")); - - verticalLayout_2->addWidget(pauseWhenDoneCheckbox); - - horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); - startStopRecordingButton = new QPushButton(groupBox); - startStopRecordingButton->setObjectName(QString::fromUtf8("startStopRecordingButton")); - - horizontalLayout_2->addWidget(startStopRecordingButton); - - saveRecordingButton = new QPushButton(groupBox); - saveRecordingButton->setObjectName(QString::fromUtf8("saveRecordingButton")); - saveRecordingButton->setEnabled(false); - - horizontalLayout_2->addWidget(saveRecordingButton); - - - verticalLayout_2->addLayout(horizontalLayout_2); - - - verticalLayout->addWidget(groupBox); - - playbackGroup = new QGroupBox(recordingGroup); - playbackGroup->setObjectName(QString::fromUtf8("playbackGroup")); - verticalLayout_3 = new QVBoxLayout(playbackGroup); - verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3")); - horizontalLayout_3 = new QHBoxLayout(); - horizontalLayout_3->setObjectName(QString::fromUtf8("horizontalLayout_3")); - label = new QLabel(playbackGroup); - label->setObjectName(QString::fromUtf8("label")); - - horizontalLayout_3->addWidget(label); - - playbackSourceCombobox = new QComboBox(playbackGroup); - playbackSourceCombobox->setObjectName(QString::fromUtf8("playbackSourceCombobox")); - - horizontalLayout_3->addWidget(playbackSourceCombobox); - - - verticalLayout_3->addLayout(horizontalLayout_3); - - checkBox_2 = new QCheckBox(playbackGroup); - checkBox_2->setObjectName(QString::fromUtf8("checkBox_2")); - - verticalLayout_3->addWidget(checkBox_2); - - startPlaybackButton = new QPushButton(playbackGroup); - startPlaybackButton->setObjectName(QString::fromUtf8("startPlaybackButton")); - - verticalLayout_3->addWidget(startPlaybackButton); - - verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - verticalLayout_3->addItem(verticalSpacer); - - - verticalLayout->addWidget(playbackGroup); - - GfxFifoPlayerControl->setWidget(recordingGroup); - - retranslateUi(GfxFifoPlayerControl); - - QMetaObject::connectSlotsByName(GfxFifoPlayerControl); - } // setupUi - - void retranslateUi(QDockWidget *GfxFifoPlayerControl) - { - GfxFifoPlayerControl->setWindowTitle(QApplication::translate("GfxFifoPlayerControl", "Fifo Player", 0, QApplication::UnicodeUTF8)); - groupBox->setTitle(QApplication::translate("GfxFifoPlayerControl", "Recording", 0, QApplication::UnicodeUTF8)); - stopManuallyButton->setText(QApplication::translate("GfxFifoPlayerControl", "Stop manually", 0, QApplication::UnicodeUTF8)); - radioButton_2->setText(QApplication::translate("GfxFifoPlayerControl", "Stop after", 0, QApplication::UnicodeUTF8)); - comboBox->clear(); - comboBox->insertItems(0, QStringList() - << QApplication::translate("GfxFifoPlayerControl", "Frames", 0, QApplication::UnicodeUTF8) - << QApplication::translate("GfxFifoPlayerControl", "Flushes", 0, QApplication::UnicodeUTF8) - ); - pauseWhenDoneCheckbox->setText(QApplication::translate("GfxFifoPlayerControl", "Pause when done", 0, QApplication::UnicodeUTF8)); - startStopRecordingButton->setText(QApplication::translate("GfxFifoPlayerControl", "Start", 0, QApplication::UnicodeUTF8)); - saveRecordingButton->setText(QApplication::translate("GfxFifoPlayerControl", "Save to File...", 0, QApplication::UnicodeUTF8)); - playbackGroup->setTitle(QApplication::translate("GfxFifoPlayerControl", "Playback", 0, QApplication::UnicodeUTF8)); - label->setText(QApplication::translate("GfxFifoPlayerControl", "Playback source:", 0, QApplication::UnicodeUTF8)); - playbackSourceCombobox->clear(); - playbackSourceCombobox->insertItems(0, QStringList() - << QApplication::translate("GfxFifoPlayerControl", "Last Recording", 0, QApplication::UnicodeUTF8) - << QApplication::translate("GfxFifoPlayerControl", "From File...", 0, QApplication::UnicodeUTF8) - ); - checkBox_2->setText(QApplication::translate("GfxFifoPlayerControl", "Loop", 0, QApplication::UnicodeUTF8)); - startPlaybackButton->setText(QApplication::translate("GfxFifoPlayerControl", "Start", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class GfxFifoPlayerControl: public Ui_GfxFifoPlayerControl {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_GFX_FIFO_PLAYER_H diff --git a/src/citra_qt/src/ui_hotkeys.h b/src/citra_qt/src/ui_hotkeys.h deleted file mode 100644 index 5b2cee6f..00000000 --- a/src/citra_qt/src/ui_hotkeys.h +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'hotkeys.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_HOTKEYS_H -#define UI_HOTKEYS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_hotkeys -{ -public: - QVBoxLayout *verticalLayout; - QTreeWidget *treeWidget; - QDialogButtonBox *buttonBox; - - void setupUi(QDialog *hotkeys) - { - if (hotkeys->objectName().isEmpty()) - hotkeys->setObjectName(QString::fromUtf8("hotkeys")); - hotkeys->resize(363, 388); - verticalLayout = new QVBoxLayout(hotkeys); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - treeWidget = new QTreeWidget(hotkeys); - treeWidget->setObjectName(QString::fromUtf8("treeWidget")); - treeWidget->setSelectionBehavior(QAbstractItemView::SelectItems); - treeWidget->setHeaderHidden(false); - - verticalLayout->addWidget(treeWidget); - - buttonBox = new QDialogButtonBox(hotkeys); - buttonBox->setObjectName(QString::fromUtf8("buttonBox")); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset); - - verticalLayout->addWidget(buttonBox); - - - retranslateUi(hotkeys); - QObject::connect(buttonBox, SIGNAL(accepted()), hotkeys, SLOT(accept())); - QObject::connect(buttonBox, SIGNAL(rejected()), hotkeys, SLOT(reject())); - - QMetaObject::connectSlotsByName(hotkeys); - } // setupUi - - void retranslateUi(QDialog *hotkeys) - { - hotkeys->setWindowTitle(QApplication::translate("hotkeys", "Hotkey Settings", 0, QApplication::UnicodeUTF8)); - QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); - ___qtreewidgetitem->setText(2, QApplication::translate("hotkeys", "Context", 0, QApplication::UnicodeUTF8)); - ___qtreewidgetitem->setText(1, QApplication::translate("hotkeys", "Hotkey", 0, QApplication::UnicodeUTF8)); - ___qtreewidgetitem->setText(0, QApplication::translate("hotkeys", "Action", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class hotkeys: public Ui_hotkeys {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_HOTKEYS_H diff --git a/src/citra_qt/src/ui_image_info.h b/src/citra_qt/src/ui_image_info.h deleted file mode 100644 index a6aaa3d8..00000000 --- a/src/citra_qt/src/ui_image_info.h +++ /dev/null @@ -1,154 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'image_info.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_IMAGE_INFO_H -#define UI_IMAGE_INFO_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_ImageInfo -{ -public: - QWidget *dockWidgetContents; - QFormLayout *formLayout; - QLabel *label_name; - QLabel *label_gameid; - QLabel *label_country; - QLabel *label_bannertext; - QLineEdit *line_name; - QLineEdit *line_gameid; - QLineEdit *line_country; - QLabel *label_banner; - QLabel *label_developer; - QLineEdit *line_developer; - QLabel *label_description; - QPlainTextEdit *edit_description; - - void setupUi(QDockWidget *ImageInfo) - { - if (ImageInfo->objectName().isEmpty()) - ImageInfo->setObjectName(QString::fromUtf8("ImageInfo")); - ImageInfo->resize(400, 300); - dockWidgetContents = new QWidget(); - dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); - formLayout = new QFormLayout(dockWidgetContents); - formLayout->setObjectName(QString::fromUtf8("formLayout")); - label_name = new QLabel(dockWidgetContents); - label_name->setObjectName(QString::fromUtf8("label_name")); - - formLayout->setWidget(1, QFormLayout::LabelRole, label_name); - - label_gameid = new QLabel(dockWidgetContents); - label_gameid->setObjectName(QString::fromUtf8("label_gameid")); - - formLayout->setWidget(4, QFormLayout::LabelRole, label_gameid); - - label_country = new QLabel(dockWidgetContents); - label_country->setObjectName(QString::fromUtf8("label_country")); - - formLayout->setWidget(5, QFormLayout::LabelRole, label_country); - - label_bannertext = new QLabel(dockWidgetContents); - label_bannertext->setObjectName(QString::fromUtf8("label_bannertext")); - - formLayout->setWidget(9, QFormLayout::LabelRole, label_bannertext); - - line_name = new QLineEdit(dockWidgetContents); - line_name->setObjectName(QString::fromUtf8("line_name")); - line_name->setEnabled(true); - line_name->setReadOnly(true); - - formLayout->setWidget(1, QFormLayout::FieldRole, line_name); - - line_gameid = new QLineEdit(dockWidgetContents); - line_gameid->setObjectName(QString::fromUtf8("line_gameid")); - line_gameid->setEnabled(true); - line_gameid->setReadOnly(true); - - formLayout->setWidget(4, QFormLayout::FieldRole, line_gameid); - - line_country = new QLineEdit(dockWidgetContents); - line_country->setObjectName(QString::fromUtf8("line_country")); - line_country->setEnabled(true); - line_country->setReadOnly(true); - - formLayout->setWidget(5, QFormLayout::FieldRole, line_country); - - label_banner = new QLabel(dockWidgetContents); - label_banner->setObjectName(QString::fromUtf8("label_banner")); - label_banner->setAlignment(Qt::AlignCenter); - - formLayout->setWidget(9, QFormLayout::FieldRole, label_banner); - - label_developer = new QLabel(dockWidgetContents); - label_developer->setObjectName(QString::fromUtf8("label_developer")); - - formLayout->setWidget(3, QFormLayout::LabelRole, label_developer); - - line_developer = new QLineEdit(dockWidgetContents); - line_developer->setObjectName(QString::fromUtf8("line_developer")); - line_developer->setReadOnly(true); - - formLayout->setWidget(3, QFormLayout::FieldRole, line_developer); - - label_description = new QLabel(dockWidgetContents); - label_description->setObjectName(QString::fromUtf8("label_description")); - - formLayout->setWidget(7, QFormLayout::LabelRole, label_description); - - edit_description = new QPlainTextEdit(dockWidgetContents); - edit_description->setObjectName(QString::fromUtf8("edit_description")); - edit_description->setMaximumSize(QSize(16777215, 80)); - edit_description->setReadOnly(true); - edit_description->setPlainText(QString::fromUtf8("")); - - formLayout->setWidget(7, QFormLayout::FieldRole, edit_description); - - ImageInfo->setWidget(dockWidgetContents); - - retranslateUi(ImageInfo); - - QMetaObject::connectSlotsByName(ImageInfo); - } // setupUi - - void retranslateUi(QDockWidget *ImageInfo) - { - ImageInfo->setWindowTitle(QApplication::translate("ImageInfo", "Image Info", 0, QApplication::UnicodeUTF8)); - label_name->setText(QApplication::translate("ImageInfo", "Name", 0, QApplication::UnicodeUTF8)); - label_gameid->setText(QApplication::translate("ImageInfo", "Game ID", 0, QApplication::UnicodeUTF8)); - label_country->setText(QApplication::translate("ImageInfo", "Country", 0, QApplication::UnicodeUTF8)); - label_bannertext->setText(QApplication::translate("ImageInfo", "Banner", 0, QApplication::UnicodeUTF8)); - line_name->setText(QString()); - line_gameid->setText(QString()); - line_country->setText(QApplication::translate("ImageInfo", "EUROPE", 0, QApplication::UnicodeUTF8)); - label_banner->setText(QString()); - label_developer->setText(QApplication::translate("ImageInfo", "Developer", 0, QApplication::UnicodeUTF8)); - label_description->setText(QApplication::translate("ImageInfo", "Description", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class ImageInfo: public Ui_ImageInfo {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_IMAGE_INFO_H diff --git a/src/citra_qt/src/ui_main.h b/src/citra_qt/src/ui_main.h deleted file mode 100644 index d349a5c6..00000000 --- a/src/citra_qt/src/ui_main.h +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'main.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_MAIN_H -#define UI_MAIN_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_MainWindow -{ -public: - QAction *action_load_elf; - QAction *action_Exit; - QAction *action_Start; - QAction *action_Pause; - QAction *action_Stop; - QAction *action_About; - QAction *action_Single_Window_Mode; - QAction *action_Hotkeys; - QAction *action_Configure; - QWidget *centralwidget; - QHBoxLayout *horizontalLayout; - QMenuBar *menubar; - QMenu *menu_File; - QMenu *menu_Emulation; - QMenu *menu_View; - QMenu *menu_Help; - QStatusBar *statusbar; - - void setupUi(QMainWindow *MainWindow) - { - if (MainWindow->objectName().isEmpty()) - MainWindow->setObjectName(QString::fromUtf8("MainWindow")); - MainWindow->resize(1081, 730); - QIcon icon; - icon.addFile(QString::fromUtf8("src/pcafe/res/icon3_64x64.ico"), QSize(), QIcon::Normal, QIcon::Off); - MainWindow->setWindowIcon(icon); - MainWindow->setTabShape(QTabWidget::Rounded); - MainWindow->setDockNestingEnabled(true); - action_load_elf = new QAction(MainWindow); - action_load_elf->setObjectName(QString::fromUtf8("action_load_elf")); - action_Exit = new QAction(MainWindow); - action_Exit->setObjectName(QString::fromUtf8("action_Exit")); - action_Start = new QAction(MainWindow); - action_Start->setObjectName(QString::fromUtf8("action_Start")); - action_Pause = new QAction(MainWindow); - action_Pause->setObjectName(QString::fromUtf8("action_Pause")); - action_Pause->setEnabled(false); - action_Stop = new QAction(MainWindow); - action_Stop->setObjectName(QString::fromUtf8("action_Stop")); - action_Stop->setEnabled(false); - action_About = new QAction(MainWindow); - action_About->setObjectName(QString::fromUtf8("action_About")); - action_Single_Window_Mode = new QAction(MainWindow); - action_Single_Window_Mode->setObjectName(QString::fromUtf8("action_Single_Window_Mode")); - action_Single_Window_Mode->setCheckable(true); - action_Hotkeys = new QAction(MainWindow); - action_Hotkeys->setObjectName(QString::fromUtf8("action_Hotkeys")); - action_Configure = new QAction(MainWindow); - action_Configure->setObjectName(QString::fromUtf8("action_Configure")); - centralwidget = new QWidget(MainWindow); - centralwidget->setObjectName(QString::fromUtf8("centralwidget")); - horizontalLayout = new QHBoxLayout(centralwidget); - horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); - MainWindow->setCentralWidget(centralwidget); - menubar = new QMenuBar(MainWindow); - menubar->setObjectName(QString::fromUtf8("menubar")); - menubar->setGeometry(QRect(0, 0, 1081, 20)); - menu_File = new QMenu(menubar); - menu_File->setObjectName(QString::fromUtf8("menu_File")); - menu_Emulation = new QMenu(menubar); - menu_Emulation->setObjectName(QString::fromUtf8("menu_Emulation")); - menu_View = new QMenu(menubar); - menu_View->setObjectName(QString::fromUtf8("menu_View")); - menu_Help = new QMenu(menubar); - menu_Help->setObjectName(QString::fromUtf8("menu_Help")); - MainWindow->setMenuBar(menubar); - statusbar = new QStatusBar(MainWindow); - statusbar->setObjectName(QString::fromUtf8("statusbar")); - MainWindow->setStatusBar(statusbar); - - menubar->addAction(menu_File->menuAction()); - menubar->addAction(menu_Emulation->menuAction()); - menubar->addAction(menu_View->menuAction()); - menubar->addAction(menu_Help->menuAction()); - menu_File->addAction(action_load_elf); - menu_File->addSeparator(); - menu_File->addAction(action_Exit); - menu_Emulation->addAction(action_Start); - menu_Emulation->addAction(action_Pause); - menu_Emulation->addAction(action_Stop); - menu_Emulation->addSeparator(); - menu_Emulation->addAction(action_Configure); - menu_View->addAction(action_Single_Window_Mode); - menu_View->addAction(action_Hotkeys); - menu_Help->addAction(action_About); - - retranslateUi(MainWindow); - QObject::connect(action_Exit, SIGNAL(triggered()), MainWindow, SLOT(close())); - QObject::connect(action_Configure, SIGNAL(triggered()), MainWindow, SLOT(OnConfigure())); - - QMetaObject::connectSlotsByName(MainWindow); - } // setupUi - - void retranslateUi(QMainWindow *MainWindow) - { - MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Citra", 0, QApplication::UnicodeUTF8)); - action_load_elf->setText(QApplication::translate("MainWindow", "Load ELF ...", 0, QApplication::UnicodeUTF8)); - action_Exit->setText(QApplication::translate("MainWindow", "E&xit", 0, QApplication::UnicodeUTF8)); - action_Start->setText(QApplication::translate("MainWindow", "&Start", 0, QApplication::UnicodeUTF8)); - action_Pause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8)); - action_Stop->setText(QApplication::translate("MainWindow", "&Stop", 0, QApplication::UnicodeUTF8)); - action_About->setText(QApplication::translate("MainWindow", "About Citra", 0, QApplication::UnicodeUTF8)); - action_Single_Window_Mode->setText(QApplication::translate("MainWindow", "Single Window Mode", 0, QApplication::UnicodeUTF8)); - action_Hotkeys->setText(QApplication::translate("MainWindow", "Configure &Hotkeys ...", 0, QApplication::UnicodeUTF8)); - action_Configure->setText(QApplication::translate("MainWindow", "Configure ...", 0, QApplication::UnicodeUTF8)); - menu_File->setTitle(QApplication::translate("MainWindow", "&File", 0, QApplication::UnicodeUTF8)); - menu_Emulation->setTitle(QApplication::translate("MainWindow", "&Emulation", 0, QApplication::UnicodeUTF8)); - menu_View->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8)); - menu_Help->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8)); - } // retranslateUi - -}; - -namespace Ui { - class MainWindow: public Ui_MainWindow {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_MAIN_H diff --git a/src/citra_qt/src/ui_welcome_wizard.h b/src/citra_qt/src/ui_welcome_wizard.h deleted file mode 100644 index 0cc5ceb4..00000000 --- a/src/citra_qt/src/ui_welcome_wizard.h +++ /dev/null @@ -1,124 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'welcome_wizard.ui' -** -** Created by: Qt User Interface Compiler version 4.8.5 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_WELCOME_WIZARD_H -#define UI_WELCOME_WIZARD_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "path_list.hxx" - -QT_BEGIN_NAMESPACE - -class Ui_WelcomeWizard -{ -public: - QWizardPage *wizardPage1; - QWizardPage *wizardPage2; - QVBoxLayout *verticalLayout_2; - QHBoxLayout *horizontalLayout; - QLineEdit *edit_path; - QPushButton *button_browse_path; - QHBoxLayout *horizontalLayout_2; - GPathList *path_list; - QVBoxLayout *verticalLayout_3; - QPushButton *button_add_path; - QSpacerItem *verticalSpacer; - - void setupUi(QWizard *WelcomeWizard) - { - if (WelcomeWizard->objectName().isEmpty()) - WelcomeWizard->setObjectName(QString::fromUtf8("WelcomeWizard")); - WelcomeWizard->resize(510, 300); - WelcomeWizard->setModal(true); - wizardPage1 = new QWizardPage(); - wizardPage1->setObjectName(QString::fromUtf8("wizardPage1")); - WelcomeWizard->addPage(wizardPage1); - wizardPage2 = new QWizardPage(); - wizardPage2->setObjectName(QString::fromUtf8("wizardPage2")); - verticalLayout_2 = new QVBoxLayout(wizardPage2); - verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); - horizontalLayout = new QHBoxLayout(); - horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); - edit_path = new QLineEdit(wizardPage2); - edit_path->setObjectName(QString::fromUtf8("edit_path")); - edit_path->setReadOnly(true); - - horizontalLayout->addWidget(edit_path); - - button_browse_path = new QPushButton(wizardPage2); - button_browse_path->setObjectName(QString::fromUtf8("button_browse_path")); - - horizontalLayout->addWidget(button_browse_path); - - - verticalLayout_2->addLayout(horizontalLayout); - - horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); - path_list = new GPathList(wizardPage2); - path_list->setObjectName(QString::fromUtf8("path_list")); - - horizontalLayout_2->addWidget(path_list); - - verticalLayout_3 = new QVBoxLayout(); - verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3")); - button_add_path = new QPushButton(wizardPage2); - button_add_path->setObjectName(QString::fromUtf8("button_add_path")); - - verticalLayout_3->addWidget(button_add_path); - - verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - verticalLayout_3->addItem(verticalSpacer); - - - horizontalLayout_2->addLayout(verticalLayout_3); - - - verticalLayout_2->addLayout(horizontalLayout_2); - - WelcomeWizard->addPage(wizardPage2); - - retranslateUi(WelcomeWizard); - - QMetaObject::connectSlotsByName(WelcomeWizard); - } // setupUi - - void retranslateUi(QWizard *WelcomeWizard) - { - WelcomeWizard->setWindowTitle(QApplication::translate("WelcomeWizard", "Welcome", 0, QApplication::UnicodeUTF8)); - wizardPage1->setTitle(QApplication::translate("WelcomeWizard", "Welcome", 0, QApplication::UnicodeUTF8)); - wizardPage1->setSubTitle(QApplication::translate("WelcomeWizard", "This wizard will guide you through the initial configuration.", 0, QApplication::UnicodeUTF8)); - wizardPage2->setTitle(QApplication::translate("WelcomeWizard", "ISO paths", 0, QApplication::UnicodeUTF8)); - wizardPage2->setSubTitle(QApplication::translate("WelcomeWizard", "If you have a collection of game images, you can add them to the path list here. Gekko will automatically show a list of your collection on startup then.", 0, QApplication::UnicodeUTF8)); - edit_path->setText(QString()); - edit_path->setPlaceholderText(QApplication::translate("WelcomeWizard", "Select a path to add ...", 0, QApplication::UnicodeUTF8)); - button_browse_path->setText(QString()); - button_add_path->setText(QString()); - } // retranslateUi - -}; - -namespace Ui { - class WelcomeWizard: public Ui_WelcomeWizard {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_WELCOME_WIZARD_H diff --git a/src/citra_qt/src/version.h b/src/citra_qt/src/version.h deleted file mode 100644 index 07022de5..00000000 --- a/src/citra_qt/src/version.h +++ /dev/null @@ -1,7 +0,0 @@ -// TODO: Supposed to be generated... -// GENERATED - Do not edit! -#ifndef VERSION_H_ -#define VERSION_H_ -#define __BUILD__ "40" -#define VERSION __BUILD__ -#endif // VERSION_H_ diff --git a/src/citra_qt/ui_callstack.h b/src/citra_qt/ui_callstack.h new file mode 100644 index 00000000..75d10253 --- /dev/null +++ b/src/citra_qt/ui_callstack.h @@ -0,0 +1,68 @@ +/******************************************************************************** +** Form generated from reading UI file 'callstack.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_CALLSTACK_H +#define UI_CALLSTACK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_CallStack +{ +public: + QWidget *dockWidgetContents; + QVBoxLayout *verticalLayout; + QTreeView *treeView; + + void setupUi(QDockWidget *CallStack) + { + if (CallStack->objectName().isEmpty()) + CallStack->setObjectName(QString::fromUtf8("CallStack")); + CallStack->resize(400, 300); + dockWidgetContents = new QWidget(); + dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); + verticalLayout = new QVBoxLayout(dockWidgetContents); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + treeView = new QTreeView(dockWidgetContents); + treeView->setObjectName(QString::fromUtf8("treeView")); + treeView->setAlternatingRowColors(true); + treeView->setRootIsDecorated(false); + treeView->setItemsExpandable(false); + + verticalLayout->addWidget(treeView); + + CallStack->setWidget(dockWidgetContents); + + retranslateUi(CallStack); + + QMetaObject::connectSlotsByName(CallStack); + } // setupUi + + void retranslateUi(QDockWidget *CallStack) + { + CallStack->setWindowTitle(QApplication::translate("CallStack", "Call stack", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class CallStack: public Ui_CallStack {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_CALLSTACK_H diff --git a/src/citra_qt/ui_cpu_regs.h b/src/citra_qt/ui_cpu_regs.h new file mode 100644 index 00000000..b8a80b3f --- /dev/null +++ b/src/citra_qt/ui_cpu_regs.h @@ -0,0 +1,69 @@ +/******************************************************************************** +** Form generated from reading UI file 'cpu_regs.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_CPU_REGS_H +#define UI_CPU_REGS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_ARMRegisters +{ +public: + QWidget *dockWidgetContents; + QVBoxLayout *verticalLayout; + QTreeWidget *treeWidget; + + void setupUi(QDockWidget *ARMRegisters) + { + if (ARMRegisters->objectName().isEmpty()) + ARMRegisters->setObjectName(QString::fromUtf8("ARMRegisters")); + ARMRegisters->resize(400, 300); + dockWidgetContents = new QWidget(); + dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); + verticalLayout = new QVBoxLayout(dockWidgetContents); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + treeWidget = new QTreeWidget(dockWidgetContents); + treeWidget->setObjectName(QString::fromUtf8("treeWidget")); + treeWidget->setAlternatingRowColors(true); + + verticalLayout->addWidget(treeWidget); + + ARMRegisters->setWidget(dockWidgetContents); + + retranslateUi(ARMRegisters); + + QMetaObject::connectSlotsByName(ARMRegisters); + } // setupUi + + void retranslateUi(QDockWidget *ARMRegisters) + { + ARMRegisters->setWindowTitle(QApplication::translate("ARMRegisters", "ARM registers", 0, QApplication::UnicodeUTF8)); + QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); + ___qtreewidgetitem->setText(1, QApplication::translate("ARMRegisters", "Value", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(0, QApplication::translate("ARMRegisters", "Register", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class ARMRegisters: public Ui_ARMRegisters {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_CPU_REGS_H diff --git a/src/citra_qt/ui_disasm.h b/src/citra_qt/ui_disasm.h new file mode 100644 index 00000000..697a224c --- /dev/null +++ b/src/citra_qt/ui_disasm.h @@ -0,0 +1,112 @@ +/******************************************************************************** +** Form generated from reading UI file 'disasm.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_DISASM_H +#define UI_DISASM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_DockWidget +{ +public: + QWidget *dockWidgetContents; + QVBoxLayout *verticalLayout; + QHBoxLayout *horizontalLayout; + QPushButton *button_step; + QPushButton *button_pause; + QPushButton *button_continue; + QPushButton *pushButton; + QPushButton *button_breakpoint; + QTreeView *treeView; + + void setupUi(QDockWidget *DockWidget) + { + if (DockWidget->objectName().isEmpty()) + DockWidget->setObjectName(QString::fromUtf8("DockWidget")); + DockWidget->resize(430, 401); + dockWidgetContents = new QWidget(); + dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); + verticalLayout = new QVBoxLayout(dockWidgetContents); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + horizontalLayout = new QHBoxLayout(); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + button_step = new QPushButton(dockWidgetContents); + button_step->setObjectName(QString::fromUtf8("button_step")); + + horizontalLayout->addWidget(button_step); + + button_pause = new QPushButton(dockWidgetContents); + button_pause->setObjectName(QString::fromUtf8("button_pause")); + + horizontalLayout->addWidget(button_pause); + + button_continue = new QPushButton(dockWidgetContents); + button_continue->setObjectName(QString::fromUtf8("button_continue")); + + horizontalLayout->addWidget(button_continue); + + pushButton = new QPushButton(dockWidgetContents); + pushButton->setObjectName(QString::fromUtf8("pushButton")); + + horizontalLayout->addWidget(pushButton); + + button_breakpoint = new QPushButton(dockWidgetContents); + button_breakpoint->setObjectName(QString::fromUtf8("button_breakpoint")); + + horizontalLayout->addWidget(button_breakpoint); + + + verticalLayout->addLayout(horizontalLayout); + + treeView = new QTreeView(dockWidgetContents); + treeView->setObjectName(QString::fromUtf8("treeView")); + treeView->setAlternatingRowColors(true); + treeView->setIndentation(20); + treeView->setRootIsDecorated(false); + treeView->header()->setVisible(false); + + verticalLayout->addWidget(treeView); + + DockWidget->setWidget(dockWidgetContents); + + retranslateUi(DockWidget); + + QMetaObject::connectSlotsByName(DockWidget); + } // setupUi + + void retranslateUi(QDockWidget *DockWidget) + { + DockWidget->setWindowTitle(QApplication::translate("DockWidget", "Disassembly", 0, QApplication::UnicodeUTF8)); + button_step->setText(QApplication::translate("DockWidget", "Step", 0, QApplication::UnicodeUTF8)); + button_pause->setText(QApplication::translate("DockWidget", "Pause", 0, QApplication::UnicodeUTF8)); + button_continue->setText(QApplication::translate("DockWidget", "Continue", 0, QApplication::UnicodeUTF8)); + pushButton->setText(QApplication::translate("DockWidget", "Step Into", 0, QApplication::UnicodeUTF8)); + button_breakpoint->setText(QApplication::translate("DockWidget", "Set Breakpoint", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class DockWidget: public Ui_DockWidget {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_DISASM_H diff --git a/src/citra_qt/ui_gfx_fifo_player.h b/src/citra_qt/ui_gfx_fifo_player.h new file mode 100644 index 00000000..a65f56ab --- /dev/null +++ b/src/citra_qt/ui_gfx_fifo_player.h @@ -0,0 +1,209 @@ +/******************************************************************************** +** Form generated from reading UI file 'gfx_fifo_player.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_GFX_FIFO_PLAYER_H +#define UI_GFX_FIFO_PLAYER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_GfxFifoPlayerControl +{ +public: + QWidget *recordingGroup; + QVBoxLayout *verticalLayout; + QGroupBox *groupBox; + QVBoxLayout *verticalLayout_2; + QRadioButton *stopManuallyButton; + QHBoxLayout *horizontalLayout; + QRadioButton *radioButton_2; + QSpinBox *spinBox; + QComboBox *comboBox; + QSpacerItem *horizontalSpacer_2; + QSpacerItem *horizontalSpacer; + QCheckBox *pauseWhenDoneCheckbox; + QHBoxLayout *horizontalLayout_2; + QPushButton *startStopRecordingButton; + QPushButton *saveRecordingButton; + QGroupBox *playbackGroup; + QVBoxLayout *verticalLayout_3; + QHBoxLayout *horizontalLayout_3; + QLabel *label; + QComboBox *playbackSourceCombobox; + QCheckBox *checkBox_2; + QPushButton *startPlaybackButton; + QSpacerItem *verticalSpacer; + + void setupUi(QDockWidget *GfxFifoPlayerControl) + { + if (GfxFifoPlayerControl->objectName().isEmpty()) + GfxFifoPlayerControl->setObjectName(QString::fromUtf8("GfxFifoPlayerControl")); + GfxFifoPlayerControl->resize(275, 297); + recordingGroup = new QWidget(); + recordingGroup->setObjectName(QString::fromUtf8("recordingGroup")); + verticalLayout = new QVBoxLayout(recordingGroup); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + groupBox = new QGroupBox(recordingGroup); + groupBox->setObjectName(QString::fromUtf8("groupBox")); + verticalLayout_2 = new QVBoxLayout(groupBox); + verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); + stopManuallyButton = new QRadioButton(groupBox); + stopManuallyButton->setObjectName(QString::fromUtf8("stopManuallyButton")); + stopManuallyButton->setChecked(true); + + verticalLayout_2->addWidget(stopManuallyButton); + + horizontalLayout = new QHBoxLayout(); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + radioButton_2 = new QRadioButton(groupBox); + radioButton_2->setObjectName(QString::fromUtf8("radioButton_2")); + + horizontalLayout->addWidget(radioButton_2); + + spinBox = new QSpinBox(groupBox); + spinBox->setObjectName(QString::fromUtf8("spinBox")); + spinBox->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + spinBox->setMinimum(1); + spinBox->setMaximum(99999); + + horizontalLayout->addWidget(spinBox); + + comboBox = new QComboBox(groupBox); + comboBox->setObjectName(QString::fromUtf8("comboBox")); + + horizontalLayout->addWidget(comboBox); + + horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout->addItem(horizontalSpacer_2); + + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout->addItem(horizontalSpacer); + + + verticalLayout_2->addLayout(horizontalLayout); + + pauseWhenDoneCheckbox = new QCheckBox(groupBox); + pauseWhenDoneCheckbox->setObjectName(QString::fromUtf8("pauseWhenDoneCheckbox")); + + verticalLayout_2->addWidget(pauseWhenDoneCheckbox); + + horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); + startStopRecordingButton = new QPushButton(groupBox); + startStopRecordingButton->setObjectName(QString::fromUtf8("startStopRecordingButton")); + + horizontalLayout_2->addWidget(startStopRecordingButton); + + saveRecordingButton = new QPushButton(groupBox); + saveRecordingButton->setObjectName(QString::fromUtf8("saveRecordingButton")); + saveRecordingButton->setEnabled(false); + + horizontalLayout_2->addWidget(saveRecordingButton); + + + verticalLayout_2->addLayout(horizontalLayout_2); + + + verticalLayout->addWidget(groupBox); + + playbackGroup = new QGroupBox(recordingGroup); + playbackGroup->setObjectName(QString::fromUtf8("playbackGroup")); + verticalLayout_3 = new QVBoxLayout(playbackGroup); + verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3")); + horizontalLayout_3 = new QHBoxLayout(); + horizontalLayout_3->setObjectName(QString::fromUtf8("horizontalLayout_3")); + label = new QLabel(playbackGroup); + label->setObjectName(QString::fromUtf8("label")); + + horizontalLayout_3->addWidget(label); + + playbackSourceCombobox = new QComboBox(playbackGroup); + playbackSourceCombobox->setObjectName(QString::fromUtf8("playbackSourceCombobox")); + + horizontalLayout_3->addWidget(playbackSourceCombobox); + + + verticalLayout_3->addLayout(horizontalLayout_3); + + checkBox_2 = new QCheckBox(playbackGroup); + checkBox_2->setObjectName(QString::fromUtf8("checkBox_2")); + + verticalLayout_3->addWidget(checkBox_2); + + startPlaybackButton = new QPushButton(playbackGroup); + startPlaybackButton->setObjectName(QString::fromUtf8("startPlaybackButton")); + + verticalLayout_3->addWidget(startPlaybackButton); + + verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + verticalLayout_3->addItem(verticalSpacer); + + + verticalLayout->addWidget(playbackGroup); + + GfxFifoPlayerControl->setWidget(recordingGroup); + + retranslateUi(GfxFifoPlayerControl); + + QMetaObject::connectSlotsByName(GfxFifoPlayerControl); + } // setupUi + + void retranslateUi(QDockWidget *GfxFifoPlayerControl) + { + GfxFifoPlayerControl->setWindowTitle(QApplication::translate("GfxFifoPlayerControl", "Fifo Player", 0, QApplication::UnicodeUTF8)); + groupBox->setTitle(QApplication::translate("GfxFifoPlayerControl", "Recording", 0, QApplication::UnicodeUTF8)); + stopManuallyButton->setText(QApplication::translate("GfxFifoPlayerControl", "Stop manually", 0, QApplication::UnicodeUTF8)); + radioButton_2->setText(QApplication::translate("GfxFifoPlayerControl", "Stop after", 0, QApplication::UnicodeUTF8)); + comboBox->clear(); + comboBox->insertItems(0, QStringList() + << QApplication::translate("GfxFifoPlayerControl", "Frames", 0, QApplication::UnicodeUTF8) + << QApplication::translate("GfxFifoPlayerControl", "Flushes", 0, QApplication::UnicodeUTF8) + ); + pauseWhenDoneCheckbox->setText(QApplication::translate("GfxFifoPlayerControl", "Pause when done", 0, QApplication::UnicodeUTF8)); + startStopRecordingButton->setText(QApplication::translate("GfxFifoPlayerControl", "Start", 0, QApplication::UnicodeUTF8)); + saveRecordingButton->setText(QApplication::translate("GfxFifoPlayerControl", "Save to File...", 0, QApplication::UnicodeUTF8)); + playbackGroup->setTitle(QApplication::translate("GfxFifoPlayerControl", "Playback", 0, QApplication::UnicodeUTF8)); + label->setText(QApplication::translate("GfxFifoPlayerControl", "Playback source:", 0, QApplication::UnicodeUTF8)); + playbackSourceCombobox->clear(); + playbackSourceCombobox->insertItems(0, QStringList() + << QApplication::translate("GfxFifoPlayerControl", "Last Recording", 0, QApplication::UnicodeUTF8) + << QApplication::translate("GfxFifoPlayerControl", "From File...", 0, QApplication::UnicodeUTF8) + ); + checkBox_2->setText(QApplication::translate("GfxFifoPlayerControl", "Loop", 0, QApplication::UnicodeUTF8)); + startPlaybackButton->setText(QApplication::translate("GfxFifoPlayerControl", "Start", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class GfxFifoPlayerControl: public Ui_GfxFifoPlayerControl {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_GFX_FIFO_PLAYER_H diff --git a/src/citra_qt/ui_hotkeys.h b/src/citra_qt/ui_hotkeys.h new file mode 100644 index 00000000..5b2cee6f --- /dev/null +++ b/src/citra_qt/ui_hotkeys.h @@ -0,0 +1,77 @@ +/******************************************************************************** +** Form generated from reading UI file 'hotkeys.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_HOTKEYS_H +#define UI_HOTKEYS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_hotkeys +{ +public: + QVBoxLayout *verticalLayout; + QTreeWidget *treeWidget; + QDialogButtonBox *buttonBox; + + void setupUi(QDialog *hotkeys) + { + if (hotkeys->objectName().isEmpty()) + hotkeys->setObjectName(QString::fromUtf8("hotkeys")); + hotkeys->resize(363, 388); + verticalLayout = new QVBoxLayout(hotkeys); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + treeWidget = new QTreeWidget(hotkeys); + treeWidget->setObjectName(QString::fromUtf8("treeWidget")); + treeWidget->setSelectionBehavior(QAbstractItemView::SelectItems); + treeWidget->setHeaderHidden(false); + + verticalLayout->addWidget(treeWidget); + + buttonBox = new QDialogButtonBox(hotkeys); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset); + + verticalLayout->addWidget(buttonBox); + + + retranslateUi(hotkeys); + QObject::connect(buttonBox, SIGNAL(accepted()), hotkeys, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), hotkeys, SLOT(reject())); + + QMetaObject::connectSlotsByName(hotkeys); + } // setupUi + + void retranslateUi(QDialog *hotkeys) + { + hotkeys->setWindowTitle(QApplication::translate("hotkeys", "Hotkey Settings", 0, QApplication::UnicodeUTF8)); + QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); + ___qtreewidgetitem->setText(2, QApplication::translate("hotkeys", "Context", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(1, QApplication::translate("hotkeys", "Hotkey", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(0, QApplication::translate("hotkeys", "Action", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class hotkeys: public Ui_hotkeys {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_HOTKEYS_H diff --git a/src/citra_qt/ui_image_info.h b/src/citra_qt/ui_image_info.h new file mode 100644 index 00000000..a6aaa3d8 --- /dev/null +++ b/src/citra_qt/ui_image_info.h @@ -0,0 +1,154 @@ +/******************************************************************************** +** Form generated from reading UI file 'image_info.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_IMAGE_INFO_H +#define UI_IMAGE_INFO_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_ImageInfo +{ +public: + QWidget *dockWidgetContents; + QFormLayout *formLayout; + QLabel *label_name; + QLabel *label_gameid; + QLabel *label_country; + QLabel *label_bannertext; + QLineEdit *line_name; + QLineEdit *line_gameid; + QLineEdit *line_country; + QLabel *label_banner; + QLabel *label_developer; + QLineEdit *line_developer; + QLabel *label_description; + QPlainTextEdit *edit_description; + + void setupUi(QDockWidget *ImageInfo) + { + if (ImageInfo->objectName().isEmpty()) + ImageInfo->setObjectName(QString::fromUtf8("ImageInfo")); + ImageInfo->resize(400, 300); + dockWidgetContents = new QWidget(); + dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); + formLayout = new QFormLayout(dockWidgetContents); + formLayout->setObjectName(QString::fromUtf8("formLayout")); + label_name = new QLabel(dockWidgetContents); + label_name->setObjectName(QString::fromUtf8("label_name")); + + formLayout->setWidget(1, QFormLayout::LabelRole, label_name); + + label_gameid = new QLabel(dockWidgetContents); + label_gameid->setObjectName(QString::fromUtf8("label_gameid")); + + formLayout->setWidget(4, QFormLayout::LabelRole, label_gameid); + + label_country = new QLabel(dockWidgetContents); + label_country->setObjectName(QString::fromUtf8("label_country")); + + formLayout->setWidget(5, QFormLayout::LabelRole, label_country); + + label_bannertext = new QLabel(dockWidgetContents); + label_bannertext->setObjectName(QString::fromUtf8("label_bannertext")); + + formLayout->setWidget(9, QFormLayout::LabelRole, label_bannertext); + + line_name = new QLineEdit(dockWidgetContents); + line_name->setObjectName(QString::fromUtf8("line_name")); + line_name->setEnabled(true); + line_name->setReadOnly(true); + + formLayout->setWidget(1, QFormLayout::FieldRole, line_name); + + line_gameid = new QLineEdit(dockWidgetContents); + line_gameid->setObjectName(QString::fromUtf8("line_gameid")); + line_gameid->setEnabled(true); + line_gameid->setReadOnly(true); + + formLayout->setWidget(4, QFormLayout::FieldRole, line_gameid); + + line_country = new QLineEdit(dockWidgetContents); + line_country->setObjectName(QString::fromUtf8("line_country")); + line_country->setEnabled(true); + line_country->setReadOnly(true); + + formLayout->setWidget(5, QFormLayout::FieldRole, line_country); + + label_banner = new QLabel(dockWidgetContents); + label_banner->setObjectName(QString::fromUtf8("label_banner")); + label_banner->setAlignment(Qt::AlignCenter); + + formLayout->setWidget(9, QFormLayout::FieldRole, label_banner); + + label_developer = new QLabel(dockWidgetContents); + label_developer->setObjectName(QString::fromUtf8("label_developer")); + + formLayout->setWidget(3, QFormLayout::LabelRole, label_developer); + + line_developer = new QLineEdit(dockWidgetContents); + line_developer->setObjectName(QString::fromUtf8("line_developer")); + line_developer->setReadOnly(true); + + formLayout->setWidget(3, QFormLayout::FieldRole, line_developer); + + label_description = new QLabel(dockWidgetContents); + label_description->setObjectName(QString::fromUtf8("label_description")); + + formLayout->setWidget(7, QFormLayout::LabelRole, label_description); + + edit_description = new QPlainTextEdit(dockWidgetContents); + edit_description->setObjectName(QString::fromUtf8("edit_description")); + edit_description->setMaximumSize(QSize(16777215, 80)); + edit_description->setReadOnly(true); + edit_description->setPlainText(QString::fromUtf8("")); + + formLayout->setWidget(7, QFormLayout::FieldRole, edit_description); + + ImageInfo->setWidget(dockWidgetContents); + + retranslateUi(ImageInfo); + + QMetaObject::connectSlotsByName(ImageInfo); + } // setupUi + + void retranslateUi(QDockWidget *ImageInfo) + { + ImageInfo->setWindowTitle(QApplication::translate("ImageInfo", "Image Info", 0, QApplication::UnicodeUTF8)); + label_name->setText(QApplication::translate("ImageInfo", "Name", 0, QApplication::UnicodeUTF8)); + label_gameid->setText(QApplication::translate("ImageInfo", "Game ID", 0, QApplication::UnicodeUTF8)); + label_country->setText(QApplication::translate("ImageInfo", "Country", 0, QApplication::UnicodeUTF8)); + label_bannertext->setText(QApplication::translate("ImageInfo", "Banner", 0, QApplication::UnicodeUTF8)); + line_name->setText(QString()); + line_gameid->setText(QString()); + line_country->setText(QApplication::translate("ImageInfo", "EUROPE", 0, QApplication::UnicodeUTF8)); + label_banner->setText(QString()); + label_developer->setText(QApplication::translate("ImageInfo", "Developer", 0, QApplication::UnicodeUTF8)); + label_description->setText(QApplication::translate("ImageInfo", "Description", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class ImageInfo: public Ui_ImageInfo {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_IMAGE_INFO_H diff --git a/src/citra_qt/ui_main.h b/src/citra_qt/ui_main.h new file mode 100644 index 00000000..d349a5c6 --- /dev/null +++ b/src/citra_qt/ui_main.h @@ -0,0 +1,148 @@ +/******************************************************************************** +** Form generated from reading UI file 'main.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_MAIN_H +#define UI_MAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QAction *action_load_elf; + QAction *action_Exit; + QAction *action_Start; + QAction *action_Pause; + QAction *action_Stop; + QAction *action_About; + QAction *action_Single_Window_Mode; + QAction *action_Hotkeys; + QAction *action_Configure; + QWidget *centralwidget; + QHBoxLayout *horizontalLayout; + QMenuBar *menubar; + QMenu *menu_File; + QMenu *menu_Emulation; + QMenu *menu_View; + QMenu *menu_Help; + QStatusBar *statusbar; + + void setupUi(QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->resize(1081, 730); + QIcon icon; + icon.addFile(QString::fromUtf8("src/pcafe/res/icon3_64x64.ico"), QSize(), QIcon::Normal, QIcon::Off); + MainWindow->setWindowIcon(icon); + MainWindow->setTabShape(QTabWidget::Rounded); + MainWindow->setDockNestingEnabled(true); + action_load_elf = new QAction(MainWindow); + action_load_elf->setObjectName(QString::fromUtf8("action_load_elf")); + action_Exit = new QAction(MainWindow); + action_Exit->setObjectName(QString::fromUtf8("action_Exit")); + action_Start = new QAction(MainWindow); + action_Start->setObjectName(QString::fromUtf8("action_Start")); + action_Pause = new QAction(MainWindow); + action_Pause->setObjectName(QString::fromUtf8("action_Pause")); + action_Pause->setEnabled(false); + action_Stop = new QAction(MainWindow); + action_Stop->setObjectName(QString::fromUtf8("action_Stop")); + action_Stop->setEnabled(false); + action_About = new QAction(MainWindow); + action_About->setObjectName(QString::fromUtf8("action_About")); + action_Single_Window_Mode = new QAction(MainWindow); + action_Single_Window_Mode->setObjectName(QString::fromUtf8("action_Single_Window_Mode")); + action_Single_Window_Mode->setCheckable(true); + action_Hotkeys = new QAction(MainWindow); + action_Hotkeys->setObjectName(QString::fromUtf8("action_Hotkeys")); + action_Configure = new QAction(MainWindow); + action_Configure->setObjectName(QString::fromUtf8("action_Configure")); + centralwidget = new QWidget(MainWindow); + centralwidget->setObjectName(QString::fromUtf8("centralwidget")); + horizontalLayout = new QHBoxLayout(centralwidget); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + MainWindow->setCentralWidget(centralwidget); + menubar = new QMenuBar(MainWindow); + menubar->setObjectName(QString::fromUtf8("menubar")); + menubar->setGeometry(QRect(0, 0, 1081, 20)); + menu_File = new QMenu(menubar); + menu_File->setObjectName(QString::fromUtf8("menu_File")); + menu_Emulation = new QMenu(menubar); + menu_Emulation->setObjectName(QString::fromUtf8("menu_Emulation")); + menu_View = new QMenu(menubar); + menu_View->setObjectName(QString::fromUtf8("menu_View")); + menu_Help = new QMenu(menubar); + menu_Help->setObjectName(QString::fromUtf8("menu_Help")); + MainWindow->setMenuBar(menubar); + statusbar = new QStatusBar(MainWindow); + statusbar->setObjectName(QString::fromUtf8("statusbar")); + MainWindow->setStatusBar(statusbar); + + menubar->addAction(menu_File->menuAction()); + menubar->addAction(menu_Emulation->menuAction()); + menubar->addAction(menu_View->menuAction()); + menubar->addAction(menu_Help->menuAction()); + menu_File->addAction(action_load_elf); + menu_File->addSeparator(); + menu_File->addAction(action_Exit); + menu_Emulation->addAction(action_Start); + menu_Emulation->addAction(action_Pause); + menu_Emulation->addAction(action_Stop); + menu_Emulation->addSeparator(); + menu_Emulation->addAction(action_Configure); + menu_View->addAction(action_Single_Window_Mode); + menu_View->addAction(action_Hotkeys); + menu_Help->addAction(action_About); + + retranslateUi(MainWindow); + QObject::connect(action_Exit, SIGNAL(triggered()), MainWindow, SLOT(close())); + QObject::connect(action_Configure, SIGNAL(triggered()), MainWindow, SLOT(OnConfigure())); + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Citra", 0, QApplication::UnicodeUTF8)); + action_load_elf->setText(QApplication::translate("MainWindow", "Load ELF ...", 0, QApplication::UnicodeUTF8)); + action_Exit->setText(QApplication::translate("MainWindow", "E&xit", 0, QApplication::UnicodeUTF8)); + action_Start->setText(QApplication::translate("MainWindow", "&Start", 0, QApplication::UnicodeUTF8)); + action_Pause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8)); + action_Stop->setText(QApplication::translate("MainWindow", "&Stop", 0, QApplication::UnicodeUTF8)); + action_About->setText(QApplication::translate("MainWindow", "About Citra", 0, QApplication::UnicodeUTF8)); + action_Single_Window_Mode->setText(QApplication::translate("MainWindow", "Single Window Mode", 0, QApplication::UnicodeUTF8)); + action_Hotkeys->setText(QApplication::translate("MainWindow", "Configure &Hotkeys ...", 0, QApplication::UnicodeUTF8)); + action_Configure->setText(QApplication::translate("MainWindow", "Configure ...", 0, QApplication::UnicodeUTF8)); + menu_File->setTitle(QApplication::translate("MainWindow", "&File", 0, QApplication::UnicodeUTF8)); + menu_Emulation->setTitle(QApplication::translate("MainWindow", "&Emulation", 0, QApplication::UnicodeUTF8)); + menu_View->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8)); + menu_Help->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAIN_H diff --git a/src/citra_qt/ui_welcome_wizard.h b/src/citra_qt/ui_welcome_wizard.h new file mode 100644 index 00000000..0cc5ceb4 --- /dev/null +++ b/src/citra_qt/ui_welcome_wizard.h @@ -0,0 +1,124 @@ +/******************************************************************************** +** Form generated from reading UI file 'welcome_wizard.ui' +** +** Created by: Qt User Interface Compiler version 4.8.5 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_WELCOME_WIZARD_H +#define UI_WELCOME_WIZARD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "path_list.hxx" + +QT_BEGIN_NAMESPACE + +class Ui_WelcomeWizard +{ +public: + QWizardPage *wizardPage1; + QWizardPage *wizardPage2; + QVBoxLayout *verticalLayout_2; + QHBoxLayout *horizontalLayout; + QLineEdit *edit_path; + QPushButton *button_browse_path; + QHBoxLayout *horizontalLayout_2; + GPathList *path_list; + QVBoxLayout *verticalLayout_3; + QPushButton *button_add_path; + QSpacerItem *verticalSpacer; + + void setupUi(QWizard *WelcomeWizard) + { + if (WelcomeWizard->objectName().isEmpty()) + WelcomeWizard->setObjectName(QString::fromUtf8("WelcomeWizard")); + WelcomeWizard->resize(510, 300); + WelcomeWizard->setModal(true); + wizardPage1 = new QWizardPage(); + wizardPage1->setObjectName(QString::fromUtf8("wizardPage1")); + WelcomeWizard->addPage(wizardPage1); + wizardPage2 = new QWizardPage(); + wizardPage2->setObjectName(QString::fromUtf8("wizardPage2")); + verticalLayout_2 = new QVBoxLayout(wizardPage2); + verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); + horizontalLayout = new QHBoxLayout(); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + edit_path = new QLineEdit(wizardPage2); + edit_path->setObjectName(QString::fromUtf8("edit_path")); + edit_path->setReadOnly(true); + + horizontalLayout->addWidget(edit_path); + + button_browse_path = new QPushButton(wizardPage2); + button_browse_path->setObjectName(QString::fromUtf8("button_browse_path")); + + horizontalLayout->addWidget(button_browse_path); + + + verticalLayout_2->addLayout(horizontalLayout); + + horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); + path_list = new GPathList(wizardPage2); + path_list->setObjectName(QString::fromUtf8("path_list")); + + horizontalLayout_2->addWidget(path_list); + + verticalLayout_3 = new QVBoxLayout(); + verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3")); + button_add_path = new QPushButton(wizardPage2); + button_add_path->setObjectName(QString::fromUtf8("button_add_path")); + + verticalLayout_3->addWidget(button_add_path); + + verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + verticalLayout_3->addItem(verticalSpacer); + + + horizontalLayout_2->addLayout(verticalLayout_3); + + + verticalLayout_2->addLayout(horizontalLayout_2); + + WelcomeWizard->addPage(wizardPage2); + + retranslateUi(WelcomeWizard); + + QMetaObject::connectSlotsByName(WelcomeWizard); + } // setupUi + + void retranslateUi(QWizard *WelcomeWizard) + { + WelcomeWizard->setWindowTitle(QApplication::translate("WelcomeWizard", "Welcome", 0, QApplication::UnicodeUTF8)); + wizardPage1->setTitle(QApplication::translate("WelcomeWizard", "Welcome", 0, QApplication::UnicodeUTF8)); + wizardPage1->setSubTitle(QApplication::translate("WelcomeWizard", "This wizard will guide you through the initial configuration.", 0, QApplication::UnicodeUTF8)); + wizardPage2->setTitle(QApplication::translate("WelcomeWizard", "ISO paths", 0, QApplication::UnicodeUTF8)); + wizardPage2->setSubTitle(QApplication::translate("WelcomeWizard", "If you have a collection of game images, you can add them to the path list here. Gekko will automatically show a list of your collection on startup then.", 0, QApplication::UnicodeUTF8)); + edit_path->setText(QString()); + edit_path->setPlaceholderText(QApplication::translate("WelcomeWizard", "Select a path to add ...", 0, QApplication::UnicodeUTF8)); + button_browse_path->setText(QString()); + button_add_path->setText(QString()); + } // retranslateUi + +}; + +namespace Ui { + class WelcomeWizard: public Ui_WelcomeWizard {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_WELCOME_WIZARD_H diff --git a/src/citra_qt/version.h b/src/citra_qt/version.h new file mode 100644 index 00000000..07022de5 --- /dev/null +++ b/src/citra_qt/version.h @@ -0,0 +1,7 @@ +// TODO: Supposed to be generated... +// GENERATED - Do not edit! +#ifndef VERSION_H_ +#define VERSION_H_ +#define __BUILD__ "40" +#define VERSION __BUILD__ +#endif // VERSION_H_ diff --git a/src/common/atomic.h b/src/common/atomic.h new file mode 100644 index 00000000..883bc14f --- /dev/null +++ b/src/common/atomic.h @@ -0,0 +1,19 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_H_ +#define _ATOMIC_H_ + +#ifdef _WIN32 + +#include "atomic_win32.h" + +#else + +// GCC-compatible compiler assumed! +#include "atomic_gcc.h" + +#endif + +#endif diff --git a/src/common/atomic_gcc.h b/src/common/atomic_gcc.h new file mode 100644 index 00000000..2eb38697 --- /dev/null +++ b/src/common/atomic_gcc.h @@ -0,0 +1,113 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_GCC_H_ +#define _ATOMIC_GCC_H_ + +#include "common.h" + +// Atomic operations are performed in a single step by the CPU. It is +// impossible for other threads to see the operation "half-done." +// +// Some atomic operations can be combined with different types of memory +// barriers called "Acquire semantics" and "Release semantics", defined below. +// +// Acquire semantics: Future memory accesses cannot be relocated to before the +// operation. +// +// Release semantics: Past memory accesses cannot be relocated to after the +// operation. +// +// These barriers affect not only the compiler, but also the CPU. + +namespace Common +{ + +inline void AtomicAdd(volatile u32& target, u32 value) { + __sync_add_and_fetch(&target, value); +} + +inline void AtomicAnd(volatile u32& target, u32 value) { + __sync_and_and_fetch(&target, value); +} + +inline void AtomicDecrement(volatile u32& target) { + __sync_add_and_fetch(&target, -1); +} + +inline void AtomicIncrement(volatile u32& target) { + __sync_add_and_fetch(&target, 1); +} + +inline u32 AtomicLoad(volatile u32& src) { + return src; // 32-bit reads are always atomic. +} +inline u32 AtomicLoadAcquire(volatile u32& src) { + //keep the compiler from caching any memory references + u32 result = src; // 32-bit reads are always atomic. + //__sync_synchronize(); // TODO: May not be necessary. + // Compiler instruction only. x86 loads always have acquire semantics. + __asm__ __volatile__ ( "":::"memory" ); + return result; +} + +inline void AtomicOr(volatile u32& target, u32 value) { + __sync_or_and_fetch(&target, value); +} + +inline void AtomicStore(volatile u32& dest, u32 value) { + dest = value; // 32-bit writes are always atomic. +} +inline void AtomicStoreRelease(volatile u32& dest, u32 value) { + __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. +} + +} + +// Old code kept here for reference in case we need the parts with __asm__ __volatile__. +#if 0 +LONG SyncInterlockedIncrement(LONG *Dest) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_add_and_fetch(Dest, 1); +#else + register int result; + __asm__ __volatile__("lock; xadd %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (1), "m" (*Dest) + : "memory"); + return result; +#endif +} + +LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_add_and_fetch(Dest, Val); +#else + register int result; + __asm__ __volatile__("lock; xadd %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); + return result; +#endif +} + +LONG SyncInterlockedExchange(LONG *Dest, LONG Val) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_lock_test_and_set(Dest, Val); +#else + register int result; + __asm__ __volatile__("lock; xchg %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); + return result; +#endif +} +#endif + +#endif diff --git a/src/common/atomic_win32.h b/src/common/atomic_win32.h new file mode 100644 index 00000000..760b16d4 --- /dev/null +++ b/src/common/atomic_win32.h @@ -0,0 +1,72 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_WIN32_H_ +#define _ATOMIC_WIN32_H_ + +#include "common.h" +#include +#include + +// Atomic operations are performed in a single step by the CPU. It is +// impossible for other threads to see the operation "half-done." +// +// Some atomic operations can be combined with different types of memory +// barriers called "Acquire semantics" and "Release semantics", defined below. +// +// Acquire semantics: Future memory accesses cannot be relocated to before the +// operation. +// +// Release semantics: Past memory accesses cannot be relocated to after the +// operation. +// +// These barriers affect not only the compiler, but also the CPU. +// +// NOTE: Acquire and Release are not differentiated right now. They perform a +// full memory barrier instead of a "one-way" memory barrier. The newest +// Windows SDK has Acquire and Release versions of some Interlocked* functions. + +namespace Common +{ + +inline void AtomicAdd(volatile u32& target, u32 value) { + InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); +} + +inline void AtomicAnd(volatile u32& target, u32 value) { + _InterlockedAnd((volatile LONG*)&target, (LONG)value); +} + +inline void AtomicIncrement(volatile u32& target) { + InterlockedIncrement((volatile LONG*)&target); +} + +inline void AtomicDecrement(volatile u32& target) { + InterlockedDecrement((volatile LONG*)&target); +} + +inline u32 AtomicLoad(volatile u32& src) { + return src; // 32-bit reads are always atomic. +} +inline u32 AtomicLoadAcquire(volatile u32& src) { + u32 result = src; // 32-bit reads are always atomic. + _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. + return result; +} + +inline void AtomicOr(volatile u32& target, u32 value) { + _InterlockedOr((volatile LONG*)&target, (LONG)value); +} + +inline void AtomicStore(volatile u32& dest, u32 value) { + dest = value; // 32-bit writes are always atomic. +} +inline void AtomicStoreRelease(volatile u32& dest, u32 value) { + _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. + dest = value; // 32-bit writes are always atomic. +} + +} + +#endif diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp new file mode 100644 index 00000000..787263f7 --- /dev/null +++ b/src/common/break_points.cpp @@ -0,0 +1,203 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "debug_interface.h" +#include "break_points.h" + +#include +#include + +bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + if (i->iAddress == _iAddress) + return true; + return false; +} + +bool BreakPoints::IsTempBreakPoint(u32 _iAddress) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + if (i->iAddress == _iAddress && i->bTemporary) + return true; + return false; +} + +BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const +{ + TBreakPointsStr bps; + for (TBreakPoints::const_iterator i = m_BreakPoints.begin(); + i != m_BreakPoints.end(); ++i) + { + if (!i->bTemporary) + { + std::stringstream bp; + bp << std::hex << i->iAddress << " " << (i->bOn ? "n" : ""); + bps.push_back(bp.str()); + } + } + + return bps; +} + +void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) +{ + for (TBreakPointsStr::const_iterator i = bps.begin(); i != bps.end(); ++i) + { + TBreakPoint bp; + std::stringstream bpstr; + bpstr << std::hex << *i; + bpstr >> bp.iAddress; + bp.bOn = i->find("n") != i->npos; + bp.bTemporary = false; + Add(bp); + } +} + +void BreakPoints::Add(const TBreakPoint& bp) +{ + if (!IsAddressBreakPoint(bp.iAddress)) + { + m_BreakPoints.push_back(bp); + //if (jit) + // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + } +} + +void BreakPoints::Add(u32 em_address, bool temp) +{ + if (!IsAddressBreakPoint(em_address)) // only add new addresses + { + TBreakPoint pt; // breakpoint settings + pt.bOn = true; + pt.bTemporary = temp; + pt.iAddress = em_address; + + m_BreakPoints.push_back(pt); + + //if (jit) + // jit->GetBlockCache()->InvalidateICache(em_address, 4); + } +} + +void BreakPoints::Remove(u32 em_address) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + { + if (i->iAddress == em_address) + { + m_BreakPoints.erase(i); + //if (jit) + // jit->GetBlockCache()->InvalidateICache(em_address, 4); + return; + } + } +} + +void BreakPoints::Clear() +{ + //if (jit) + //{ + // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), + // [](const TBreakPoint& bp) + // { + // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + // } + // ); + //} + + m_BreakPoints.clear(); +} + +MemChecks::TMemChecksStr MemChecks::GetStrings() const +{ + TMemChecksStr mcs; + for (TMemChecks::const_iterator i = m_MemChecks.begin(); + i != m_MemChecks.end(); ++i) + { + std::stringstream mc; + mc << std::hex << i->StartAddress; + mc << " " << (i->bRange ? i->EndAddress : i->StartAddress) << " " << + (i->bRange ? "n" : "") << (i->OnRead ? "r" : "") << + (i->OnWrite ? "w" : "") << (i->Log ? "l" : "") << (i->Break ? "p" : ""); + mcs.push_back(mc.str()); + } + + return mcs; +} + +void MemChecks::AddFromStrings(const TMemChecksStr& mcs) +{ + for (TMemChecksStr::const_iterator i = mcs.begin(); i != mcs.end(); ++i) + { + TMemCheck mc; + std::stringstream mcstr; + mcstr << std::hex << *i; + mcstr >> mc.StartAddress; + mc.bRange = i->find("n") != i->npos; + mc.OnRead = i->find("r") != i->npos; + mc.OnWrite = i->find("w") != i->npos; + mc.Log = i->find("l") != i->npos; + mc.Break = i->find("p") != i->npos; + if (mc.bRange) + mcstr >> mc.EndAddress; + else + mc.EndAddress = mc.StartAddress; + Add(mc); + } +} + +void MemChecks::Add(const TMemCheck& _rMemoryCheck) +{ + if (GetMemCheck(_rMemoryCheck.StartAddress) == 0) + m_MemChecks.push_back(_rMemoryCheck); +} + +void MemChecks::Remove(u32 _Address) +{ + for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) + { + if (i->StartAddress == _Address) + { + m_MemChecks.erase(i); + return; + } + } +} + +TMemCheck *MemChecks::GetMemCheck(u32 address) +{ + for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) + { + if (i->bRange) + { + if (address >= i->StartAddress && address <= i->EndAddress) + return &(*i); + } + else if (i->StartAddress == address) + return &(*i); + } + + // none found + return 0; +} + +void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, + bool write, int size, u32 pc) +{ + if ((write && OnWrite) || (!write && OnRead)) + { + if (Log) + { + INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", + pc, debug_interface->getDescription(pc).c_str(), + write ? "Write" : "Read", size*8, size*2, iValue, addr, + debug_interface->getDescription(addr).c_str() + ); + } + if (Break) + debug_interface->breakNow(); + } +} diff --git a/src/common/break_points.h b/src/common/break_points.h new file mode 100644 index 00000000..dc771ba0 --- /dev/null +++ b/src/common/break_points.h @@ -0,0 +1,102 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _DEBUGGER_BREAKPOINTS_H +#define _DEBUGGER_BREAKPOINTS_H + +#include +#include + +#include "common.h" + +class DebugInterface; + +struct TBreakPoint +{ + u32 iAddress; + bool bOn; + bool bTemporary; +}; + +struct TMemCheck +{ + TMemCheck() { + numHits = 0; + StartAddress = EndAddress = 0; + bRange = OnRead = OnWrite = Log = Break = false; + } + u32 StartAddress; + u32 EndAddress; + + bool bRange; + + bool OnRead; + bool OnWrite; + + bool Log; + bool Break; + + u32 numHits; + + void Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, + bool write, int size, u32 pc); +}; + +// Code breakpoints. +class BreakPoints +{ +public: + typedef std::vector TBreakPoints; + typedef std::vector TBreakPointsStr; + + const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } + + TBreakPointsStr GetStrings() const; + void AddFromStrings(const TBreakPointsStr& bps); + + // is address breakpoint + bool IsAddressBreakPoint(u32 _iAddress); + bool IsTempBreakPoint(u32 _iAddress); + + // Add BreakPoint + void Add(u32 em_address, bool temp=false); + void Add(const TBreakPoint& bp); + + // Remove Breakpoint + void Remove(u32 _iAddress); + void Clear(); + + void DeleteByAddress(u32 _Address); + +private: + TBreakPoints m_BreakPoints; + u32 m_iBreakOnCount; +}; + + +// Memory breakpoints +class MemChecks +{ +public: + typedef std::vector TMemChecks; + typedef std::vector TMemChecksStr; + + TMemChecks m_MemChecks; + + const TMemChecks& GetMemChecks() { return m_MemChecks; } + + TMemChecksStr GetStrings() const; + void AddFromStrings(const TMemChecksStr& mcs); + + void Add(const TMemCheck& _rMemoryCheck); + + // memory breakpoint + TMemCheck *GetMemCheck(u32 address); + void Remove(u32 _Address); + + void Clear() { m_MemChecks.clear(); }; +}; + +#endif + diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h new file mode 100644 index 00000000..68c2943a --- /dev/null +++ b/src/common/chunk_file.h @@ -0,0 +1,874 @@ +// 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/ + +#ifndef _POINTERWRAP_H_ +#define _POINTERWRAP_H_ + +// Extremely simple serialization framework. + +// (mis)-features: +// + Super fast +// + Very simple +// + Same code is used for serialization and deserializaition (in most cases) +// - Zero backwards/forwards compatibility +// - Serialization code for anything complex has to be manually written. + +#include +#include +#include +#include +#include +#include +#ifndef __SYMBIAN32__ +#if defined(IOS) || defined(MACGNUSTD) +#include +#else +#include +#endif +#endif + +#include "common.h" +#include "file_util.h" +//#include "../ext/snappy/snappy-c.h" + +#if defined(IOS) || defined(MACGNUSTD) +namespace std { + using tr1::is_pointer; +} +#endif +#ifdef __SYMBIAN32__ +namespace std { + template + struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; + }; + template const bool bool_constant::value; + template struct is_pointer : public bool_constant {}; + template struct is_pointer : public bool_constant {}; +} +#endif + +template +struct LinkedListItem : public T +{ + LinkedListItem *next; +}; + +class PointerWrap; + +class PointerWrapSection +{ +public: + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { + } + ~PointerWrapSection(); + + bool operator == (const int &v) const { return ver_ == v; } + bool operator != (const int &v) const { return ver_ != v; } + bool operator <= (const int &v) const { return ver_ <= v; } + bool operator >= (const int &v) const { return ver_ >= v; } + bool operator < (const int &v) const { return ver_ < v; } + bool operator > (const int &v) const { return ver_ > v; } + + operator bool() const { + return ver_ > 0; + } + +private: + PointerWrap &p_; + int ver_; + const char *title_; +}; + +// Wrapper class +class PointerWrap +{ + // This makes it a compile error if you forget to define DoState() on non-POD. + // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... +#ifdef _MSC_VER + template::value, bool isPointer = std::is_pointer::value> +#else + template::value> +#endif + struct DoHelper + { + static void DoArray(PointerWrap *p, T *x, int count) + { + for (int i = 0; i < count; ++i) + p->Do(x[i]); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoClass(x); + } + }; + + template + struct DoHelper + { + static void DoArray(PointerWrap *p, T *x, int count) + { + p->DoVoid((void *)x, sizeof(T) * count); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoVoid((void *)&x, sizeof(x)); + } + }; + +public: + enum Mode { + MODE_READ = 1, // load + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + }; + + enum Error { + ERROR_NONE = 0, + ERROR_WARNING = 1, + ERROR_FAILURE = 2, + }; + + u8 **ptr; + Mode mode; + Error error; + +public: + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} + + PointerWrapSection Section(const char *title, int ver) { + return Section(title, ver, ver); + } + + // The returned object can be compared against the version that was loaded. + // This can be used to support versions as old as minVer. + // Version = 0 means the section was not found. + PointerWrapSection Section(const char *title, int minVer, int ver) { + char marker[16] = {0}; + int foundVersion = ver; + + strncpy(marker, title, sizeof(marker)); + if (!ExpectVoid(marker, sizeof(marker))) + { + // Might be before we added name markers for safety. + if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) + DoMarker(title); + // Wasn't found, but maybe we can still load the state. + else + foundVersion = 0; + } + else + Do(foundVersion); + + if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { + WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + return PointerWrapSection(*this, foundVersion, title); + } + + void SetMode(Mode mode_) {mode = mode_;} + Mode GetMode() const {return mode;} + u8 **GetPPtr() {return ptr;} + void SetError(Error error_) + { + if (error < error_) + error = error_; + if (error > ERROR_WARNING) + mode = PointerWrap::MODE_MEASURE; + } + + bool ExpectVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; + default: break; // throw an error? + } + (*ptr) += size; + return true; + } + + void DoVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: memcpy(data, *ptr, size); break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; + default: break; // throw an error? + } + (*ptr) += size; + } + + template + void Do(std::map &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMap(x, dv); + } + + template + void Do(std::map &x) + { + T dv = T(); + DoMap(x, dv); + } + + template + void DoMap(std::map &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x[first] = second; + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::map::iterator itr = x.begin(); + while (number > 0) + { + K first = itr->first; + Do(first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + template + void Do(std::multimap &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMultimap(x, dv); + } + + template + void Do(std::multimap &x) + { + T dv = T(); + DoMultimap(x, dv); + } + + template + void DoMultimap(std::multimap &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x.insert(std::make_pair(first, second)); + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::multimap::iterator itr = x.begin(); + while (number > 0) + { + Do(itr->first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + // Store vectors. + template + void Do(std::vector &x) + { + T *dv = NULL; + DoVector(x, dv); + } + + template + void Do(std::vector &x) + { + T dv = T(); + DoVector(x, dv); + } + + + template + void DoPOD(std::vector &x) + { + T dv = T(); + DoVectorPOD(x, dv); + } + + template + void Do(std::vector &x, T &default_val) + { + DoVector(x, default_val); + } + + template + void DoVector(std::vector &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + template + void DoVectorPOD(std::vector &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + // Store deques. + template + void Do(std::deque &x) + { + T *dv = NULL; + DoDeque(x, dv); + } + + template + void Do(std::deque &x) + { + T dv = T(); + DoDeque(x, dv); + } + + template + void DoDeque(std::deque &x, T &default_val) + { + u32 deq_size = (u32)x.size(); + Do(deq_size); + x.resize(deq_size, default_val); + u32 i; + for(i = 0; i < deq_size; i++) + Do(x[i]); + } + + // Store STL lists. + template + void Do(std::list &x) + { + T *dv = NULL; + Do(x, dv); + } + + template + void Do(std::list &x) + { + T dv = T(); + DoList(x, dv); + } + + template + void Do(std::list &x, T &default_val) + { + DoList(x, default_val); + } + + template + void DoList(std::list &x, T &default_val) + { + u32 list_size = (u32)x.size(); + Do(list_size); + x.resize(list_size, default_val); + + typename std::list::iterator itr, end; + for (itr = x.begin(), end = x.end(); itr != end; ++itr) + Do(*itr); + } + + + // Store STL sets. + template + void Do(std::set &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (*it != NULL) + delete *it; + } + } + DoSet(x); + } + + template + void Do(std::set &x) + { + DoSet(x); + } + + template + void DoSet(std::set &x) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + + switch (mode) + { + case MODE_READ: + { + x.clear(); + while (number-- > 0) + { + T it = T(); + Do(it); + x.insert(it); + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::set::iterator itr = x.begin(); + while (number-- > 0) + Do(*itr++); + } + break; + + default: + ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); + } + } + + // Store strings. + void Do(std::string &x) + { + int stringLen = (int)x.length() + 1; + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (char*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; + } + (*ptr) += stringLen; + } + + void Do(std::wstring &x) + { + int stringLen = sizeof(wchar_t)*((int)x.length() + 1); + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (wchar_t*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; + } + (*ptr) += stringLen; + } + + template + void DoClass(T &x) { + x.DoState(*this); + } + + template + void DoClass(T *&x) { + if (mode == MODE_READ) + { + if (x != NULL) + delete x; + x = new T(); + } + x->DoState(*this); + } + + template + void DoArray(T *x, int count) { + DoHelper::DoArray(this, x, count); + } + + template + void Do(T &x) { + DoHelper::Do(this, x); + } + + template + void DoPOD(T &x) { + DoHelper::Do(this, x); + } + + template + void DoPointer(T* &x, T*const base) { + // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range + s32 offset = x - base; + Do(offset); + if (mode == MODE_READ) + x = base + offset; + } + + template* (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> + void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) + { + LinkedListItem* list_cur = list_start; + LinkedListItem* prev = 0; + + while (true) + { + u8 shouldExist = (list_cur ? 1 : 0); + Do(shouldExist); + if (shouldExist == 1) + { + LinkedListItem* cur = list_cur ? list_cur : TNew(); + TDo(*this, (T*)cur); + if (!list_cur) + { + if (mode == MODE_READ) + { + cur->next = 0; + list_cur = cur; + if (prev) + prev->next = cur; + else + list_start = cur; + } + else + { + TFree(cur); + continue; + } + } + } + else + { + if (mode == MODE_READ) + { + if (prev) + prev->next = 0; + if (list_end) + *list_end = prev; + if (list_cur) + { + if (list_start == list_cur) + list_start = 0; + do + { + LinkedListItem* next = list_cur->next; + TFree(list_cur); + list_cur = next; + } + while (list_cur); + } + } + break; + } + prev = list_cur; + list_cur = list_cur->next; + } + } + + void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) + { + u32 cookie = arbitraryNumber; + Do(cookie); + if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) + { + PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + SetError(ERROR_FAILURE); + } + } +}; + +inline PointerWrapSection::~PointerWrapSection() { + if (ver_ > 0) { + p_.DoMarker(title_); + } +} + + +class CChunkFileReader +{ +public: + enum Error { + ERROR_NONE, + ERROR_BAD_FILE, + ERROR_BROKEN_STATE, + }; + + // Load file template + template + static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) + { + INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); + _failureReason->clear(); + _failureReason->append("LoadStateWrongVersion"); + + if (!File::Exists(_rFilename)) { + _failureReason->clear(); + _failureReason->append("LoadStateDoesntExist"); + ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); + return ERROR_BAD_FILE; + } + + // Check file size + const u64 fileSize = File::GetSize(_rFilename); + static const u64 headerSize = sizeof(SChunkHeader); + if (fileSize < headerSize) + { + ERROR_LOG(COMMON,"ChunkReader: File too small"); + return ERROR_BAD_FILE; + } + + File::IOFile pFile(_rFilename, "rb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); + return ERROR_BAD_FILE; + } + + // read the header + SChunkHeader header; + if (!pFile.ReadArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Bad header size"); + return ERROR_BAD_FILE; + } + + // Check revision + if (header.Revision != _Revision) + { + ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", + header.Revision, _Revision); + return ERROR_BAD_FILE; + } + + if (strcmp(header.GitVersion, _VersionString) != 0) + { + WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", + header.GitVersion); + } + + // get size + const int sz = (int)(fileSize - headerSize); + if (header.ExpectedSize != sz) + { + ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", + sz, header.ExpectedSize); + return ERROR_BAD_FILE; + } + + // read the state + u8* buffer = new u8[sz]; + if (!pFile.ReadBytes(buffer, sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Error reading file"); + return ERROR_BAD_FILE; + } + + u8 *ptr = buffer; + u8 *buf = buffer; + if (header.Compress) { + u8 *uncomp_buffer = new u8[header.UncompressedSize]; + size_t uncomp_size = header.UncompressedSize; + snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); + if ((int)uncomp_size != header.UncompressedSize) { + ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); + } + ptr = uncomp_buffer; + buf = uncomp_buffer; + delete [] buffer; + } + + PointerWrap p(&ptr, PointerWrap::MODE_READ); + _class.DoState(p); + delete[] buf; + + INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + // Save file template + template + static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) + { + INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); + + File::IOFile pFile(_rFilename, "wb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); + return ERROR_BAD_FILE; + } + + bool compress = true; + + // Get data + u8 *ptr = 0; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + + u8 * buffer = new u8[sz]; + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Create header + SChunkHeader header; + header.Compress = compress ? 1 : 0; + header.Revision = _Revision; + header.ExpectedSize = (int)sz; + header.UncompressedSize = (int)sz; + strncpy(header.GitVersion, _VersionString, 32); + header.GitVersion[31] = '\0'; + + // Write to file + if (compress) { + size_t comp_len = snappy_max_compressed_length(sz); + u8 *compressed_buffer = new u8[comp_len]; + snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); + delete [] buffer; + header.ExpectedSize = (int)comp_len; + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { + ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); + return ERROR_BAD_FILE; + } else { + INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); + } + delete [] compressed_buffer; + } else { + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&buffer[0], sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); + return ERROR_BAD_FILE; + } + delete [] buffer; + } + + INFO_LOG(COMMON,"ChunkReader: Done writing %s", + _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + template + static Error Verify(T& _class) + { + u8 *ptr = 0; + + // Step 1: Measure the space required. + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + std::vector buffer(sz); + + // Step 2: Dump the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Step 3: Verify the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_VERIFY); + _class.DoState(p); + + return ERROR_NONE; + } + +private: + struct SChunkHeader + { + int Revision; + int Compress; + int ExpectedSize; + int UncompressedSize; + char GitVersion[32]; + }; +}; + +#endif // _POINTERWRAP_H_ diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 00000000..3b71d9b3 --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,171 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +// DO NOT EVER INCLUDE directly _or indirectly_ from this file +// since it slows down the build a lot. + +#include +#include +#include + +// SVN version number +extern const char *scm_rev_str; +extern const char *netplay_dolphin_ver; + +// Force enable logging in the right modes. For some reason, something had changed +// so that debugfast no longer logged. +#if defined(_DEBUG) || defined(DEBUGFAST) +#undef LOGGING +#define LOGGING 1 +#endif + +#define STACKALIGN + +#if __cplusplus >= 201103 || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) +#define HAVE_CXX11_SYNTAX 1 +#endif + +#if HAVE_CXX11_SYNTAX +// 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); +}; +#endif + +#include "log.h" +#include "common_types.h" +#include "msg_handler.h" +#include "common_funcs.h" +#include "common_paths.h" +#include "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 + + #define NOMINMAX + +// Memory leak checks + #define CHECK_HEAP_INTEGRITY() + +// 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 + +// Since they are always around on windows + #define HAVE_WX 1 + #define HAVE_OPENAL 1 + + #define HAVE_PORTAUDIO 1 + +// Debug definitions + #if defined(_DEBUG) + #include + #undef CHECK_HEAP_INTEGRITY + #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} + // If you want to see how much a pain in the ass singletons are, for example: + // {614} normal block at 0x030C5310, 188 bytes long. + // Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 + struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } }; + //CrtDebugBreak breakAt(614); + #endif // end DEBUG/FAST + +#endif + +// Windows compatibility +#ifndef _WIN32 +#include +#define MAX_PATH PATH_MAX +#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 + +// Dummy macro for marking translatable strings that can not be immediately translated. +// wxWidgets does not have a true dummy macro for this. +#define _trans(a) a + +#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 +}; + +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#endif // _COMMON_H_ diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h new file mode 100644 index 00000000..7ca0b350 --- /dev/null +++ b/src/common/common_funcs.h @@ -0,0 +1,245 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMONFUNCS_H_ +#define _COMMONFUNCS_H_ + +#ifdef _WIN32 +#define SLEEP(x) Sleep(x) +#else +#include +#define SLEEP(x) usleep(x*1000) +#endif + +template struct CompileTimeAssert; +template<> struct CompileTimeAssert {}; + +#define b2(x) ( (x) | ( (x) >> 1) ) +#define b4(x) ( b2(x) | ( b2(x) >> 2) ) +#define b8(x) ( b4(x) | ( b4(x) >> 4) ) +#define b16(x) ( b8(x) | ( b8(x) >> 8) ) +#define b32(x) (b16(x) | (b16(x) >>16) ) +#define ROUND_UP_POW2(x) (b32(x - 1) + 1) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC +#include +static __inline __m128i __attribute__((__always_inline__)) +_mm_shuffle_epi8(__m128i a, __m128i mask) +{ + __m128i result; + __asm__("pshufb %1, %0" + : "=x" (result) + : "xm" (mask), "0" (a)); + return result; +} +#endif + +#ifndef _WIN32 + +#include +#ifdef __linux__ +#include +#elif defined __FreeBSD__ +#include +#endif + +// go to debugger mode + #ifdef GEKKO + #define Crash() + #elif defined _M_GENERIC + #define Crash() { exit(1); } + #else + #define Crash() {asm ("int $3");} + #endif + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +// GCC 4.8 defines all the rotate functions now +// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit +#ifndef _rotl +inline u32 _rotl(u32 x, int shift) { + shift &= 31; + if (!shift) return x; + return (x << shift) | (x >> (32 - shift)); +} + +inline u32 _rotr(u32 x, int shift) { + shift &= 31; + if (!shift) return x; + return (x >> shift) | (x << (32 - shift)); +} +#endif + +inline u64 _rotl64(u64 x, unsigned int shift){ + unsigned int n = shift % 64; + return (x << n) | (x >> (64 - n)); +} + +inline u64 _rotr64(u64 x, unsigned int shift){ + unsigned int n = shift % 64; + return (x >> n) | (x << (64 - n)); +} + +#else // WIN32 +// Function Cross-Compatibility + #define strcasecmp _stricmp + #define strncasecmp _strnicmp + #define unlink _unlink + #define snprintf _snprintf + #define vscprintf _vscprintf + +// 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 != NULL) + { + // 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 + + #if _M_IX86 + #define Crash() {__asm int 3} + #else +extern "C" { + __declspec(dllimport) void __stdcall DebugBreak(void); +} + #define Crash() {DebugBreak();} + #endif // M_IX86 +#endif // WIN32 ndef + +// Dolphin's min and max functions +#undef min +#undef max + +template +inline T min(const T& a, const T& b) {return a > b ? b : a;} +template +inline T max(const T& a, const T& b) {return a > b ? a : b;} + +// Generic function to get last error message. +// Call directly after the command or use the error num. +// This function might change the error code. +// Defined in Misc.cpp. +const char* GetLastErrorMsg(); + +namespace Common +{ +inline u8 swap8(u8 _data) {return _data;} +inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} + +#ifdef ANDROID +#undef swap16 +#undef swap32 +#undef swap64 +#endif + +#ifdef _WIN32 +inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} +inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} +inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} +#elif _M_ARM +inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} +inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} +inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} +#elif __linux__ +inline u16 swap16(u16 _data) {return bswap_16(_data);} +inline u32 swap32(u32 _data) {return bswap_32(_data);} +inline u64 swap64(u64 _data) {return bswap_64(_data);} +#elif __APPLE__ +inline __attribute__((always_inline)) u16 swap16(u16 _data) + {return (_data >> 8) | (_data << 8);} +inline __attribute__((always_inline)) u32 swap32(u32 _data) + {return __builtin_bswap32(_data);} +inline __attribute__((always_inline)) u64 swap64(u64 _data) + {return __builtin_bswap64(_data);} +#elif __FreeBSD__ +inline u16 swap16(u16 _data) {return bswap16(_data);} +inline u32 swap32(u32 _data) {return bswap32(_data);} +inline u64 swap64(u64 _data) {return bswap64(_data);} +#else +// Slow generic implementation. +inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} +inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} +inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} +#endif + +inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} +inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} +inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} + +template +void swap(u8*); + +template <> +inline void swap<1>(u8* data) +{} + +template <> +inline void swap<2>(u8* data) +{ + *reinterpret_cast(data) = swap16(data); +} + +template <> +inline void swap<4>(u8* data) +{ + *reinterpret_cast(data) = swap32(data); +} + +template <> +inline void swap<8>(u8* data) +{ + *reinterpret_cast(data) = swap64(data); +} + +template +inline T FromBigEndian(T data) +{ + //static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); + + swap(reinterpret_cast(&data)); + return data; +} + +} // Namespace Common + +#endif // _COMMONFUNCS_H_ diff --git a/src/common/common_paths.h b/src/common/common_paths.h new file mode 100644 index 00000000..9ccb87d8 --- /dev/null +++ b/src/common/common_paths.h @@ -0,0 +1,79 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMON_PATHS_H_ +#define _COMMON_PATHS_H_ + +// Make sure we pick up USER_DIR if set in config.h +#include "common.h" + +// Directory seperators, do we need this? +#define DIR_SEP "/" +#define DIR_SEP_CHR '/' + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// The user data dir +#define ROOT_DIR "." +#ifdef _WIN32 + #define USERDATA_DIR "user" + #define EMU_DATA_DIR "emu" +#else + #define USERDATA_DIR "user" + #ifdef USER_DIR + #define EMU_DATA_DIR USER_DIR + #else + #define EMU_DATA_DIR ".emu" + #endif +#endif + +// Shared data dirs (Sys and shared User for linux) +#ifdef _WIN32 + #define SYSDATA_DIR "sys" +#else + #ifdef DATA_DIR + #define SYSDATA_DIR DATA_DIR "sys" + #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP + #else + #define SYSDATA_DIR "sys" + #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP + #endif +#endif + +// Dirs in both User and Sys +#define EUR_DIR "EUR" +#define USA_DIR "USA" +#define JAP_DIR "JAP" + +// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) +#define CONFIG_DIR "config" +#define GAMECONFIG_DIR "game_config" +#define MAPS_DIR "maps" +#define CACHE_DIR "cache" +#define SHADERCACHE_DIR "shader_cache" +#define STATESAVES_DIR "state_saves" +#define SCREENSHOTS_DIR "screenShots" +#define DUMP_DIR "dump" +#define DUMP_TEXTURES_DIR "textures" +#define DUMP_FRAMES_DIR "frames" +#define DUMP_AUDIO_DIR "audio" +#define LOGS_DIR "logs" +#define SHADERS_DIR "shaders" +#define SYSCONF_DIR "sysconf" + +// Filenames +// Files in the directory returned by GetUserPath(D_CONFIG_IDX) +#define EMU_CONFIG "emu.ini" +#define DEBUGGER_CONFIG "debugger.ini" +#define LOGGER_CONFIG "logger.ini" + +// Files in the directory returned by GetUserPath(D_LOGS_IDX) +#define MAIN_LOG "emu.log" + +// Files in the directory returned by GetUserPath(D_SYSCONF_IDX) +#define SYSCONF "SYSCONF" + +#endif // _COMMON_PATHS_H_ diff --git a/src/common/common_types.h b/src/common/common_types.h new file mode 100644 index 00000000..af1cd0e2 --- /dev/null +++ b/src/common/common_types.h @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file common_types.h + * @author ShizZy + * @date 2012-02-11 + * @brief Common types used throughout the project + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#pragma once + +#include +#include // data_types__m128.cpp + +#ifdef _WIN32 + +#include + +typedef unsigned __int8 u8; ///< 8-bit unsigned byte +typedef unsigned __int16 u16; ///< 16-bit unsigned short +typedef unsigned __int32 u32; ///< 32-bit unsigned word +typedef unsigned __int64 u64; ///< 64-bit unsigned int + +typedef signed __int8 s8; ///< 8-bit signed byte +typedef signed __int16 s16; ///< 16-bit signed short +typedef signed __int32 s32; ///< 32-bit signed word +typedef signed __int64 s64; ///< 64-bit signed int + +#else + +typedef unsigned char u8; ///< 8-bit unsigned byte +typedef unsigned short u16; ///< 16-bit unsigned short +typedef unsigned int u32; ///< 32-bit unsigned word +typedef unsigned long long u64; ///< 64-bit unsigned int + +typedef signed char s8; ///< 8-bit signed byte +typedef signed short s16; ///< 16-bit signed short +typedef signed int s32; ///< 32-bit signed word +typedef signed long long s64; ///< 64-bit signed int + +// For using windows lock code +#define TCHAR char +#define LONG int + +#endif // _WIN32 + +typedef float f32; ///< 32-bit floating point +typedef double f64; ///< 64-bit floating point + +#include "swap.h" + +/// Union for fast 16-bit type casting +union t16 { + u8 _u8[2]; ///< 8-bit unsigned char(s) + u16 _u16; ///< 16-bit unsigned shorts(s) +}; + +/// Union for fast 32-bit type casting +union t32 { + f32 _f32; ///< 32-bit floating point(s) + u32 _u32; ///< 32-bit unsigned int(s) + s32 _s32; ///< 32-bit signed int(s) + u16 _u16[2]; ///< 16-bit unsigned shorts(s) + u8 _u8[4]; ///< 8-bit unsigned char(s) +}; + +/// Union for fast 64-bit type casting +union t64 { + f64 _f64; ///< 64-bit floating point + u64 _u64; ///< 64-bit unsigned long + f32 _f32[2]; ///< 32-bit floating point(s) + u32 _u32[2]; ///< 32-bit unsigned int(s) + s32 _s32[2]; ///< 32-bit signed int(s) + u16 _u16[4]; ///< 16-bit unsigned shorts(s) + u8 _u8[8]; ///< 8-bit unsigned char(s) +}; + +/// Union for fast 128-bit type casting +union t128 { + struct + { + t64 ps0; ///< 64-bit paired single 0 + t64 ps1; ///< 64-bit paired single 1 + }; + __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) +}; + +/// 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 abs(x1_ - x0_); } + inline u32 height() const { return abs(y1_ - y0_); } + + inline bool operator == (const Rect& val) const { + return (x0_ == val.x0_ && y0_ == val.y0_ && x1_ == val.x1_ && y1_ == val.y1_); + } +}; diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp new file mode 100644 index 00000000..270ad9ce --- /dev/null +++ b/src/common/console_listener.cpp @@ -0,0 +1,337 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include // min +#include // System: To be able to add strings with "+" +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include "common.h" +#include "log_manager.h" // Common +#include "console_listener.h" // Common + +ConsoleListener::ConsoleListener() +{ +#ifdef _WIN32 + hConsole = NULL; + bUseColor = true; +#else + bUseColor = isatty(fileno(stdout)); +#endif +} + +ConsoleListener::~ConsoleListener() +{ + Close(); +} + +// 100, 100, "Dolphin Log Console" +// Open console window - width and height is the size of console window +// Name is the window title +void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title) +{ +#ifdef _WIN32 + if (!GetConsoleWindow()) + { + // Open the console window and create the window handle for GetStdHandle() + AllocConsole(); + // Hide + if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE); + // Save the window handle that AllocConsole() created + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + // Set the console window title + SetConsoleTitle(UTF8ToTStr(Title).c_str()); + // Set letter space + LetterSpace(80, 4000); + //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); + } + else + { + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + } +#endif +} + +void ConsoleListener::UpdateHandle() +{ +#ifdef _WIN32 + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +#endif +} + +// Close the console window and close the eventual file handle +void ConsoleListener::Close() +{ +#ifdef _WIN32 + if (hConsole == NULL) + return; + FreeConsole(); + hConsole = NULL; +#else + fflush(NULL); +#endif +} + +bool ConsoleListener::IsOpen() +{ +#ifdef _WIN32 + return (hConsole != NULL); +#else + return true; +#endif +} + +/* + LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are + dependent on each other, that's the reason for the additional checks. +*/ +void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) +{ +#ifdef _WIN32 + BOOL SB, SW; + if (BufferFirst) + { + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + // Change the screen buffer window size + SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + } + else + { + // Change the screen buffer window size + SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + } +#endif +} +void ConsoleListener::LetterSpace(int Width, int Height) +{ +#ifdef _WIN32 + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + + // + int OldBufferWidth = ConInfo.dwSize.X; + int OldBufferHeight = ConInfo.dwSize.Y; + int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); + int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); + // + int NewBufferWidth = Width; + int NewBufferHeight = Height; + int NewScreenWidth = NewBufferWidth - 1; + int NewScreenHeight = OldScreenHeight; + + // Width + BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1)); + // Height + BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); + + // Resize the window too + //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); +#endif +} +#ifdef _WIN32 +COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) +{ + COORD Ret = {0, 0}; + // Full rows + int Step = (int)floor((float)BytesRead / (float)BufferWidth); + Ret.Y += Step; + // Partial row + Ret.X = BytesRead - (BufferWidth * Step); + return Ret; +} +#endif +void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) +{ +#ifdef _WIN32 + // Check size + if (Width < 8 || Height < 12) return; + + bool DBef = true; + bool DAft = true; + std::string SLog = ""; + + const HWND hWnd = GetConsoleWindow(); + const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y; + + // --------------------------------------------------------------------- + // Save the current text + // ------------------------ + DWORD cCharsRead = 0; + COORD coordScreen = { 0, 0 }; + + static const int MAX_BYTES = 1024 * 16; + + std::vector> Str; + std::vector> Attr; + + // ReadConsoleOutputAttribute seems to have a limit at this level + static const int ReadBufferSize = MAX_BYTES - 32; + + DWORD cAttrRead = ReadBufferSize; + DWORD BytesRead = 0; + while (BytesRead < BufferSize) + { + Str.resize(Str.size() + 1); + if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + + Attr.resize(Attr.size() + 1); + if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + // Break on error + if (cAttrRead == 0) break; + BytesRead += cAttrRead; + coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X); + } + // Letter space + int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f); + int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f); + int LBufWidth = LWidth + 1; + int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth); + // Change screen buffer size + LetterSpace(LBufWidth, LBufHeight); + + + ClearScreen(true); + coordScreen.Y = 0; + coordScreen.X = 0; + DWORD cCharsWritten = 0; + + int BytesWritten = 0; + DWORD cAttrWritten = 0; + for (size_t i = 0; i < Attr.size(); i++) + { + if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + BytesWritten += cAttrWritten; + coordScreen = GetCoordinates(BytesWritten, LBufWidth); + } + + const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; + COORD Coo = GetCoordinates(OldCursor, LBufWidth); + SetConsoleCursorPosition(hConsole, Coo); + + if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str()); + + // Resize the window too + if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); +#endif +} + +void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) +{ +#if defined(_WIN32) + /* + const int MAX_BYTES = 1024*10; + char Str[MAX_BYTES]; + va_list ArgPtr; + int Cnt; + va_start(ArgPtr, Text); + Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); + va_end(ArgPtr); + */ + DWORD cCharsWritten; + WORD Color; + + switch (Level) + { + case NOTICE_LEVEL: // light green + Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case ERROR_LEVEL: // light red + Color = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case WARNING_LEVEL: // light yellow + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case INFO_LEVEL: // cyan + Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; + break; + case DEBUG_LEVEL: // gray + Color = FOREGROUND_INTENSITY; + break; + default: // off-white + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + } + if (strlen(Text) > 10) + { + // First 10 chars white + SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); + Text += 10; + } + SetConsoleTextAttribute(hConsole, Color); + WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); +#else + char ColorAttr[16] = ""; + char ResetAttr[16] = ""; + + if (bUseColor) + { + strcpy(ResetAttr, "\033[0m"); + switch (Level) + { + case NOTICE_LEVEL: // light green + strcpy(ColorAttr, "\033[92m"); + break; + case ERROR_LEVEL: // light red + strcpy(ColorAttr, "\033[91m"); + break; + case WARNING_LEVEL: // light yellow + strcpy(ColorAttr, "\033[93m"); + break; + default: + break; + } + } + fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); +#endif +} +// Clear console screen +void ConsoleListener::ClearScreen(bool Cursor) +{ +#if defined(_WIN32) + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleScreenBufferInfo(hConsole, &csbi); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + // Write space to the entire console + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); + // Reset cursor + if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); +#endif +} + + diff --git a/src/common/console_listener.h b/src/common/console_listener.h new file mode 100644 index 00000000..a2936050 --- /dev/null +++ b/src/common/console_listener.h @@ -0,0 +1,41 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _CONSOLELISTENER_H +#define _CONSOLELISTENER_H + +#include "log_manager.h" + +#ifdef _WIN32 +#include +#endif + +class ConsoleListener : public LogListener +{ +public: + ConsoleListener(); + ~ConsoleListener(); + + void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console"); + void UpdateHandle(); + void Close(); + bool IsOpen(); + void LetterSpace(int Width, int Height); + void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst); + void PixelSpace(int Left, int Top, int Width, int Height, bool); +#ifdef _WIN32 + COORD GetCoordinates(int BytesRead, int BufferWidth); +#endif + void Log(LogTypes::LOG_LEVELS, const char *Text); + void ClearScreen(bool Cursor = true); + +private: +#ifdef _WIN32 + HWND GetHwnd(void); + HANDLE hConsole; +#endif + bool bUseColor; +}; + +#endif // _CONSOLELISTENER_H diff --git a/src/common/cpu_detect.h b/src/common/cpu_detect.h new file mode 100644 index 00000000..e93cf333 --- /dev/null +++ b/src/common/cpu_detect.h @@ -0,0 +1,81 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +// Detect the cpu, so we'll know which optimizations to use +#ifndef _CPUDETECT_H_ +#define _CPUDETECT_H_ + +#include + +enum CPUVendor +{ + VENDOR_INTEL = 0, + VENDOR_AMD = 1, + VENDOR_ARM = 2, + VENDOR_OTHER = 3, +}; + +struct CPUInfo +{ + CPUVendor vendor; + + char cpu_string[0x21]; + char brand_string[0x41]; + bool OS64bit; + bool CPU64bit; + bool Mode64bit; + + bool HTT; + int num_cores; + int logical_cpu_count; + + bool bSSE; + bool bSSE2; + bool bSSE3; + bool bSSSE3; + bool bPOPCNT; + bool bSSE4_1; + bool bSSE4_2; + bool bLZCNT; + bool bSSE4A; + bool bAVX; + bool bAES; + bool bLAHFSAHF64; + bool bLongMode; + + // ARM specific CPUInfo + bool bSwp; + bool bHalf; + bool bThumb; + bool bFastMult; + bool bVFP; + bool bEDSP; + bool bThumbEE; + bool bNEON; + bool bVFPv3; + bool bTLS; + bool bVFPv4; + bool bIDIVa; + bool bIDIVt; + bool bArmV7; // enable MOVT, MOVW etc + + // ARMv8 specific + bool bFP; + bool bASIMD; + + // Call Detect() + explicit CPUInfo(); + + // Turn the cpu info into a string we can show + std::string Summarize(); + +private: + // Detects the various cpu features + void Detect(); +}; + +extern CPUInfo cpu_info; + +#endif // _CPUDETECT_H_ diff --git a/src/common/debug_interface.h b/src/common/debug_interface.h new file mode 100644 index 00000000..49cc54a8 --- /dev/null +++ b/src/common/debug_interface.h @@ -0,0 +1,39 @@ +#ifndef _DEBUGINTERFACE_H +#define _DEBUGINTERFACE_H + +#include +#include + +class DebugInterface +{ +protected: + virtual ~DebugInterface() {} + +public: + virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} + virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} + virtual int getInstructionSize(int /*instruction*/) {return 1;} + virtual bool isAlive() {return true;} + virtual bool isBreakpoint(unsigned int /*address*/) {return false;} + virtual void setBreakpoint(unsigned int /*address*/){} + virtual void clearBreakpoint(unsigned int /*address*/){} + virtual void clearAllBreakpoints() {} + virtual void toggleBreakpoint(unsigned int /*address*/){} + virtual bool isMemCheck(unsigned int /*address*/) {return false;} + virtual void toggleMemCheck(unsigned int /*address*/){} + virtual unsigned int readMemory(unsigned int /*address*/){return 0;} + virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} + virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} + virtual unsigned int readInstruction(unsigned int /*address*/){return 0;} + virtual unsigned int getPC() {return 0;} + virtual void setPC(unsigned int /*address*/) {} + virtual void step() {} + virtual void runToBreakpoint() {} + virtual void breakNow() {} + virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} + virtual void showJitResults(unsigned int /*address*/) {}; + virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} + virtual std::string getDescription(unsigned int /*address*/) = 0; +}; + +#endif diff --git a/src/common/emu_window.h b/src/common/emu_window.h new file mode 100644 index 00000000..f4936705 --- /dev/null +++ b/src/common/emu_window.h @@ -0,0 +1,102 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file emu_window.h + * @author Neobrain + * @date 2012-06-01 + * @brief Interface for implementing an emulator window manager + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#ifndef CORE_EMUWINDOW_H_ +#define CORE_EMUWINDOW_H_ + +#include "common.h" + +//namespace input_common +//{ +//class KeyboardInput; +//} + +// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, +// QGLWidget, GLFW, etc...) +class EmuWindow +{ + +public: + /// Data structure to store an emuwindow configuration + struct Config{ + bool fullscreen; + int res_width; + int res_height; + }; + + /// Swap buffers to display the next frame + virtual void SwapBuffers() = 0; + + /// Polls window events + virtual void PollEvents() = 0; + + /// Makes the graphics context current for the caller thread + virtual void MakeCurrent() = 0; + + /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread + virtual void DoneCurrent() = 0; + + /** + * @brief Called from KeyboardInput constructor to notify EmuWindow about its presence + * @param controller_interface Pointer to a running KeyboardInput interface + */ + //void set_controller_interface(input_common::KeyboardInput* controller_interface) { + // controller_interface_ = controller_interface; + //} + //input_common::KeyboardInput* controller_interface() { return controller_interface_; } + + Config config() { return config_; } + void set_config(Config val) { config_ = val; } + + int client_area_width() { return client_area_width_; } + void set_client_area_width(int val) { client_area_width_ = val; } + + int client_area_height() { return client_area_height_; } + void set_client_area_height(int val) { client_area_height_ = val; } + + std::string window_title() { return window_title_; } + void set_window_title(std::string val) { window_title_ = val; } + +protected: + EmuWindow() : client_area_width_(640), client_area_height_(480) { + char window_title[255]; + sprintf(window_title, "citra [%s|%s] - %s", + "null-cpu", + "null-renderer", + __DATE__); + window_title_ = window_title; + } + virtual ~EmuWindow() {} + + std::string window_title_; ///< Current window title, should be used by window impl. + + int client_area_width_; ///< Current client width, should be set by window impl. + int client_area_height_; ///< Current client height, should be set by window impl. + +private: + Config config_; ///< Internal configuration + +}; + +#endif // CORE_EMUWINDOW_H_ diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp new file mode 100644 index 00000000..9f717dba --- /dev/null +++ b/src/common/extended_trace.cpp @@ -0,0 +1,433 @@ +// -------------------------------------------------------------------------------------- +// +// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com +// For companies(Austin,TX): If you would like to get my resume, send an email. +// +// The source is free, but if you want to use it, mention my name and e-mail address +// +// History: +// 1.0 Initial version Zoltan Csizmadia +// 1.1 WhineCube version Masken +// 1.2 Dolphin version Masken +// +// -------------------------------------------------------------------------------------- + +#if defined(WIN32) + +#include +#include +#include "extended_trace.h" +#include "string_util.h" +using namespace std; + +#include +#include + +#define BUFFERSIZE 0x200 +#pragma warning(disable:4996) + +// Unicode safe char* -> TCHAR* conversion +void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) +{ +#if defined(UNICODE)||defined(_UNICODE) + ULONG index = 0; + PCSTR lpAct = lpszIn; + + for( ; ; lpAct++ ) + { + lpszOut[index++] = (TCHAR)(*lpAct); + if ( *lpAct == 0 ) + break; + } +#else + // This is trivial :) + strcpy( lpszOut, lpszIn ); +#endif +} + +// Let's figure out the path for the symbol files +// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath +// Note: There is no size check for lpszSymbolPath! +static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath ) +{ + CHAR lpszPath[BUFFERSIZE]; + + // Creating the default path + // ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + strcpy( lpszSymbolPath, "." ); + + // environment variable _NT_SYMBOL_PATH + if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + } + + // environment variable _NT_ALTERNATE_SYMBOL_PATH + if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + } + + // environment variable SYSTEMROOT + if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + strcat( lpszSymbolPath, ";" ); + + // SYSTEMROOT\System32 + strcat( lpszSymbolPath, lpszPath ); + strcat( lpszSymbolPath, "\\System32" ); + } + + // Add user defined path + if ( lpszIniPath != NULL ) + if ( lpszIniPath[0] != '\0' ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszIniPath ); + } +} + +// Uninitialize the loaded symbol files +BOOL UninitSymInfo() { + return SymCleanup( GetCurrentProcess() ); +} + +// Initializes the symbol files +BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) +{ + CHAR lpszSymbolPath[BUFFERSIZE]; + DWORD symOptions = SymGetOptions(); + + symOptions |= SYMOPT_LOAD_LINES; + symOptions &= ~SYMOPT_UNDNAME; + SymSetOptions( symOptions ); + InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); + + return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE); +} + +// Get the module name from a given address +static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) +{ + BOOL ret = FALSE; + IMAGEHLP_MODULE moduleInfo; + + ::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); + moduleInfo.SizeOfStruct = sizeof(moduleInfo); + + if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) + { + // Got it! + PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule ); + ret = TRUE; + } + else + // Not found :( + _tcscpy( lpszModule, _T("?") ); + + return ret; +} + +// Get function prototype and parameter info from ip address and stack address +static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) +{ + BOOL ret = FALSE; + DWORD dwSymSize = 10000; + TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); + CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; + LPTSTR lpszParamSep = NULL; + LPTSTR lpszParsed = lpszUnDSymbol; + PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize ); + + ::ZeroMemory( pSym, dwSymSize ); + pSym->SizeOfStruct = dwSymSize; + pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL); + + // Set the default to unknown + _tcscpy( lpszSymbol, _T("?") ); + + // Get symbol info for IP +#ifndef _M_X64 + DWORD dwDisp = 0; + if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) +#else + //makes it compile but hell im not sure if this works... + DWORD64 dwDisp = 0; + if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) +#endif + { + // Make the symbol readable for humans + UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, + UNDNAME_COMPLETE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_SPECIAL_SYMS | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_ACCESS_SPECIFIERS ); + + // Symbol information is ANSI string + PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol ); + + // I am just smarter than the symbol file :) + if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("mainCRTStartup()")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()")); + + lpszSymbol[0] = _T('\0'); + + // Let's go through the stack, and modify the function prototype, and insert the actual + // parameter values from the stack + if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL) + { + ULONG index = 0; + for( ; ; index++ ) + { + lpszParamSep = _tcschr( lpszParsed, _T(',') ); + if ( lpszParamSep == NULL ) + break; + + *lpszParamSep = _T('\0'); + + _tcscat( lpszSymbol, lpszParsed ); + _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) ); + + lpszParsed = lpszParamSep + 1; + } + + lpszParamSep = _tcschr( lpszParsed, _T(')') ); + if ( lpszParamSep != NULL ) + { + *lpszParamSep = _T('\0'); + + _tcscat( lpszSymbol, lpszParsed ); + _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) ); + + lpszParsed = lpszParamSep + 1; + } + } + + _tcscat( lpszSymbol, lpszParsed ); + + ret = TRUE; + } + GlobalFree( pSym ); + + return ret; +} + +// Get source file name and line number from IP address +// The output format is: "sourcefile(linenumber)" or +// "modulename!address" or +// "address" +static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ) +{ + BOOL ret = FALSE; + IMAGEHLP_LINE lineInfo; + DWORD dwDisp; + TCHAR lpszFileName[BUFFERSIZE] = _T(""); + TCHAR lpModuleInfo[BUFFERSIZE] = _T(""); + + _tcscpy( lpszSourceInfo, _T("?(?)") ); + + ::ZeroMemory( &lineInfo, sizeof( lineInfo ) ); + lineInfo.SizeOfStruct = sizeof( lineInfo ); + + if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) ) + { + // Got it. Let's use "sourcefile(linenumber)" format + PCSTR2LPTSTR( lineInfo.FileName, lpszFileName ); + TCHAR fname[_MAX_FNAME]; + TCHAR ext[_MAX_EXT]; + _tsplitpath(lpszFileName, NULL, NULL, fname, ext); + _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber ); + ret = TRUE; + } + else + { + // There is no source file information. :( + // Let's use the "modulename!address" format + GetModuleNameFromAddress( address, lpModuleInfo ); + + if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0')) + // There is no modulename information. :(( + // Let's use the "address" format + _stprintf( lpszSourceInfo, _T("0x%08X"), address ); + else + _stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address ); + + ret = FALSE; + } + + return ret; +} + +void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) +{ + TCHAR symInfo[BUFFERSIZE] = _T("?"); + TCHAR srcInfo[BUFFERSIZE] = _T("?"); + + GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); + GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); + etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); +} + +void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) +{ + STACKFRAME callStack; + BOOL bResult; + CONTEXT context; + HANDLE hProcess = GetCurrentProcess(); + + // If it's not this thread, let's suspend it, and resume it at the end + if ( hThread != GetCurrentThread() ) + if ( SuspendThread( hThread ) == -1 ) + { + // whaaat ?! + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &context, sizeof(context) ); + context.ContextFlags = CONTEXT_FULL; + + if ( !GetThreadContext( hThread, &context ) ) + { + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &callStack, sizeof(callStack) ); +#ifndef _M_X64 + callStack.AddrPC.Offset = context.Eip; + callStack.AddrStack.Offset = context.Esp; + callStack.AddrFrame.Offset = context.Ebp; +#else + callStack.AddrPC.Offset = context.Rip; + callStack.AddrStack.Offset = context.Rsp; + callStack.AddrFrame.Offset = context.Rbp; +#endif + callStack.AddrPC.Mode = AddrModeFlat; + callStack.AddrStack.Mode = AddrModeFlat; + callStack.AddrFrame.Mode = AddrModeFlat; + + etfprint(file, "Call stack info: \n"); + etfprint(file, lpszMessage); + + PrintFunctionAndSourceInfo(file, callStack); + + for( ULONG index = 0; ; index++ ) + { + bResult = StackWalk( + IMAGE_FILE_MACHINE_I386, + hProcess, + hThread, + &callStack, + NULL, + NULL, + SymFunctionTableAccess, + SymGetModuleBase, + NULL); + + if ( index == 0 ) + continue; + + if( !bResult || callStack.AddrFrame.Offset == 0 ) + break; + + PrintFunctionAndSourceInfo(file, callStack); + + } + + if ( hThread != GetCurrentThread() ) + ResumeThread( hThread ); +} + +void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) +{ + STACKFRAME callStack; + BOOL bResult; + TCHAR symInfo[BUFFERSIZE] = _T("?"); + TCHAR srcInfo[BUFFERSIZE] = _T("?"); + HANDLE hProcess = GetCurrentProcess(); + + // If it's not this thread, let's suspend it, and resume it at the end + if ( hThread != GetCurrentThread() ) + if ( SuspendThread( hThread ) == -1 ) + { + // whaaat ?! + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &callStack, sizeof(callStack) ); + callStack.AddrPC.Offset = eip; + callStack.AddrStack.Offset = esp; + callStack.AddrFrame.Offset = ebp; + callStack.AddrPC.Mode = AddrModeFlat; + callStack.AddrStack.Mode = AddrModeFlat; + callStack.AddrFrame.Mode = AddrModeFlat; + + etfprint(file, "Call stack info: \n"); + etfprint(file, lpszMessage); + + PrintFunctionAndSourceInfo(file, callStack); + + for( ULONG index = 0; ; index++ ) + { + bResult = StackWalk( + IMAGE_FILE_MACHINE_I386, + hProcess, + hThread, + &callStack, + NULL, + NULL, + SymFunctionTableAccess, + SymGetModuleBase, + NULL); + + if ( index == 0 ) + continue; + + if( !bResult || callStack.AddrFrame.Offset == 0 ) + break; + + PrintFunctionAndSourceInfo(file, callStack); + } + + if ( hThread != GetCurrentThread() ) + ResumeThread( hThread ); +} + +char g_uefbuf[2048]; + +void etfprintf(FILE *file, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int len = vsprintf(g_uefbuf, format, ap); + fwrite(g_uefbuf, 1, len, file); + va_end(ap); +} + +void etfprint(FILE *file, const std::string &text) +{ + size_t len = text.length(); + fwrite(text.data(), 1, len, file); +} + +#endif //WIN32 diff --git a/src/common/extended_trace.h b/src/common/extended_trace.h new file mode 100644 index 00000000..1552e901 --- /dev/null +++ b/src/common/extended_trace.h @@ -0,0 +1,53 @@ +// ----------------------------------------------------------------------------------------- +// +// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com +// For companies(Austin,TX): If you would like to get my resume, send an email. +// +// The source is free, but if you want to use it, mention my name and e-mail address +// +// History: +// 1.0 Initial version Zoltan Csizmadia +// 1.1 WhineCube version Masken +// 1.2 Dolphin version Masken +// +// ---------------------------------------------------------------------------------------- + +#ifndef _EXTENDEDTRACE_H_INCLUDED_ +#define _EXTENDEDTRACE_H_INCLUDED_ + +#if defined(WIN32) + +#include +#include + +#include + +#pragma comment( lib, "imagehlp.lib" ) + +#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath ) +#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() +#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file) +#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp) +// class File; + +BOOL InitSymInfo( PCSTR ); +BOOL UninitSymInfo(); +void StackTrace(HANDLE, char const* msg, FILE *file); +void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp); + +// functions by Masken +void etfprintf(FILE *file, const char *format, ...); +void etfprint(FILE *file, const std::string &text); +#define UEFBUFSIZE 2048 +extern char g_uefbuf[UEFBUFSIZE]; + +#else // not WIN32 + +#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) +#define EXTENDEDTRACEUNINITIALIZE() ((void)0) +#define STACKTRACE(file) ((void)0) +#define STACKTRACE2(file, eip, esp, ebp) ((void)0) + +#endif // WIN32 + +#endif // _EXTENDEDTRACE_H_INCLUDED_ diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h new file mode 100644 index 00000000..57efcd83 --- /dev/null +++ b/src/common/fifo_queue.h @@ -0,0 +1,115 @@ + +#ifndef _FIFO_QUEUE_H_ +#define _FIFO_QUEUE_H_ + +// a simple lockless thread-safe, +// single reader, single writer queue + +#include "atomic.h" + +namespace Common +{ + +template +class FifoQueue +{ +public: + FifoQueue() : m_size(0) + { + m_write_ptr = m_read_ptr = new ElementPtr(); + } + + ~FifoQueue() + { + // this will empty out the whole queue + delete m_read_ptr; + } + + u32 Size() const + { + return m_size; + } + + bool Empty() const + { + //return (m_read_ptr == m_write_ptr); + return (0 == m_size); + } + + T& Front() const + { + return *m_read_ptr->current; + } + + template + void Push(Arg&& t) + { + // create the element, add it to the queue + m_write_ptr->current = new T(std::forward(t)); + // set the next pointer to a new element ptr + // then advance the write pointer + m_write_ptr = m_write_ptr->next = new ElementPtr(); + Common::AtomicIncrement(m_size); + } + + void Pop() + { + Common::AtomicDecrement(m_size); + ElementPtr *const tmpptr = m_read_ptr; + // advance the read pointer + m_read_ptr = m_read_ptr->next; + // set the next element to NULL to stop the recursive deletion + tmpptr->next = NULL; + delete tmpptr; // this also deletes the element + } + + bool Pop(T& t) + { + if (Empty()) + return false; + + t = std::move(Front()); + Pop(); + + return true; + } + + // not thread-safe + void Clear() + { + m_size = 0; + delete m_read_ptr; + m_write_ptr = m_read_ptr = new ElementPtr(); + } + +private: + // stores a pointer to element + // and a pointer to the next ElementPtr + class ElementPtr + { + public: + ElementPtr() : current(NULL), next(NULL) {} + + ~ElementPtr() + { + if (current) + { + delete current; + // recusion ftw + if (next) + delete next; + } + } + + T *volatile current; + ElementPtr *volatile next; + }; + + ElementPtr *volatile m_write_ptr; + ElementPtr *volatile m_read_ptr; + volatile u32 m_size; +}; + +} + +#endif diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp new file mode 100644 index 00000000..59f64010 --- /dev/null +++ b/src/common/file_search.cpp @@ -0,0 +1,106 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "common_paths.h" +#ifndef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include + +#include "file_search.h" + +#include "string_util.h" + + +CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories) +{ + // Reverse the loop order for speed? + for (size_t j = 0; j < _rSearchStrings.size(); j++) + { + for (size_t i = 0; i < _rDirectories.size(); i++) + { + FindFiles(_rSearchStrings[j], _rDirectories[i]); + } + } +} + + +void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) +{ + std::string GCMSearchPath; + BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); +#ifdef _WIN32 + WIN32_FIND_DATA findData; + HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); + + if (FindFirst != INVALID_HANDLE_VALUE) + { + bool bkeepLooping = true; + + while (bkeepLooping) + { + if (findData.cFileName[0] != '.') + { + std::string strFilename; + BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); + m_FileNames.push_back(strFilename); + } + + bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false; + } + } + FindClose(FindFirst); + + +#else + // TODO: super lame/broken + + auto end_match(_searchString); + + // assuming we have a "*.blah"-like pattern + if (!end_match.empty() && end_match[0] == '*') + end_match.erase(0, 1); + + // ugly + if (end_match == ".*") + end_match.clear(); + + DIR* dir = opendir(_strPath.c_str()); + + if (!dir) + return; + + while (auto const dp = readdir(dir)) + { + std::string found(dp->d_name); + + if ((found != ".") && (found != "..") + && (found.size() >= end_match.size()) + && std::equal(end_match.rbegin(), end_match.rend(), found.rbegin())) + { + std::string full_name; + if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR) + full_name = _strPath + found; + else + full_name = _strPath + DIR_SEP + found; + + m_FileNames.push_back(full_name); + } + } + + closedir(dir); +#endif +} + +const CFileSearch::XStringVector& CFileSearch::GetFileNames() const +{ + return m_FileNames; +} diff --git a/src/common/file_search.h b/src/common/file_search.h new file mode 100644 index 00000000..2a9ff801 --- /dev/null +++ b/src/common/file_search.h @@ -0,0 +1,28 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FILESEARCH_H_ +#define _FILESEARCH_H_ + +#include +#include + +class CFileSearch +{ +public: + typedef std::vectorXStringVector; + + CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories); + const XStringVector& GetFileNames() const; + +private: + + void FindFiles(const std::string& _searchString, const std::string& _strPath); + + XStringVector m_FileNames; +}; + +#endif // _FILESEARCH_H_ + diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp new file mode 100644 index 00000000..8b47cb3e --- /dev/null +++ b/src/common/file_util.cpp @@ -0,0 +1,910 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "common_paths.h" +#include "file_util.h" +#include "string_util.h" + +#ifdef _WIN32 +#include +#include // for SHGetFolderPath +#include +#include // for GetSaveFileName +#include +#include // getcwd +#else +#include +#include +#include +#include +#include +#endif + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#include +#include + +#include "string_util.h" + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#endif + +#ifdef BSD4_4 +#define stat64 stat +#define fstat64 fstat +#endif + +// This namespace has various generic functions related to files and paths. +// The code still needs a ton of cleanup. +// REMEMBER: strdup considered harmful! +namespace File +{ + +// Remove any ending forward slashes from directory paths +// Modifies argument. +static void StripTailDirSlashes(std::string &fname) +{ + if (fname.length() > 1) + { + size_t i = fname.length() - 1; + while (fname[i] == DIR_SEP_CHR) + fname[i--] = '\0'; + } + return; +} + +// Returns true if file filename exists +bool Exists(const std::string &filename) +{ + struct stat64 file_info; + + std::string copy(filename); + StripTailDirSlashes(copy); + +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else + int result = stat64(copy.c_str(), &file_info); +#endif + + return (result == 0); +} + +// Returns true if filename is a directory +bool IsDirectory(const std::string &filename) +{ + struct stat64 file_info; + + std::string copy(filename); + StripTailDirSlashes(copy); + +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else + int result = stat64(copy.c_str(), &file_info); +#endif + + if (result < 0) { + WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } + + return S_ISDIR(file_info.st_mode); +} + +// Deletes a given filename, return true on success +// Doesn't supports deleting a directory +bool Delete(const std::string &filename) +{ + INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); + + // Return true because we care about the file no + // being there, not the actual delete. + if (!Exists(filename)) + { + WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); + return true; + } + + // We can't delete a directory + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); + return false; + } + +#ifdef _WIN32 + if (!DeleteFile(UTF8ToTStr(filename).c_str())) + { + WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } +#else + if (unlink(filename.c_str()) == -1) { + WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } +#endif + + return true; +} + +// Returns true if successful, or path already exists. +bool CreateDir(const std::string &path) +{ + INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); +#ifdef _WIN32 + if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) + return true; + DWORD error = GetLastError(); + if (error == ERROR_ALREADY_EXISTS) + { + WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); + return true; + } + ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error); + return false; +#else + if (mkdir(path.c_str(), 0755) == 0) + return true; + + int err = errno; + + if (err == EEXIST) + { + WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); + return true; + } + + ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); + return false; +#endif +} + +// Creates the full path of fullPath returns true on success +bool CreateFullPath(const std::string &fullPath) +{ + int panicCounter = 100; + INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); + + if (File::Exists(fullPath)) + { + INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); + return true; + } + + size_t position = 0; + while (true) + { + // Find next sub path + position = fullPath.find(DIR_SEP_CHR, position); + + // we're done, yay! + if (position == fullPath.npos) + return true; + + // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") + std::string const subPath(fullPath.substr(0, position + 1)); + if (!File::IsDirectory(subPath)) + File::CreateDir(subPath); + + // A safety check + panicCounter--; + if (panicCounter <= 0) + { + ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); + return false; + } + position++; + } +} + + +// Deletes a directory filename, returns true on success +bool DeleteDir(const std::string &filename) +{ + INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); + + // check if a directory + if (!File::IsDirectory(filename)) + { + ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); + return false; + } + +#ifdef _WIN32 + if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) + return true; +#else + if (rmdir(filename.c_str()) == 0) + return true; +#endif + ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); + + return false; +} + +// renames file srcFilename to destFilename, returns true on success +bool Rename(const std::string &srcFilename, const std::string &destFilename) +{ + INFO_LOG(COMMON, "Rename: %s --> %s", + srcFilename.c_str(), destFilename.c_str()); + if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) + return true; + ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; +} + +// copies file srcFilename to destFilename, returns true on success +bool Copy(const std::string &srcFilename, const std::string &destFilename) +{ + INFO_LOG(COMMON, "Copy: %s --> %s", + srcFilename.c_str(), destFilename.c_str()); +#ifdef _WIN32 + if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) + return true; + + ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; +#else + + // buffer size +#define BSIZE 1024 + + char buffer[BSIZE]; + + // Open input file + FILE *input = fopen(srcFilename.c_str(), "rb"); + if (!input) + { + ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; + } + + // open output file + FILE *output = fopen(destFilename.c_str(), "wb"); + if (!output) + { + fclose(input); + ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; + } + + // copy loop + while (!feof(input)) + { + // read input + int rnum = fread(buffer, sizeof(char), BSIZE, input); + if (rnum != BSIZE) + { + if (ferror(input) != 0) + { + ERROR_LOG(COMMON, + "Copy: failed reading from source, %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + goto bail; + } + } + + // write output + int wnum = fwrite(buffer, sizeof(char), rnum, output); + if (wnum != rnum) + { + ERROR_LOG(COMMON, + "Copy: failed writing to output, %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + goto bail; + } + } + // close files + fclose(input); + fclose(output); + return true; +bail: + if (input) + fclose(input); + if (output) + fclose(output); + return false; +#endif +} + +// Returns the size of filename (64bit) +u64 GetSize(const std::string &filename) +{ + if (!Exists(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); + return 0; + } + + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); + return 0; + } + + struct stat64 buf; +#ifdef _WIN32 + if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) +#else + if (stat64(filename.c_str(), &buf) == 0) +#endif + { + DEBUG_LOG(COMMON, "GetSize: %s: %lld", + filename.c_str(), (long long)buf.st_size); + return buf.st_size; + } + + ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", + filename.c_str(), GetLastErrorMsg()); + return 0; +} + +// Overloaded GetSize, accepts file descriptor +u64 GetSize(const int fd) +{ + struct stat64 buf; + if (fstat64(fd, &buf) != 0) { + ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", + fd, GetLastErrorMsg()); + return 0; + } + return buf.st_size; +} + +// Overloaded GetSize, accepts FILE* +u64 GetSize(FILE *f) +{ + // can't use off_t here because it can be 32-bit + u64 pos = ftello(f); + if (fseeko(f, 0, SEEK_END) != 0) { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", + f, GetLastErrorMsg()); + return 0; + } + u64 size = ftello(f); + if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", + f, GetLastErrorMsg()); + return 0; + } + return size; +} + +// creates an empty file filename, returns true on success +bool CreateEmptyFile(const std::string &filename) +{ + INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); + + if (!File::IOFile(filename, "wb")) + { + ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } + + return true; +} + + +// Scans the directory tree gets, starting from _Directory and adds the +// results into parentEntry. Returns the number of files+directories found +u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) +{ + INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); + // How many files + directories we found + u32 foundEntries = 0; +#ifdef _WIN32 + // Find the first file in the directory. + WIN32_FIND_DATA ffd; + + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return foundEntries; + } + // windows loop + do + { + FSTEntry entry; + const std::string virtualName(TStrToUTF8(ffd.cFileName)); +#else + struct dirent dirent, *result = NULL; + + DIR *dirp = opendir(directory.c_str()); + if (!dirp) + return 0; + + // non windows loop + while (!readdir_r(dirp, &dirent, &result) && result) + { + FSTEntry entry; + const std::string virtualName(result->d_name); +#endif + // check for "." and ".." + if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || + ((virtualName[0] == '.') && (virtualName[1] == '.') && + (virtualName[2] == '\0'))) + continue; + entry.virtualName = virtualName; + entry.physicalName = directory; + entry.physicalName += DIR_SEP + entry.virtualName; + + if (IsDirectory(entry.physicalName.c_str())) + { + entry.isDirectory = true; + // is a directory, lets go inside + entry.size = ScanDirectoryTree(entry.physicalName, entry); + foundEntries += (u32)entry.size; + } + else + { // is a file + entry.isDirectory = false; + entry.size = GetSize(entry.physicalName.c_str()); + } + ++foundEntries; + // Push into the tree + parentEntry.children.push_back(entry); +#ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + } + closedir(dirp); +#endif + // Return number of entries found. + return foundEntries; +} + + +// Deletes the given directory and anything under it. Returns true on success. +bool DeleteDirRecursively(const std::string &directory) +{ + INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); +#ifdef _WIN32 + // Find the first file in the directory. + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return false; + } + + // windows loop + do + { + const std::string virtualName(TStrToUTF8(ffd.cFileName)); +#else + struct dirent dirent, *result = NULL; + DIR *dirp = opendir(directory.c_str()); + if (!dirp) + return false; + + // non windows loop + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtualName = result->d_name; +#endif + + // check for "." and ".." + if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || + ((virtualName[0] == '.') && (virtualName[1] == '.') && + (virtualName[2] == '\0'))) + continue; + + std::string newPath = directory + DIR_SEP_CHR + virtualName; + if (IsDirectory(newPath)) + { + if (!DeleteDirRecursively(newPath)) + { + #ifndef _WIN32 + closedir(dirp); + #endif + + return false; + } + } + else + { + if (!File::Delete(newPath)) + { + #ifndef _WIN32 + closedir(dirp); + #endif + + return false; + } + } + +#ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + } + closedir(dirp); +#endif + File::DeleteDir(directory); + + return true; +} + +// Create directory and copy contents (does not overwrite existing files) +void CopyDir(const std::string &source_path, const std::string &dest_path) +{ +#ifndef _WIN32 + if (source_path == dest_path) return; + if (!File::Exists(source_path)) return; + if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); + + struct dirent dirent, *result = NULL; + DIR *dirp = opendir(source_path.c_str()); + if (!dirp) return; + + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtualName(result->d_name); + // check for "." and ".." + if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || + ((virtualName[0] == '.') && (virtualName[1] == '.') && + (virtualName[2] == '\0'))) + continue; + + std::string source, dest; + source = source_path + virtualName; + dest = dest_path + virtualName; + if (IsDirectory(source)) + { + source += '/'; + dest += '/'; + if (!File::Exists(dest)) File::CreateFullPath(dest); + CopyDir(source, dest); + } + else if (!File::Exists(dest)) File::Copy(source, dest); + } + closedir(dirp); +#endif +} + +// Returns the current directory +std::string GetCurrentDir() +{ + char *dir; + // Get the current working directory (getcwd uses malloc) + if (!(dir = __getcwd(NULL, 0))) { + + ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", + GetLastErrorMsg()); + return NULL; + } + std::string strDir = dir; + free(dir); + return strDir; +} + +// Sets the current directory to the given directory +bool SetCurrentDir(const std::string &directory) +{ + return __chdir(directory.c_str()) == 0; +} + +#if defined(__APPLE__) +std::string GetBundleDirectory() +{ + CFURLRef BundleRef; + char AppBundlePath[MAXPATHLEN]; + // Get the main bundle for the app + BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); + CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); + CFRelease(BundleRef); + CFRelease(BundlePath); + + return AppBundlePath; +} +#endif + +#ifdef _WIN32 +std::string& GetExeDirectory() +{ + static std::string DolphinPath; + if (DolphinPath.empty()) + { + TCHAR Dolphin_exe_Path[2048]; + GetModuleFileName(NULL, Dolphin_exe_Path, 2048); + DolphinPath = TStrToUTF8(Dolphin_exe_Path); + DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); + } + return DolphinPath; +} +#endif + +std::string GetSysDirectory() +{ + std::string sysDir; + +#if defined (__APPLE__) + sysDir = GetBundleDirectory(); + sysDir += DIR_SEP; + sysDir += SYSDATA_DIR; +#else + sysDir = SYSDATA_DIR; +#endif + sysDir += DIR_SEP; + + INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); + return sysDir; +} + +// Returns a string with a Dolphin data dir or file in the user's home +// directory. To be used in "multi-user" mode (that is, installed). +const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) +{ + static std::string paths[NUM_PATH_INDICES]; + + // Set up all paths and files on the first run + if (paths[D_USER_IDX].empty()) + { +#ifdef _WIN32 + paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; +#else + if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; + else + paths[D_USER_IDX] = std::string(getenv("HOME") ? + getenv("HOME") : getenv("PWD") ? + getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; +#endif + + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; + paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + } + + if (!newPath.empty()) + { + if (!File::IsDirectory(newPath)) + { + WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); + return paths[DirIDX]; + } + else + { + paths[DirIDX] = newPath; + } + + switch (DirIDX) + { + case D_ROOT_IDX: + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; + paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; + break; + + case D_USER_IDX: + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; + paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + break; + + case D_CONFIG_IDX: + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + break; + + case D_DUMP_IDX: + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + break; + + case D_LOGS_IDX: + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + } + } + + return paths[DirIDX]; +} + +//std::string GetThemeDir(const std::string& theme_name) +//{ +// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; +// +//#if !defined(_WIN32) +// // If theme does not exist in user's dir load from shared directory +// if (!File::Exists(dir)) +// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; +//#endif +// +// return dir; +//} + +bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) +{ + return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); +} + +bool ReadFileToString(bool text_file, const char *filename, std::string &str) +{ + File::IOFile file(filename, text_file ? "r" : "rb"); + auto const f = file.GetHandle(); + + if (!f) + return false; + + str.resize(static_cast(GetSize(f))); + return file.ReadArray(&str[0], str.size()); +} + +IOFile::IOFile() + : m_file(NULL), m_good(true) +{} + +IOFile::IOFile(std::FILE* file) + : m_file(file), m_good(true) +{} + +IOFile::IOFile(const std::string& filename, const char openmode[]) + : m_file(NULL), m_good(true) +{ + Open(filename, openmode); +} + +IOFile::~IOFile() +{ + Close(); +} + +IOFile::IOFile(IOFile&& other) + : m_file(NULL), m_good(true) +{ + Swap(other); +} + +IOFile& IOFile::operator=(IOFile&& other) +{ + Swap(other); + return *this; +} + +void IOFile::Swap(IOFile& other) +{ + std::swap(m_file, other.m_file); + std::swap(m_good, other.m_good); +} + +bool IOFile::Open(const std::string& filename, const char openmode[]) +{ + Close(); +#ifdef _WIN32 + _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); +#else + m_file = fopen(filename.c_str(), openmode); +#endif + + m_good = IsOpen(); + return m_good; +} + +bool IOFile::Close() +{ + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; + + m_file = NULL; + return m_good; +} + +std::FILE* IOFile::ReleaseHandle() +{ + std::FILE* const ret = m_file; + m_file = NULL; + return ret; +} + +void IOFile::SetHandle(std::FILE* file) +{ + Close(); + Clear(); + m_file = file; +} + +u64 IOFile::GetSize() +{ + if (IsOpen()) + return File::GetSize(m_file); + else + return 0; +} + +bool IOFile::Seek(s64 off, int origin) +{ + if (!IsOpen() || 0 != fseeko(m_file, off, origin)) + m_good = false; + + return m_good; +} + +u64 IOFile::Tell() +{ + if (IsOpen()) + return ftello(m_file); + else + return -1; +} + +bool IOFile::Flush() +{ + if (!IsOpen() || 0 != std::fflush(m_file)) + m_good = false; + + return m_good; +} + +bool IOFile::Resize(u64 size) +{ + if (!IsOpen() || 0 != +#ifdef _WIN32 + // ector: _chsize sucks, not 64-bit safe + // F|RES: changed to _chsize_s. i think it is 64-bit safe + _chsize_s(_fileno(m_file), size) +#else + // TODO: handle 64bit and growing + ftruncate(fileno(m_file), size) +#endif + ) + m_good = false; + + return m_good; +} + +} // namespace diff --git a/src/common/file_util.h b/src/common/file_util.h new file mode 100644 index 00000000..f4ef949d --- /dev/null +++ b/src/common/file_util.h @@ -0,0 +1,224 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FILEUTIL_H_ +#define _FILEUTIL_H_ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "string_util.h" + +// User directory indices for GetUserPath +enum { + D_USER_IDX, + D_ROOT_IDX, + D_CONFIG_IDX, + D_GAMECONFIG_IDX, + D_MAPS_IDX, + D_CACHE_IDX, + D_SHADERCACHE_IDX, + D_SHADERS_IDX, + D_STATESAVES_IDX, + D_SCREENSHOTS_IDX, + D_HIRESTEXTURES_IDX, + D_DUMP_IDX, + D_DUMPFRAMES_IDX, + D_DUMPAUDIO_IDX, + D_DUMPTEXTURES_IDX, + D_DUMPDSP_IDX, + D_LOGS_IDX, + D_SYSCONF_IDX, + F_EMUCONFIG_IDX, + F_DEBUGGERCONFIG_IDX, + F_LOGGERCONFIG_IDX, + F_MAINLOG_IDX, + F_RAMDUMP_IDX, + F_ARAMDUMP_IDX, + F_SYSCONF_IDX, + NUM_PATH_INDICES +}; + +namespace File +{ + +// FileSystem tree node/ +struct FSTEntry +{ + bool isDirectory; + u64 size; // file length or number of entries from children + std::string physicalName; // name on disk + std::string virtualName; // name in FST names table + std::vector children; +}; + +// Returns true if file filename exists +bool Exists(const std::string &filename); + +// Returns true if filename is a directory +bool IsDirectory(const std::string &filename); + +// Returns the size of filename (64bit) +u64 GetSize(const std::string &filename); + +// Overloaded GetSize, accepts file descriptor +u64 GetSize(const int fd); + +// Overloaded GetSize, accepts FILE* +u64 GetSize(FILE *f); + +// Returns true if successful, or path already exists. +bool CreateDir(const std::string &filename); + +// Creates the full path of fullPath returns true on success +bool CreateFullPath(const std::string &fullPath); + +// Deletes a given filename, return true on success +// Doesn't supports deleting a directory +bool Delete(const std::string &filename); + +// Deletes a directory filename, returns true on success +bool DeleteDir(const std::string &filename); + +// renames file srcFilename to destFilename, returns true on success +bool Rename(const std::string &srcFilename, const std::string &destFilename); + +// copies file srcFilename to destFilename, returns true on success +bool Copy(const std::string &srcFilename, const std::string &destFilename); + +// creates an empty file filename, returns true on success +bool CreateEmptyFile(const std::string &filename); + +// Scans the directory tree gets, starting from _Directory and adds the +// results into parentEntry. Returns the number of files+directories found +u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry); + +// deletes the given directory and anything under it. Returns true on success. +bool DeleteDirRecursively(const std::string &directory); + +// Returns the current directory +std::string GetCurrentDir(); + +// Create directory and copy contents (does not overwrite existing files) +void CopyDir(const std::string &source_path, const std::string &dest_path); + +// Set the current directory to given directory +bool SetCurrentDir(const std::string &directory); + +// Returns a pointer to a string with a Dolphin data dir in the user's home +// directory. To be used in "multi-user" mode (that is, installed). +const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); + +// probably doesn't belong here +//std::string GetThemeDir(const std::string& theme_name); + +// Returns the path to where the sys file are +std::string GetSysDirectory(); + +#ifdef __APPLE__ +std::string GetBundleDirectory(); +#endif + +#ifdef _WIN32 +std::string &GetExeDirectory(); +#endif + +bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); +bool ReadFileToString(bool text_file, const char *filename, std::string &str); + +// simple wrapper for cstdlib file functions to +// hopefully will make error checking easier +// and make forgetting an fclose() harder +class IOFile : public NonCopyable +{ +public: + IOFile(); + IOFile(std::FILE* file); + IOFile(const std::string& filename, const char openmode[]); + + ~IOFile(); + + IOFile(IOFile&& other); + IOFile& operator=(IOFile&& other); + + void Swap(IOFile& other); + + bool Open(const std::string& filename, const char openmode[]); + bool Close(); + + template + bool ReadArray(T* data, size_t length) + { + if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) + m_good = false; + + return m_good; + } + + template + bool WriteArray(const T* data, size_t length) + { + if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + m_good = false; + + return m_good; + } + + bool ReadBytes(void* data, size_t length) + { + return ReadArray(reinterpret_cast(data), length); + } + + bool WriteBytes(const void* data, size_t length) + { + return WriteArray(reinterpret_cast(data), length); + } + + bool IsOpen() { return NULL != m_file; } + + // m_good is set to false when a read, write or other function fails + bool IsGood() { return m_good; } + operator void*() { return m_good ? m_file : NULL; } + + std::FILE* ReleaseHandle(); + + std::FILE* GetHandle() { return m_file; } + + void SetHandle(std::FILE* file); + + bool Seek(s64 off, int origin); + u64 Tell(); + u64 GetSize(); + bool Resize(u64 size); + bool Flush(); + + // clear error state + void Clear() { m_good = true; std::clearerr(m_file); } + + std::FILE* m_file; + bool m_good; +private: + IOFile(IOFile&); + IOFile& operator=(IOFile& other); +}; + +} // namespace + +// To deal with Windows being dumb at unicode: +template +void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) +{ +#ifdef _WIN32 + fstream.open(UTF8ToTStr(filename).c_str(), openmode); +#else + fstream.open(filename.c_str(), openmode); +#endif +} + +#endif diff --git a/src/common/fixed_size_queue.h b/src/common/fixed_size_queue.h new file mode 100644 index 00000000..1f507f4a --- /dev/null +++ b/src/common/fixed_size_queue.h @@ -0,0 +1,75 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FIXED_SIZE_QUEUE_H_ +#define _FIXED_SIZE_QUEUE_H_ + +// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the +// real STL classes. + +// Not fully featured, no safety checking yet. Add features as needed. + +// TODO: "inline" storage? + +template +class fixed_size_queue.h +{ + T *storage; + int head; + int tail; + int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. + + // Make copy constructor private for now. + fixed_size_queue.h(fixed_size_queue.h &other) { } + +public: + fixed_size_queue.h() + { + storage = new T[N]; + clear(); + } + + ~fixed_size_queue.h() + { + delete [] storage; + } + + void clear() { + head = 0; + tail = 0; + count = 0; + } + + void push(T t) { + storage[tail] = t; + tail++; + if (tail == N) + tail = 0; + count++; + } + + void pop() { + head++; + if (head == N) + head = 0; + count--; + } + + T pop_front() { + const T &temp = storage[head]; + pop(); + return temp; + } + + T &front() { return storage[head]; } + const T &front() const { return storage[head]; } + + size_t size() const { + return count; + } +}; + +#endif // _FIXED_SIZE_QUEUE_H_ + diff --git a/src/common/hash.cpp b/src/common/hash.cpp new file mode 100644 index 00000000..5303f07b --- /dev/null +++ b/src/common/hash.cpp @@ -0,0 +1,520 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "hash.h" +#if _M_SSE >= 0x402 +#include "cpu_detect.h" +#include +#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 = 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 = 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 = 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 = 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 = 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 = 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 new file mode 100644 index 00000000..addfa4b5 --- /dev/null +++ b/src/common/hash.h @@ -0,0 +1,20 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _HASH_H_ +#define _HASH_H_ + +#include "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); +#endif // _HASH_H_ diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h new file mode 100644 index 00000000..da5d6b9b --- /dev/null +++ b/src/common/linear_disk_cache.h @@ -0,0 +1,191 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _LINEAR_DISKCACHE +#define _LINEAR_DISKCACHE + +#include "common.h" +#include + +// defined in Version.cpp +extern const char *scm_rev_git_str; + +// On disk format: +//header{ +// u32 'DCAC'; +// u32 version; // svn_rev +// u16 sizeof(key_type); +// u16 sizeof(value_type); +//} + +//key_value_pair{ +// u32 value_size; +// key_type key; +// value_type[value_size] value; +//} + +template +class LinearDiskCacheReader +{ +public: + virtual void Read(const K &key, const V *value, u32 value_size) = 0; +}; + +// Dead simple unsorted key-value store with append functionality. +// No random read functionality, all reading is done in OpenAndRead. +// Keys and values can contain any characters, including \0. +// +// Suitable for caching generated shader bytecode between executions. +// Not tuned for extreme performance but should be reasonably fast. +// Does not support keys or values larger than 2GB, which should be reasonable. +// Keys must have non-zero length; values can have zero length. + +// K and V are some POD type +// K : the key type +// V : value array type +template +class LinearDiskCache +{ +public: + // return number of read entries + u32 OpenAndRead(const char *filename, LinearDiskCacheReader &reader) + { + using std::ios_base; + + // close any currently opened file + Close(); + m_num_entries = 0; + + // try opening for reading/writing + OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); + + m_file.seekg(0, std::ios::end); + std::fstream::pos_type end_pos = m_file.tellg(); + m_file.seekg(0, std::ios::beg); + std::fstream::pos_type start_pos = m_file.tellg(); + std::streamoff file_size = end_pos - start_pos; + + if (m_file.is_open() && ValidateHeader()) + { + // good header, read some key/value pairs + K key; + + V *value = NULL; + u32 value_size; + u32 entry_number; + + std::fstream::pos_type last_pos = m_file.tellg(); + + while (Read(&value_size)) + { + std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; + if (next_extent > file_size) + break; + + delete[] value; + value = new V[value_size]; + + // read key/value and pass to reader + if (Read(&key) && + Read(value, value_size) && + Read(&entry_number) && + entry_number == m_num_entries+1) + { + reader.Read(key, value, value_size); + } + else + { + break; + } + + m_num_entries++; + last_pos = m_file.tellg(); + } + m_file.seekp(last_pos); + m_file.clear(); + + delete[] value; + return m_num_entries; + } + + // failed to open file for reading or bad header + // close and recreate file + Close(); + m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); + WriteHeader(); + return 0; + } + + void Sync() + { + m_file.flush(); + } + + void Close() + { + if (m_file.is_open()) + m_file.close(); + // clear any error flags + m_file.clear(); + } + + // Appends a key-value pair to the store. + void Append(const K &key, const V *value, u32 value_size) + { + // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) + Write(&value_size); + Write(&key); + Write(value, value_size); + m_num_entries++; + Write(&m_num_entries); + } + +private: + void WriteHeader() + { + Write(&m_header); + } + + bool ValidateHeader() + { + char file_header[sizeof(Header)]; + + return (Read(file_header, sizeof(Header)) + && !memcmp((const char*)&m_header, file_header, sizeof(Header))); + } + + template + bool Write(const D *data, u32 count = 1) + { + return m_file.write((const char*)data, count * sizeof(D)).good(); + } + + template + bool Read(const D *data, u32 count = 1) + { + return m_file.read((char*)data, count * sizeof(D)).good(); + } + + struct Header + { + Header() + : id(*(u32*)"DCAC") + , key_t_size(sizeof(K)) + , value_t_size(sizeof(V)) + { + memcpy(ver, scm_rev_git_str, 40); + } + + const u32 id; + const u16 key_t_size, value_t_size; + char ver[40]; + + } m_header; + + std::fstream m_file; + u32 m_num_entries; +}; + +#endif // _LINEAR_DISKCACHE diff --git a/src/common/log.h b/src/common/log.h new file mode 100644 index 00000000..432a307f --- /dev/null +++ b/src/common/log.h @@ -0,0 +1,155 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _LOG_H_ +#define _LOG_H_ + +#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. +#define ERROR_LEVEL 2 // Critical errors +#define WARNING_LEVEL 3 // Something is suspicious. +#define INFO_LEVEL 4 // General information. +#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. + +namespace LogTypes +{ + +enum LOG_TYPE { + ACTIONREPLAY, + AUDIO, + AUDIO_INTERFACE, + BOOT, + COMMANDPROCESSOR, + COMMON, + CONSOLE, + DISCIO, + FILEMON, + DSPHLE, + DSPLLE, + DSP_MAIL, + DSPINTERFACE, + DVDINTERFACE, + DYNA_REC, + EXPANSIONINTERFACE, + GDB_STUB, + ARM11, + GPFIFO, + OSHLE, + MASTER_LOG, + MEMMAP, + MEMCARD_MANAGER, + OSREPORT, + PAD, + PROCESSORINTERFACE, + PIXELENGINE, + SERIALINTERFACE, + SP1, + STREAMINGINTERFACE, + VIDEO, + VIDEOINTERFACE, + LOADER, + FILESYS, + WII_IPC_DVD, + WII_IPC_ES, + WII_IPC_FILEIO, + WII_IPC_HID, + WII_IPC_HLE, + WII_IPC_NET, + WII_IPC_WC24, + WII_IPC_SSL, + RENDER, + LCD, + HW, + TIME, + NETPLAY, + + NUMBER_OF_LOGS // Must be last +}; + +// FIXME: should this be removed? +enum LOG_LEVELS { + LNOTICE = NOTICE_LEVEL, + LERROR = ERROR_LEVEL, + LWARNING = WARNING_LEVEL, + LINFO = INFO_LEVEL, + LDEBUG = DEBUG_LEVEL, +}; + +#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS +#define LOGTYPES_TYPE LogTypes::LOG_TYPE + +} // namespace + +void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, + const char *file, int line, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 5, 6))) +#endif + ; + +#if defined LOGGING || defined _DEBUG || defined DEBUGFAST +#define MAX_LOGLEVEL DEBUG_LEVEL +#else +#ifndef MAX_LOGLEVEL +#define MAX_LOGLEVEL WARNING_LEVEL +#endif // loglevel +#endif // logging + +#ifdef GEKKO +#define GENERIC_LOG(t, v, ...) +#else +// Let the compiler optimize this out +#define GENERIC_LOG(t, v, ...) { \ + if (v <= MAX_LOGLEVEL) \ + GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ + } +#endif + +#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) +#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) +#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) +#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0) +#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0) + +#if MAX_LOGLEVEL >= DEBUG_LEVEL +#define _dbg_assert_(_t_, _a_) \ + if (!(_a_)) {\ + ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \ + __LINE__, __FILE__, __TIME__); \ + if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \ + } +#define _dbg_assert_msg_(_t_, _a_, ...)\ + if (!(_a_)) {\ + ERROR_LOG(_t_, __VA_ARGS__); \ + if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ + } +#define _dbg_update_() Host_UpdateLogDisplay(); + +#else // not debug +#define _dbg_update_() ; + +#ifndef _dbg_assert_ +#define _dbg_assert_(_t_, _a_) {} +#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} +#endif // dbg_assert +#endif // MAX_LOGLEVEL DEBUG + +#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_) + +#ifndef GEKKO +#ifdef _WIN32 +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) {\ + if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ + } +#else // not win32 +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) {\ + if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ + } +#endif // WIN32 +#else // GEKKO +#define _assert_msg_(_t_, _a_, _fmt_, ...) +#endif + +#endif // _LOG_H_ diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp new file mode 100644 index 00000000..b5b03484 --- /dev/null +++ b/src/common/log_manager.cpp @@ -0,0 +1,200 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#ifdef ANDROID +#include "Host.h" +#endif +#include "log_manager.h" +#include "console_listener.h" +#include "timer.h" +#include "thread.h" +#include "file_util.h" + +void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (LogManager::GetInstance()) + LogManager::GetInstance()->Log(level, type, + file, line, fmt, args); + va_end(args); +} + +LogManager *LogManager::m_logManager = NULL; + +LogManager::LogManager() +{ + // create log files + m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); + m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); + m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); + m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); + m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); + m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); + m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); + m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); + m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt"); + m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt"); + m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); + m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); + m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); + m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); + m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); + m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); + m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); + m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); + m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); + m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); + m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11"); + m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); + m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); + m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); + m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); + m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); + m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); + m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT"); + m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); + m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); + m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing"); + m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader"); + m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); + m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); + m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); + m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); + m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); + m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); + m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); + m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); + m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); + m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); + m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); + m_Log[LogTypes::HW] = new LogContainer("HARDWARE", "HARDWARE"); + m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); + m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); + m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + + m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); + m_consoleLog = new ConsoleListener(); + m_debuggerLog = new DebuggerLogListener(); + + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_Log[i]->SetEnable(true); + m_Log[i]->AddListener(m_fileLog); + m_Log[i]->AddListener(m_consoleLog); +#ifdef _MSC_VER + if (IsDebuggerPresent()) + m_Log[i]->AddListener(m_debuggerLog); +#endif + } +} + +LogManager::~LogManager() +{ + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog); + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog); + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog); + } + + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + delete m_Log[i]; + + delete m_fileLog; + delete m_consoleLog; + delete m_debuggerLog; +} + +void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char *format, va_list args) +{ + char temp[MAX_MSGLEN]; + char msg[MAX_MSGLEN * 2]; + LogContainer *log = m_Log[type]; + + if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) + return; + + CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); + + static const char level_to_char[7] = "-NEWID"; + sprintf(msg, "%s %s:%u %c[%s]: %s\n", + Common::Timer::GetTimeFormatted().c_str(), + file, line, level_to_char[(int)level], + log->GetShortName(), temp); +#ifdef ANDROID + Host_SysMessage(msg); +#endif + printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this + log->Trigger(level, msg); +} + +void LogManager::Init() +{ + m_logManager = new LogManager(); +} + +void LogManager::Shutdown() +{ + delete m_logManager; + m_logManager = NULL; +} + +LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable) + : m_enable(enable) +{ + strncpy(m_fullName, fullName, 128); + strncpy(m_shortName, shortName, 32); + m_level = LogTypes::LWARNING; +} + +// LogContainer +void LogContainer::AddListener(LogListener *listener) +{ + std::lock_guard lk(m_listeners_lock); + m_listeners.insert(listener); +} + +void LogContainer::RemoveListener(LogListener *listener) +{ + std::lock_guard lk(m_listeners_lock); + m_listeners.erase(listener); +} + +void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) +{ + std::lock_guard lk(m_listeners_lock); + + std::set::const_iterator i; + for (i = m_listeners.begin(); i != m_listeners.end(); ++i) + { + (*i)->Log(level, msg); + } +} + +FileLogListener::FileLogListener(const char *filename) +{ + OpenFStream(m_logfile, filename, std::ios::app); + SetEnable(true); +} + +void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) +{ + if (!IsEnabled() || !IsValid()) + return; + + std::lock_guard lk(m_log_lock); + m_logfile << msg << std::flush; +} + +void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) +{ +#if _MSC_VER + ::OutputDebugStringA(msg); +#endif +} diff --git a/src/common/log_manager.h b/src/common/log_manager.h new file mode 100644 index 00000000..579198ff --- /dev/null +++ b/src/common/log_manager.h @@ -0,0 +1,169 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _LOGMANAGER_H_ +#define _LOGMANAGER_H_ + +#include "log.h" +#include "string_util.h" +#include "thread.h" +#include "file_util.h" + +#include +#include + +#define MAX_MESSAGES 8000 +#define MAX_MSGLEN 1024 + + +// pure virtual interface +class LogListener +{ +public: + virtual ~LogListener() {} + + virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0; +}; + +class FileLogListener : public LogListener +{ +public: + FileLogListener(const char *filename); + + void Log(LogTypes::LOG_LEVELS, const char *msg); + + bool IsValid() { return !m_logfile.fail(); } + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + + const char* GetName() const { return "file"; } + +private: + std::mutex m_log_lock; + std::ofstream m_logfile; + bool m_enable; +}; + +class DebuggerLogListener : public LogListener +{ +public: + void Log(LogTypes::LOG_LEVELS, const char *msg); +}; + +class LogContainer +{ +public: + LogContainer(const char* shortName, const char* fullName, bool enable = false); + + const char* GetShortName() const { return m_shortName; } + const char* GetFullName() const { return m_fullName; } + + void AddListener(LogListener* listener); + void RemoveListener(LogListener* listener); + + void Trigger(LogTypes::LOG_LEVELS, const char *msg); + + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + + LogTypes::LOG_LEVELS GetLevel() const { return m_level; } + + void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } + + bool HasListeners() const { return !m_listeners.empty(); } + +private: + char m_fullName[128]; + char m_shortName[32]; + bool m_enable; + LogTypes::LOG_LEVELS m_level; + std::mutex m_listeners_lock; + std::set m_listeners; +}; + +class ConsoleListener; + +class LogManager : NonCopyable +{ +private: + LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; + FileLogListener *m_fileLog; + ConsoleListener *m_consoleLog; + DebuggerLogListener *m_debuggerLog; + static LogManager *m_logManager; // Singleton. Ugh. + + LogManager(); + ~LogManager(); +public: + + static u32 GetMaxLevel() { return MAX_LOGLEVEL; } + + void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char *fmt, va_list args); + + void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) + { + m_Log[type]->SetLevel(level); + } + + void SetEnable(LogTypes::LOG_TYPE type, bool enable) + { + m_Log[type]->SetEnable(enable); + } + + bool IsEnabled(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->IsEnabled(); + } + + const char* GetShortName(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->GetShortName(); + } + + const char* GetFullName(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->GetFullName(); + } + + void AddListener(LogTypes::LOG_TYPE type, LogListener *listener) + { + m_Log[type]->AddListener(listener); + } + + void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener) + { + m_Log[type]->RemoveListener(listener); + } + + FileLogListener *GetFileListener() const + { + return m_fileLog; + } + + ConsoleListener *GetConsoleListener() const + { + return m_consoleLog; + } + + DebuggerLogListener *GetDebuggerListener() const + { + return m_debuggerLog; + } + + static LogManager* GetInstance() + { + return m_logManager; + } + + static void SetInstance(LogManager *logManager) + { + m_logManager = logManager; + } + + static void Init(); + static void Shutdown(); +}; + +#endif // _LOGMANAGER_H_ diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp new file mode 100644 index 00000000..da90f8d7 --- /dev/null +++ b/src/common/math_util.cpp @@ -0,0 +1,212 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "math_util.h" + +#include +#include + +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& 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 new file mode 100644 index 00000000..4410c5e0 --- /dev/null +++ b/src/common/math_util.h @@ -0,0 +1,200 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _MATH_UTIL_H_ +#define _MATH_UTIL_H_ + +#include "common.h" + +#include + +namespace MathUtil +{ + +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 +struct Rectangle +{ + T left; + T top; + T right; + T bottom; + + 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; } + + T GetWidth() const { return abs(right - left); } + T GetHeight() const { return abs(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&); + +#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]; +}; + +#endif // _MATH_UTIL_H_ diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp new file mode 100644 index 00000000..1a6fcf44 --- /dev/null +++ b/src/common/mem_arena.cpp @@ -0,0 +1,477 @@ +// 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 + +#include "memory_util.h" +#include "mem_arena.h" + +#ifdef _WIN32 +//#include "CommonWindows.h" +#else +#include +#include +#include +#include +#include +#ifdef ANDROID +#include +#include +#endif +#endif + +#ifdef IOS +void* globalbase = NULL; +#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: + ERROR_LOG(MEMMAP, "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 + + + +#ifndef _WIN32 +// do not make this "static" +#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) +std::string ram_temp_file = "/home/user/gc_mem.tmp"; +#else +std::string ram_temp_file = "/tmp/gc_mem.tmp"; +#endif +#elif !defined(_XBOX) +SYSTEM_INFO sysInfo; +#endif + + +// Windows mappings need to be on 64K boundaries, due to Alpha legacy. +#ifdef _WIN32 +size_t roundup(size_t x) { +#ifndef _XBOX + int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; +#else + int gran = 0x10000; // 64k in 360 +#endif + return (x + gran - 1) & ~(gran - 1); +} +#else +size_t roundup(size_t x) { + return x; +} +#endif + + +void MemArena::GrabLowMemSpace(size_t size) +{ +#ifdef _WIN32 +#ifndef _XBOX + hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); + GetSystemInfo(&sysInfo); +#endif +#elif defined(ANDROID) + // Use ashmem so we don't have to allocate a file on disk! + fd = ashmem_create_region("PPSSPP_RAM", size); + // Note that it appears that ashmem is pinned by default, so no need to pin. + if (fd < 0) + { + ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); + return; + } +#else + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); + if (fd < 0) + { + ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno)); + return; + } + // delete immediately, we keep the fd so it still lives + unlink(ram_temp_file.c_str()); + if (ftruncate(fd, size) != 0) + { + ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size); + } + return; +#endif +} + + +void MemArena::ReleaseSpace() +{ +#ifdef _WIN32 + CloseHandle(hMemoryMapping); + hMemoryMapping = 0; +#elif defined(__SYMBIAN32__) + memmap->Close(); + delete memmap; +#else + close(fd); +#endif +} + + +void *MemArena::CreateView(s64 offset, size_t size, void *base) +{ +#ifdef _WIN32 +#ifdef _XBOX + size = roundup(size); + // use 64kb pages + void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + return ptr; +#else + size = roundup(size); + void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); + return ptr; +#endif +#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 BLACKBERRY + MAP_NOSYNCFILE | +#elif defined(__FreeBSD__) + MAP_NOSYNC | +#endif + ((base == 0) ? 0 : MAP_FIXED), fd, offset); + + if (retval == MAP_FAILED) + { + NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd); + return 0; + } + return retval; +#endif +} + + +void MemArena::ReleaseView(void* view, size_t size) +{ +#ifdef _WIN32 +#ifndef _XBOX + UnmapViewOfFile(view); +#endif +#elif defined(__SYMBIAN32__) + memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); +#else + munmap(view, size); +#endif +} + +#ifndef __SYMBIAN32__ +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(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 +#ifdef IOS + void* base = NULL; + if (globalbase == NULL){ + base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0); + if (base == MAP_FAILED) { + PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno)); + return 0; + } + munmap(base, 0x08000000); + globalbase = base; + } + else{ base = globalbase; } +#else + void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0); + if (base == MAP_FAILED) { + PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); + return 0; + } + munmap(base, 0x10000000); +#endif + return static_cast(base); +#endif +#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; + +#if defined(_XBOX) + void *ptr; +#endif + + // 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 { +#ifdef __SYMBIAN32__ + *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); + arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + } + *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); +#elif defined(_XBOX) + *(view.out_ptr_low) = (u8*)(base + view.virtual_address); + //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); + } + *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); +#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 + +#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 = NULL; + } + 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 = NULL; + } + } + 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 ... +#ifndef __SYMBIAN32__ + arena->GrabLowMemSpace(total_mem); +#endif + + // 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)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } +#elif defined(_XBOX) + // Reserve 256MB + u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + 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 = NULL; + + 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)) + { + INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); + base_attempts = 0; + break; + } + } +#elif defined(__SYMBIAN32__) + arena->memmap = new RChunk(); + arena->memmap->CreateDisconnectedLocal(0, 0, 0x10000000); + if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } + u8* base = arena->memmap->Base(); +#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)) + { + ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } +#endif + if (base_attempts) + PanicAlert("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 = NULL; + if (views[i].out_ptr_low) + *views[i].out_ptr_low = NULL; + } +} diff --git a/src/common/mem_arena.h b/src/common/mem_arena.h new file mode 100644 index 00000000..8bdf9f18 --- /dev/null +++ b/src/common/mem_arena.h @@ -0,0 +1,81 @@ +// 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/ + +#ifndef _MEMARENA_H_ +#define _MEMARENA_H_ + +#ifdef _WIN32 +#include +#endif + +#ifdef __SYMBIAN32__ +#include +#endif + +#include "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); + +#ifdef __SYMBIAN32__ + RChunk* memmap; +#else + // This only finds 1 GB in 32-bit + static u8 *Find4GBBase(); +#endif +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); + +#endif // _MEMARENA_H_ diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp new file mode 100644 index 00000000..cc6e77b3 --- /dev/null +++ b/src/common/memory_util.cpp @@ -0,0 +1,197 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "memory_util.h" +#include "string_util.h" + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) +#include +#define PAGE_MASK (getpagesize() - 1) +#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) +#endif + +// This is purposely not a full wrapper for virtualalloc/mmap, but it +// provides exactly the primitive operations that Dolphin needs. + +void* AllocateExecutableMemory(size_t size, bool low) +{ +#if defined(_WIN32) + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + static char *map_hint = 0; +#if defined(__x86_64__) && !defined(MAP_32BIT) + // This OS has no flag to enforce allocation below the 4 GB boundary, + // but if we hint that we want a low address it is very likely we will + // get one. + // An older version of this code used MAP_FIXED, but that has the side + // effect of discarding already mapped pages that happen to be in the + // requested virtual memory range (such as the emulated RAM, sometimes). + if (low && (!map_hint)) + map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ +#endif + void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANON | MAP_PRIVATE +#if defined(__x86_64__) && defined(MAP_32BIT) + | (low ? MAP_32BIT : 0) +#endif + , -1, 0); +#endif /* defined(_WIN32) */ + + // printf("Mapped executable memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + +#if defined(__FreeBSD__) + if (ptr == MAP_FAILED) + { + ptr = NULL; +#else + if (ptr == NULL) + { +#endif + PanicAlert("Failed to allocate executable memory"); + } +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) + else + { + if (low) + { + map_hint += size; + map_hint = (char*)round_page(map_hint); /* round up to the next page */ + // printf("Next map will (hopefully) be at %p\n", map_hint); + } + } +#endif + +#if defined(_M_X64) + if ((u64)ptr >= 0x80000000 && low == true) + PanicAlert("Executable memory ended up above 2GB!"); +#endif + + return ptr; +} + +void* AllocateMemoryPages(size_t size) +{ +#ifdef _WIN32 + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +#else + void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + + // printf("Mapped memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + + if (ptr == NULL) + PanicAlert("Failed to allocate raw memory"); + + return ptr; +} + +void* AllocateAlignedMemory(size_t size,size_t alignment) +{ +#ifdef _WIN32 + void* ptr = _aligned_malloc(size,alignment); +#else + void* ptr = NULL; +#ifdef ANDROID + ptr = memalign(alignment, size); +#else + if (posix_memalign(&ptr, alignment, size) != 0) + ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); +#endif +#endif + + // printf("Mapped memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + + if (ptr == NULL) + PanicAlert("Failed to allocate aligned memory"); + + return ptr; +} + +void FreeMemoryPages(void* ptr, size_t size) +{ + if (ptr) + { +#ifdef _WIN32 + + if (!VirtualFree(ptr, 0, MEM_RELEASE)) + PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); + ptr = NULL; // Is this our responsibility? + +#else + munmap(ptr, size); +#endif + } +} + +void FreeAlignedMemory(void* ptr) +{ + if (ptr) + { +#ifdef _WIN32 + _aligned_free(ptr); +#else + free(ptr); +#endif + } +} + +void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +#ifdef _WIN32 + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) + PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); +#else + mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); +#endif +} + +void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +#ifdef _WIN32 + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) + PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); +#else + mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); +#endif +} + +std::string MemUsage() +{ +#ifdef _WIN32 +#pragma comment(lib, "psapi") + DWORD processID = GetCurrentProcessId(); + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + std::string Ret; + + // Print information about the memory usage of the process. + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + if (NULL == hProcess) return "MemUsage Error"; + + if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) + Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); + + CloseHandle(hProcess); + return Ret; +#else + return ""; +#endif +} diff --git a/src/common/memory_util.h b/src/common/memory_util.h new file mode 100644 index 00000000..49b2589d --- /dev/null +++ b/src/common/memory_util.h @@ -0,0 +1,25 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _MEMORYUTIL_H +#define _MEMORYUTIL_H + +#ifndef _WIN32 +#include +#endif +#include + +void* AllocateExecutableMemory(size_t size, bool low = true); +void* AllocateMemoryPages(size_t size); +void FreeMemoryPages(void* ptr, size_t size); +void* AllocateAlignedMemory(size_t size,size_t alignment); +void FreeAlignedMemory(void* ptr); +void WriteProtectMemory(void* ptr, size_t size, bool executable = false); +void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); +std::string MemUsage(); + +inline int GetPageSize() { return 4096; } + +#endif diff --git a/src/common/misc.cpp b/src/common/misc.cpp new file mode 100644 index 00000000..93580547 --- /dev/null +++ b/src/common/misc.cpp @@ -0,0 +1,37 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" + +#ifdef _WIN32 +#include +#endif + +// Neither Android nor OS X support TLS +#if defined(__APPLE__) || (ANDROID && __clang__) +#define __thread +#endif + +// Generic function to get last error message. +// Call directly after the command or use the error num. +// This function might change the error code. +const char* GetLastErrorMsg() +{ + static const size_t buff_size = 255; + +#ifdef _WIN32 + static __declspec(thread) char err_str[buff_size] = {}; + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + err_str, buff_size, NULL); +#else + static __thread char err_str[buff_size] = {}; + + // Thread safe (XSI-compliant) + strerror_r(errno, err_str, buff_size); +#endif + + return err_str; +} diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp new file mode 100644 index 00000000..8e9fe218 --- /dev/null +++ b/src/common/msg_handler.cpp @@ -0,0 +1,107 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include // System + +#include "common.h" // Local +#include "string_util.h" + +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); +static MsgAlertHandler msg_handler = DefaultMsgHandler; +static bool AlertEnabled = true; + +std::string DefaultStringTranslator(const char* text); +static StringTranslator str_translator = DefaultStringTranslator; + +// Select which of these functions that are used for message boxes. If +// wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp +void RegisterMsgAlertHandler(MsgAlertHandler handler) +{ + msg_handler = handler; +} + +// Select translation function. For wxWidgets use wxStringTranslator in Main.cpp +void RegisterStringTranslator(StringTranslator translator) +{ + str_translator = translator; +} + +// enable/disable the alert handler +void SetEnableAlert(bool enable) +{ + AlertEnabled = enable; +} + +// This is the first stop for gui alerts where the log is updated and the +// correct window is shown +bool MsgAlert(bool yes_no, int Style, const char* format, ...) +{ + // Read message and write it to the log + std::string caption; + char buffer[2048]; + + static std::string info_caption; + static std::string warn_caption; + static std::string ques_caption; + static std::string crit_caption; + + if (!info_caption.length()) + { + info_caption = str_translator(_trans("Information")); + ques_caption = str_translator(_trans("Question")); + warn_caption = str_translator(_trans("Warning")); + crit_caption = str_translator(_trans("Critical")); + } + + switch(Style) + { + case INFORMATION: + caption = info_caption; + break; + case QUESTION: + caption = ques_caption; + break; + case WARNING: + caption = warn_caption; + break; + case CRITICAL: + caption = crit_caption; + break; + } + + va_list args; + va_start(args, format); + CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); + va_end(args); + + ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); + + // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored + if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) + return msg_handler(caption.c_str(), buffer, yes_no, Style); + + return true; +} + +// Default non library dependent panic alert +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) +{ +//#ifdef _WIN32 +// int STYLE = MB_ICONINFORMATION; +// if (Style == QUESTION) STYLE = MB_ICONQUESTION; +// if (Style == WARNING) STYLE = MB_ICONWARNING; +// +// return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); +//#else + printf("%s\n", text); + return true; +//#endif +} + +// Default (non) translator +std::string DefaultStringTranslator(const char* text) +{ + return text; +} + diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h new file mode 100644 index 00000000..bde2808f --- /dev/null +++ b/src/common/msg_handler.h @@ -0,0 +1,73 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _MSGHANDLER_H_ +#define _MSGHANDLER_H_ + +#include + +// Message alerts +enum MSG_TYPE +{ + INFORMATION, + QUESTION, + WARNING, + CRITICAL +}; + +typedef bool (*MsgAlertHandler)(const char* caption, const char* text, + bool yes_no, int Style); +typedef std::string (*StringTranslator)(const char* text); + +void RegisterMsgAlertHandler(MsgAlertHandler handler); +void RegisterStringTranslator(StringTranslator translator); + +extern bool MsgAlert(bool yes_no, int Style, const char* format, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) +#endif + ; +void SetEnableAlert(bool enable); + +#ifndef GEKKO +#ifdef _WIN32 + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) + // Use these macros (that do the same thing) if the message should be translated. + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) +#else + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) + // Use these macros (that do the same thing) if the message should be translated. + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) +#endif +#else +// GEKKO + #define SuccessAlert(format, ...) ; + #define PanicAlert(format, ...) ; + #define PanicYesNo(format, ...) ; + #define AskYesNo(format, ...) ; + #define CriticalAlert(format, ...) ; + #define SuccessAlertT(format, ...) ; + #define PanicAlertT(format, ...) ; + #define PanicYesNoT(format, ...) ; + #define AskYesNoT(format, ...) ; + #define CriticalAlertT(format, ...) ; +#endif + +#endif // _MSGHANDLER_H_ diff --git a/src/common/platform.h b/src/common/platform.h new file mode 100644 index 00000000..84c6b636 --- /dev/null +++ b/src/common/platform.h @@ -0,0 +1,142 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file platform.h + * @author ShizZy + * @date 2012-02-11 + * @brief Platform detection macros for portable compilation + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#ifndef COMMON_PLATFORM_H_ +#define COMMON_PLATFORM_H_ + +#include "common_types.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Platform definitions + +/// Enumeration for defining the supported platforms +#define PLATFORM_NULL 0 +#define PLATFORM_WINDOWS 1 +#define PLATFORM_MACOSX 2 +#define PLATFORM_LINUX 3 +#define PLATFORM_ANDROID 4 +#define PLATFORM_IOS 5 + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Platform detection + +#ifndef EMU_PLATFORM + +#if defined( __WIN32__ ) || defined( _WIN32 ) +#define EMU_PLATFORM PLATFORM_WINDOWS + +#elif defined( __APPLE__ ) || defined( __APPLE_CC__ ) +#define EMU_PLATFORM PLATFORM_MAXOSX + +#elif defined(__linux__) +#define EMU_PLATFORM PLATFORM_LINUX + +#else // Assume linux otherwise +#define EMU_PLATFORM PLATFORM_LINUX + +#endif + +#endif + +#if defined(__x86_64__) || defined(_M_X64) || defined(__alpha__) || defined(__ia64__) +#define EMU_ARCHITECTURE_X64 +#else +#define EMU_ARCHITECTURE_X86 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Compiler-Specific Definitions + +#if EMU_PLATFORM == PLATFORM_WINDOWS + +#include + +#define NOMINMAX +#define EMU_FASTCALL __fastcall + +inline struct tm* localtime_r(const time_t *clock, struct tm *result) { + if (localtime_s(result, clock) == 0) + return result; + return NULL; +} + +#else + +#define EMU_FASTCALL __attribute__((fastcall)) +#define __stdcall +#define __cdecl + +#define LONG long +#define BOOL bool +#define DWORD u32 + +#endif + +#if EMU_PLATFORM != PLATFORM_WINDOWS + +// TODO: Hacks.. +#include +#define MAX_PATH PATH_MAX + +#include +#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; + +inline u32 _rotl(u32 x, int shift) { + shift &= 31; + if (0 == shift) { + return x; + } + return (x << shift) | (x >> (32 - shift)); +} + +inline u64 _rotl64(u64 x, u32 shift){ + u32 n = shift % 64; + return (x << n) | (x >> (64 - n)); +} + +inline u32 _rotr(u32 x, int shift) { + shift &= 31; + if (0 == shift) { + return x; + } + return (x >> shift) | (x << (32 - shift)); +} + +inline u64 _rotr64(u64 x, u32 shift){ + u32 n = shift % 64; + return (x >> n) | (x << (64 - n)); +} + +#endif + +#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) + +#endif // COMMON_PLATFORM_H_ diff --git a/src/common/scm_rev.h b/src/common/scm_rev.h new file mode 100644 index 00000000..69962c58 --- /dev/null +++ b/src/common/scm_rev.h @@ -0,0 +1,4 @@ +#define SCM_REV_STR "a7b06698ff012aa7b1094414e796ffae1ca1eb4d" +#define SCM_DESC_STR "a7b0669" +#define SCM_BRANCH_STR "master" +#define SCM_IS_MASTER 1 diff --git a/src/common/src/atomic.h b/src/common/src/atomic.h deleted file mode 100644 index 883bc14f..00000000 --- a/src/common/src/atomic.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_H_ -#define _ATOMIC_H_ - -#ifdef _WIN32 - -#include "atomic_win32.h" - -#else - -// GCC-compatible compiler assumed! -#include "atomic_gcc.h" - -#endif - -#endif diff --git a/src/common/src/atomic_gcc.h b/src/common/src/atomic_gcc.h deleted file mode 100644 index 2eb38697..00000000 --- a/src/common/src/atomic_gcc.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_GCC_H_ -#define _ATOMIC_GCC_H_ - -#include "common.h" - -// Atomic operations are performed in a single step by the CPU. It is -// impossible for other threads to see the operation "half-done." -// -// Some atomic operations can be combined with different types of memory -// barriers called "Acquire semantics" and "Release semantics", defined below. -// -// Acquire semantics: Future memory accesses cannot be relocated to before the -// operation. -// -// Release semantics: Past memory accesses cannot be relocated to after the -// operation. -// -// These barriers affect not only the compiler, but also the CPU. - -namespace Common -{ - -inline void AtomicAdd(volatile u32& target, u32 value) { - __sync_add_and_fetch(&target, value); -} - -inline void AtomicAnd(volatile u32& target, u32 value) { - __sync_and_and_fetch(&target, value); -} - -inline void AtomicDecrement(volatile u32& target) { - __sync_add_and_fetch(&target, -1); -} - -inline void AtomicIncrement(volatile u32& target) { - __sync_add_and_fetch(&target, 1); -} - -inline u32 AtomicLoad(volatile u32& src) { - return src; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - //keep the compiler from caching any memory references - u32 result = src; // 32-bit reads are always atomic. - //__sync_synchronize(); // TODO: May not be necessary. - // Compiler instruction only. x86 loads always have acquire semantics. - __asm__ __volatile__ ( "":::"memory" ); - return result; -} - -inline void AtomicOr(volatile u32& target, u32 value) { - __sync_or_and_fetch(&target, value); -} - -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. -} -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. -} - -} - -// Old code kept here for reference in case we need the parts with __asm__ __volatile__. -#if 0 -LONG SyncInterlockedIncrement(LONG *Dest) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_add_and_fetch(Dest, 1); -#else - register int result; - __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (1), "m" (*Dest) - : "memory"); - return result; -#endif -} - -LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_add_and_fetch(Dest, Val); -#else - register int result; - __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); - return result; -#endif -} - -LONG SyncInterlockedExchange(LONG *Dest, LONG Val) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_lock_test_and_set(Dest, Val); -#else - register int result; - __asm__ __volatile__("lock; xchg %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); - return result; -#endif -} -#endif - -#endif diff --git a/src/common/src/atomic_win32.h b/src/common/src/atomic_win32.h deleted file mode 100644 index 760b16d4..00000000 --- a/src/common/src/atomic_win32.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_WIN32_H_ -#define _ATOMIC_WIN32_H_ - -#include "common.h" -#include -#include - -// Atomic operations are performed in a single step by the CPU. It is -// impossible for other threads to see the operation "half-done." -// -// Some atomic operations can be combined with different types of memory -// barriers called "Acquire semantics" and "Release semantics", defined below. -// -// Acquire semantics: Future memory accesses cannot be relocated to before the -// operation. -// -// Release semantics: Past memory accesses cannot be relocated to after the -// operation. -// -// These barriers affect not only the compiler, but also the CPU. -// -// NOTE: Acquire and Release are not differentiated right now. They perform a -// full memory barrier instead of a "one-way" memory barrier. The newest -// Windows SDK has Acquire and Release versions of some Interlocked* functions. - -namespace Common -{ - -inline void AtomicAdd(volatile u32& target, u32 value) { - InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); -} - -inline void AtomicAnd(volatile u32& target, u32 value) { - _InterlockedAnd((volatile LONG*)&target, (LONG)value); -} - -inline void AtomicIncrement(volatile u32& target) { - InterlockedIncrement((volatile LONG*)&target); -} - -inline void AtomicDecrement(volatile u32& target) { - InterlockedDecrement((volatile LONG*)&target); -} - -inline u32 AtomicLoad(volatile u32& src) { - return src; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - u32 result = src; // 32-bit reads are always atomic. - _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. - return result; -} - -inline void AtomicOr(volatile u32& target, u32 value) { - _InterlockedOr((volatile LONG*)&target, (LONG)value); -} - -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. -} -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. - dest = value; // 32-bit writes are always atomic. -} - -} - -#endif diff --git a/src/common/src/break_points.cpp b/src/common/src/break_points.cpp deleted file mode 100644 index 787263f7..00000000 --- a/src/common/src/break_points.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "debug_interface.h" -#include "break_points.h" - -#include -#include - -bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - if (i->iAddress == _iAddress) - return true; - return false; -} - -bool BreakPoints::IsTempBreakPoint(u32 _iAddress) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - if (i->iAddress == _iAddress && i->bTemporary) - return true; - return false; -} - -BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const -{ - TBreakPointsStr bps; - for (TBreakPoints::const_iterator i = m_BreakPoints.begin(); - i != m_BreakPoints.end(); ++i) - { - if (!i->bTemporary) - { - std::stringstream bp; - bp << std::hex << i->iAddress << " " << (i->bOn ? "n" : ""); - bps.push_back(bp.str()); - } - } - - return bps; -} - -void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) -{ - for (TBreakPointsStr::const_iterator i = bps.begin(); i != bps.end(); ++i) - { - TBreakPoint bp; - std::stringstream bpstr; - bpstr << std::hex << *i; - bpstr >> bp.iAddress; - bp.bOn = i->find("n") != i->npos; - bp.bTemporary = false; - Add(bp); - } -} - -void BreakPoints::Add(const TBreakPoint& bp) -{ - if (!IsAddressBreakPoint(bp.iAddress)) - { - m_BreakPoints.push_back(bp); - //if (jit) - // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); - } -} - -void BreakPoints::Add(u32 em_address, bool temp) -{ - if (!IsAddressBreakPoint(em_address)) // only add new addresses - { - TBreakPoint pt; // breakpoint settings - pt.bOn = true; - pt.bTemporary = temp; - pt.iAddress = em_address; - - m_BreakPoints.push_back(pt); - - //if (jit) - // jit->GetBlockCache()->InvalidateICache(em_address, 4); - } -} - -void BreakPoints::Remove(u32 em_address) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - { - if (i->iAddress == em_address) - { - m_BreakPoints.erase(i); - //if (jit) - // jit->GetBlockCache()->InvalidateICache(em_address, 4); - return; - } - } -} - -void BreakPoints::Clear() -{ - //if (jit) - //{ - // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), - // [](const TBreakPoint& bp) - // { - // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); - // } - // ); - //} - - m_BreakPoints.clear(); -} - -MemChecks::TMemChecksStr MemChecks::GetStrings() const -{ - TMemChecksStr mcs; - for (TMemChecks::const_iterator i = m_MemChecks.begin(); - i != m_MemChecks.end(); ++i) - { - std::stringstream mc; - mc << std::hex << i->StartAddress; - mc << " " << (i->bRange ? i->EndAddress : i->StartAddress) << " " << - (i->bRange ? "n" : "") << (i->OnRead ? "r" : "") << - (i->OnWrite ? "w" : "") << (i->Log ? "l" : "") << (i->Break ? "p" : ""); - mcs.push_back(mc.str()); - } - - return mcs; -} - -void MemChecks::AddFromStrings(const TMemChecksStr& mcs) -{ - for (TMemChecksStr::const_iterator i = mcs.begin(); i != mcs.end(); ++i) - { - TMemCheck mc; - std::stringstream mcstr; - mcstr << std::hex << *i; - mcstr >> mc.StartAddress; - mc.bRange = i->find("n") != i->npos; - mc.OnRead = i->find("r") != i->npos; - mc.OnWrite = i->find("w") != i->npos; - mc.Log = i->find("l") != i->npos; - mc.Break = i->find("p") != i->npos; - if (mc.bRange) - mcstr >> mc.EndAddress; - else - mc.EndAddress = mc.StartAddress; - Add(mc); - } -} - -void MemChecks::Add(const TMemCheck& _rMemoryCheck) -{ - if (GetMemCheck(_rMemoryCheck.StartAddress) == 0) - m_MemChecks.push_back(_rMemoryCheck); -} - -void MemChecks::Remove(u32 _Address) -{ - for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) - { - if (i->StartAddress == _Address) - { - m_MemChecks.erase(i); - return; - } - } -} - -TMemCheck *MemChecks::GetMemCheck(u32 address) -{ - for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) - { - if (i->bRange) - { - if (address >= i->StartAddress && address <= i->EndAddress) - return &(*i); - } - else if (i->StartAddress == address) - return &(*i); - } - - // none found - return 0; -} - -void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, - bool write, int size, u32 pc) -{ - if ((write && OnWrite) || (!write && OnRead)) - { - if (Log) - { - INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", - pc, debug_interface->getDescription(pc).c_str(), - write ? "Write" : "Read", size*8, size*2, iValue, addr, - debug_interface->getDescription(addr).c_str() - ); - } - if (Break) - debug_interface->breakNow(); - } -} diff --git a/src/common/src/break_points.h b/src/common/src/break_points.h deleted file mode 100644 index dc771ba0..00000000 --- a/src/common/src/break_points.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _DEBUGGER_BREAKPOINTS_H -#define _DEBUGGER_BREAKPOINTS_H - -#include -#include - -#include "common.h" - -class DebugInterface; - -struct TBreakPoint -{ - u32 iAddress; - bool bOn; - bool bTemporary; -}; - -struct TMemCheck -{ - TMemCheck() { - numHits = 0; - StartAddress = EndAddress = 0; - bRange = OnRead = OnWrite = Log = Break = false; - } - u32 StartAddress; - u32 EndAddress; - - bool bRange; - - bool OnRead; - bool OnWrite; - - bool Log; - bool Break; - - u32 numHits; - - void Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, - bool write, int size, u32 pc); -}; - -// Code breakpoints. -class BreakPoints -{ -public: - typedef std::vector TBreakPoints; - typedef std::vector TBreakPointsStr; - - const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } - - TBreakPointsStr GetStrings() const; - void AddFromStrings(const TBreakPointsStr& bps); - - // is address breakpoint - bool IsAddressBreakPoint(u32 _iAddress); - bool IsTempBreakPoint(u32 _iAddress); - - // Add BreakPoint - void Add(u32 em_address, bool temp=false); - void Add(const TBreakPoint& bp); - - // Remove Breakpoint - void Remove(u32 _iAddress); - void Clear(); - - void DeleteByAddress(u32 _Address); - -private: - TBreakPoints m_BreakPoints; - u32 m_iBreakOnCount; -}; - - -// Memory breakpoints -class MemChecks -{ -public: - typedef std::vector TMemChecks; - typedef std::vector TMemChecksStr; - - TMemChecks m_MemChecks; - - const TMemChecks& GetMemChecks() { return m_MemChecks; } - - TMemChecksStr GetStrings() const; - void AddFromStrings(const TMemChecksStr& mcs); - - void Add(const TMemCheck& _rMemoryCheck); - - // memory breakpoint - TMemCheck *GetMemCheck(u32 address); - void Remove(u32 _Address); - - void Clear() { m_MemChecks.clear(); }; -}; - -#endif - diff --git a/src/common/src/chunk_file.h b/src/common/src/chunk_file.h deleted file mode 100644 index 68c2943a..00000000 --- a/src/common/src/chunk_file.h +++ /dev/null @@ -1,874 +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/ - -#ifndef _POINTERWRAP_H_ -#define _POINTERWRAP_H_ - -// Extremely simple serialization framework. - -// (mis)-features: -// + Super fast -// + Very simple -// + Same code is used for serialization and deserializaition (in most cases) -// - Zero backwards/forwards compatibility -// - Serialization code for anything complex has to be manually written. - -#include -#include -#include -#include -#include -#include -#ifndef __SYMBIAN32__ -#if defined(IOS) || defined(MACGNUSTD) -#include -#else -#include -#endif -#endif - -#include "common.h" -#include "file_util.h" -//#include "../ext/snappy/snappy-c.h" - -#if defined(IOS) || defined(MACGNUSTD) -namespace std { - using tr1::is_pointer; -} -#endif -#ifdef __SYMBIAN32__ -namespace std { - template - struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; - }; - template const bool bool_constant::value; - template struct is_pointer : public bool_constant {}; - template struct is_pointer : public bool_constant {}; -} -#endif - -template -struct LinkedListItem : public T -{ - LinkedListItem *next; -}; - -class PointerWrap; - -class PointerWrapSection -{ -public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } - ~PointerWrapSection(); - - bool operator == (const int &v) const { return ver_ == v; } - bool operator != (const int &v) const { return ver_ != v; } - bool operator <= (const int &v) const { return ver_ <= v; } - bool operator >= (const int &v) const { return ver_ >= v; } - bool operator < (const int &v) const { return ver_ < v; } - bool operator > (const int &v) const { return ver_ > v; } - - operator bool() const { - return ver_ > 0; - } - -private: - PointerWrap &p_; - int ver_; - const char *title_; -}; - -// Wrapper class -class PointerWrap -{ - // This makes it a compile error if you forget to define DoState() on non-POD. - // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... -#ifdef _MSC_VER - template::value, bool isPointer = std::is_pointer::value> -#else - template::value> -#endif - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - for (int i = 0; i < count; ++i) - p->Do(x[i]); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoClass(x); - } - }; - - template - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - p->DoVoid((void *)x, sizeof(T) * count); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoVoid((void *)&x, sizeof(x)); - } - }; - -public: - enum Mode { - MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare - }; - - enum Error { - ERROR_NONE = 0, - ERROR_WARNING = 1, - ERROR_FAILURE = 2, - }; - - u8 **ptr; - Mode mode; - Error error; - -public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} - - PointerWrapSection Section(const char *title, int ver) { - return Section(title, ver, ver); - } - - // The returned object can be compared against the version that was loaded. - // This can be used to support versions as old as minVer. - // Version = 0 means the section was not found. - PointerWrapSection Section(const char *title, int minVer, int ver) { - char marker[16] = {0}; - int foundVersion = ver; - - strncpy(marker, title, sizeof(marker)); - if (!ExpectVoid(marker, sizeof(marker))) - { - // Might be before we added name markers for safety. - if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) - DoMarker(title); - // Wasn't found, but maybe we can still load the state. - else - foundVersion = 0; - } - else - Do(foundVersion); - - if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { - WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); - SetError(ERROR_FAILURE); - return PointerWrapSection(*this, -1, title); - } - return PointerWrapSection(*this, foundVersion, title); - } - - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} - void SetError(Error error_) - { - if (error < error_) - error = error_; - if (error > ERROR_WARNING) - mode = PointerWrap::MODE_MEASURE; - } - - bool ExpectVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; - default: break; // throw an error? - } - (*ptr) += size; - return true; - } - - void DoVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: memcpy(data, *ptr, size); break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; - default: break; // throw an error? - } - (*ptr) += size; - } - - template - void Do(std::map &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMap(x, dv); - } - - template - void Do(std::map &x) - { - T dv = T(); - DoMap(x, dv); - } - - template - void DoMap(std::map &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x[first] = second; - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::map::iterator itr = x.begin(); - while (number > 0) - { - K first = itr->first; - Do(first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - template - void Do(std::multimap &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMultimap(x, dv); - } - - template - void Do(std::multimap &x) - { - T dv = T(); - DoMultimap(x, dv); - } - - template - void DoMultimap(std::multimap &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x.insert(std::make_pair(first, second)); - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::multimap::iterator itr = x.begin(); - while (number > 0) - { - Do(itr->first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - // Store vectors. - template - void Do(std::vector &x) - { - T *dv = NULL; - DoVector(x, dv); - } - - template - void Do(std::vector &x) - { - T dv = T(); - DoVector(x, dv); - } - - - template - void DoPOD(std::vector &x) - { - T dv = T(); - DoVectorPOD(x, dv); - } - - template - void Do(std::vector &x, T &default_val) - { - DoVector(x, default_val); - } - - template - void DoVector(std::vector &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - template - void DoVectorPOD(std::vector &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - // Store deques. - template - void Do(std::deque &x) - { - T *dv = NULL; - DoDeque(x, dv); - } - - template - void Do(std::deque &x) - { - T dv = T(); - DoDeque(x, dv); - } - - template - void DoDeque(std::deque &x, T &default_val) - { - u32 deq_size = (u32)x.size(); - Do(deq_size); - x.resize(deq_size, default_val); - u32 i; - for(i = 0; i < deq_size; i++) - Do(x[i]); - } - - // Store STL lists. - template - void Do(std::list &x) - { - T *dv = NULL; - Do(x, dv); - } - - template - void Do(std::list &x) - { - T dv = T(); - DoList(x, dv); - } - - template - void Do(std::list &x, T &default_val) - { - DoList(x, default_val); - } - - template - void DoList(std::list &x, T &default_val) - { - u32 list_size = (u32)x.size(); - Do(list_size); - x.resize(list_size, default_val); - - typename std::list::iterator itr, end; - for (itr = x.begin(), end = x.end(); itr != end; ++itr) - Do(*itr); - } - - - // Store STL sets. - template - void Do(std::set &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (*it != NULL) - delete *it; - } - } - DoSet(x); - } - - template - void Do(std::set &x) - { - DoSet(x); - } - - template - void DoSet(std::set &x) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - - switch (mode) - { - case MODE_READ: - { - x.clear(); - while (number-- > 0) - { - T it = T(); - Do(it); - x.insert(it); - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::set::iterator itr = x.begin(); - while (number-- > 0) - Do(*itr++); - } - break; - - default: - ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); - } - } - - // Store strings. - void Do(std::string &x) - { - int stringLen = (int)x.length() + 1; - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (char*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; - } - (*ptr) += stringLen; - } - - void Do(std::wstring &x) - { - int stringLen = sizeof(wchar_t)*((int)x.length() + 1); - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (wchar_t*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; - } - (*ptr) += stringLen; - } - - template - void DoClass(T &x) { - x.DoState(*this); - } - - template - void DoClass(T *&x) { - if (mode == MODE_READ) - { - if (x != NULL) - delete x; - x = new T(); - } - x->DoState(*this); - } - - template - void DoArray(T *x, int count) { - DoHelper::DoArray(this, x, count); - } - - template - void Do(T &x) { - DoHelper::Do(this, x); - } - - template - void DoPOD(T &x) { - DoHelper::Do(this, x); - } - - template - void DoPointer(T* &x, T*const base) { - // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range - s32 offset = x - base; - Do(offset); - if (mode == MODE_READ) - x = base + offset; - } - - template* (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> - void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) - { - LinkedListItem* list_cur = list_start; - LinkedListItem* prev = 0; - - while (true) - { - u8 shouldExist = (list_cur ? 1 : 0); - Do(shouldExist); - if (shouldExist == 1) - { - LinkedListItem* cur = list_cur ? list_cur : TNew(); - TDo(*this, (T*)cur); - if (!list_cur) - { - if (mode == MODE_READ) - { - cur->next = 0; - list_cur = cur; - if (prev) - prev->next = cur; - else - list_start = cur; - } - else - { - TFree(cur); - continue; - } - } - } - else - { - if (mode == MODE_READ) - { - if (prev) - prev->next = 0; - if (list_end) - *list_end = prev; - if (list_cur) - { - if (list_start == list_cur) - list_start = 0; - do - { - LinkedListItem* next = list_cur->next; - TFree(list_cur); - list_cur = next; - } - while (list_cur); - } - } - break; - } - prev = list_cur; - list_cur = list_cur->next; - } - } - - void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) - { - u32 cookie = arbitraryNumber; - Do(cookie); - if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) - { - PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); - SetError(ERROR_FAILURE); - } - } -}; - -inline PointerWrapSection::~PointerWrapSection() { - if (ver_ > 0) { - p_.DoMarker(title_); - } -} - - -class CChunkFileReader -{ -public: - enum Error { - ERROR_NONE, - ERROR_BAD_FILE, - ERROR_BROKEN_STATE, - }; - - // Load file template - template - static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) - { - INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); - _failureReason->clear(); - _failureReason->append("LoadStateWrongVersion"); - - if (!File::Exists(_rFilename)) { - _failureReason->clear(); - _failureReason->append("LoadStateDoesntExist"); - ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); - return ERROR_BAD_FILE; - } - - // Check file size - const u64 fileSize = File::GetSize(_rFilename); - static const u64 headerSize = sizeof(SChunkHeader); - if (fileSize < headerSize) - { - ERROR_LOG(COMMON,"ChunkReader: File too small"); - return ERROR_BAD_FILE; - } - - File::IOFile pFile(_rFilename, "rb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); - return ERROR_BAD_FILE; - } - - // read the header - SChunkHeader header; - if (!pFile.ReadArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Bad header size"); - return ERROR_BAD_FILE; - } - - // Check revision - if (header.Revision != _Revision) - { - ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", - header.Revision, _Revision); - return ERROR_BAD_FILE; - } - - if (strcmp(header.GitVersion, _VersionString) != 0) - { - WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", - header.GitVersion); - } - - // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) - { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); - return ERROR_BAD_FILE; - } - - // read the state - u8* buffer = new u8[sz]; - if (!pFile.ReadBytes(buffer, sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Error reading file"); - return ERROR_BAD_FILE; - } - - u8 *ptr = buffer; - u8 *buf = buffer; - if (header.Compress) { - u8 *uncomp_buffer = new u8[header.UncompressedSize]; - size_t uncomp_size = header.UncompressedSize; - snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); - if ((int)uncomp_size != header.UncompressedSize) { - ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); - } - ptr = uncomp_buffer; - buf = uncomp_buffer; - delete [] buffer; - } - - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); - delete[] buf; - - INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - // Save file template - template - static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - - File::IOFile pFile(_rFilename, "wb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); - return ERROR_BAD_FILE; - } - - bool compress = true; - - // Get data - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - - u8 * buffer = new u8[sz]; - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Create header - SChunkHeader header; - header.Compress = compress ? 1 : 0; - header.Revision = _Revision; - header.ExpectedSize = (int)sz; - header.UncompressedSize = (int)sz; - strncpy(header.GitVersion, _VersionString, 32); - header.GitVersion[31] = '\0'; - - // Write to file - if (compress) { - size_t comp_len = snappy_max_compressed_length(sz); - u8 *compressed_buffer = new u8[comp_len]; - snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); - delete [] buffer; - header.ExpectedSize = (int)comp_len; - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { - ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); - return ERROR_BAD_FILE; - } else { - INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); - } - delete [] compressed_buffer; - } else { - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&buffer[0], sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); - return ERROR_BAD_FILE; - } - delete [] buffer; - } - - INFO_LOG(COMMON,"ChunkReader: Done writing %s", - _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - template - static Error Verify(T& _class) - { - u8 *ptr = 0; - - // Step 1: Measure the space required. - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector buffer(sz); - - // Step 2: Dump the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Step 3: Verify the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_VERIFY); - _class.DoState(p); - - return ERROR_NONE; - } - -private: - struct SChunkHeader - { - int Revision; - int Compress; - int ExpectedSize; - int UncompressedSize; - char GitVersion[32]; - }; -}; - -#endif // _POINTERWRAP_H_ diff --git a/src/common/src/common.h b/src/common/src/common.h deleted file mode 100644 index 3b71d9b3..00000000 --- a/src/common/src/common.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMON_H_ -#define _COMMON_H_ - -// DO NOT EVER INCLUDE directly _or indirectly_ from this file -// since it slows down the build a lot. - -#include -#include -#include - -// SVN version number -extern const char *scm_rev_str; -extern const char *netplay_dolphin_ver; - -// Force enable logging in the right modes. For some reason, something had changed -// so that debugfast no longer logged. -#if defined(_DEBUG) || defined(DEBUGFAST) -#undef LOGGING -#define LOGGING 1 -#endif - -#define STACKALIGN - -#if __cplusplus >= 201103 || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) -#define HAVE_CXX11_SYNTAX 1 -#endif - -#if HAVE_CXX11_SYNTAX -// 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); -}; -#endif - -#include "log.h" -#include "common_types.h" -#include "msg_handler.h" -#include "common_funcs.h" -#include "common_paths.h" -#include "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 - - #define NOMINMAX - -// Memory leak checks - #define CHECK_HEAP_INTEGRITY() - -// 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 - -// Since they are always around on windows - #define HAVE_WX 1 - #define HAVE_OPENAL 1 - - #define HAVE_PORTAUDIO 1 - -// Debug definitions - #if defined(_DEBUG) - #include - #undef CHECK_HEAP_INTEGRITY - #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} - // If you want to see how much a pain in the ass singletons are, for example: - // {614} normal block at 0x030C5310, 188 bytes long. - // Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 - struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } }; - //CrtDebugBreak breakAt(614); - #endif // end DEBUG/FAST - -#endif - -// Windows compatibility -#ifndef _WIN32 -#include -#define MAX_PATH PATH_MAX -#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 - -// Dummy macro for marking translatable strings that can not be immediately translated. -// wxWidgets does not have a true dummy macro for this. -#define _trans(a) a - -#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 -}; - -// This should be used in the private: declarations for a class -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -#endif // _COMMON_H_ diff --git a/src/common/src/common_funcs.h b/src/common/src/common_funcs.h deleted file mode 100644 index 7ca0b350..00000000 --- a/src/common/src/common_funcs.h +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMONFUNCS_H_ -#define _COMMONFUNCS_H_ - -#ifdef _WIN32 -#define SLEEP(x) Sleep(x) -#else -#include -#define SLEEP(x) usleep(x*1000) -#endif - -template struct CompileTimeAssert; -template<> struct CompileTimeAssert {}; - -#define b2(x) ( (x) | ( (x) >> 1) ) -#define b4(x) ( b2(x) | ( b2(x) >> 2) ) -#define b8(x) ( b4(x) | ( b4(x) >> 4) ) -#define b16(x) ( b8(x) | ( b8(x) >> 8) ) -#define b32(x) (b16(x) | (b16(x) >>16) ) -#define ROUND_UP_POW2(x) (b32(x - 1) + 1) - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC -#include -static __inline __m128i __attribute__((__always_inline__)) -_mm_shuffle_epi8(__m128i a, __m128i mask) -{ - __m128i result; - __asm__("pshufb %1, %0" - : "=x" (result) - : "xm" (mask), "0" (a)); - return result; -} -#endif - -#ifndef _WIN32 - -#include -#ifdef __linux__ -#include -#elif defined __FreeBSD__ -#include -#endif - -// go to debugger mode - #ifdef GEKKO - #define Crash() - #elif defined _M_GENERIC - #define Crash() { exit(1); } - #else - #define Crash() {asm ("int $3");} - #endif - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -// GCC 4.8 defines all the rotate functions now -// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit -#ifndef _rotl -inline u32 _rotl(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x << shift) | (x >> (32 - shift)); -} - -inline u32 _rotr(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x >> shift) | (x << (32 - shift)); -} -#endif - -inline u64 _rotl64(u64 x, unsigned int shift){ - unsigned int n = shift % 64; - return (x << n) | (x >> (64 - n)); -} - -inline u64 _rotr64(u64 x, unsigned int shift){ - unsigned int n = shift % 64; - return (x >> n) | (x << (64 - n)); -} - -#else // WIN32 -// Function Cross-Compatibility - #define strcasecmp _stricmp - #define strncasecmp _strnicmp - #define unlink _unlink - #define snprintf _snprintf - #define vscprintf _vscprintf - -// 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 != NULL) - { - // 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 - - #if _M_IX86 - #define Crash() {__asm int 3} - #else -extern "C" { - __declspec(dllimport) void __stdcall DebugBreak(void); -} - #define Crash() {DebugBreak();} - #endif // M_IX86 -#endif // WIN32 ndef - -// Dolphin's min and max functions -#undef min -#undef max - -template -inline T min(const T& a, const T& b) {return a > b ? b : a;} -template -inline T max(const T& a, const T& b) {return a > b ? a : b;} - -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -// Defined in Misc.cpp. -const char* GetLastErrorMsg(); - -namespace Common -{ -inline u8 swap8(u8 _data) {return _data;} -inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} - -#ifdef ANDROID -#undef swap16 -#undef swap32 -#undef swap64 -#endif - -#ifdef _WIN32 -inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} -inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} -inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} -#elif _M_ARM -inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} -inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} -inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} -#elif __linux__ -inline u16 swap16(u16 _data) {return bswap_16(_data);} -inline u32 swap32(u32 _data) {return bswap_32(_data);} -inline u64 swap64(u64 _data) {return bswap_64(_data);} -#elif __APPLE__ -inline __attribute__((always_inline)) u16 swap16(u16 _data) - {return (_data >> 8) | (_data << 8);} -inline __attribute__((always_inline)) u32 swap32(u32 _data) - {return __builtin_bswap32(_data);} -inline __attribute__((always_inline)) u64 swap64(u64 _data) - {return __builtin_bswap64(_data);} -#elif __FreeBSD__ -inline u16 swap16(u16 _data) {return bswap16(_data);} -inline u32 swap32(u32 _data) {return bswap32(_data);} -inline u64 swap64(u64 _data) {return bswap64(_data);} -#else -// Slow generic implementation. -inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} -inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} -inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} -#endif - -inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} -inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} -inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} - -template -void swap(u8*); - -template <> -inline void swap<1>(u8* data) -{} - -template <> -inline void swap<2>(u8* data) -{ - *reinterpret_cast(data) = swap16(data); -} - -template <> -inline void swap<4>(u8* data) -{ - *reinterpret_cast(data) = swap32(data); -} - -template <> -inline void swap<8>(u8* data) -{ - *reinterpret_cast(data) = swap64(data); -} - -template -inline T FromBigEndian(T data) -{ - //static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); - - swap(reinterpret_cast(&data)); - return data; -} - -} // Namespace Common - -#endif // _COMMONFUNCS_H_ diff --git a/src/common/src/common_paths.h b/src/common/src/common_paths.h deleted file mode 100644 index 9ccb87d8..00000000 --- a/src/common/src/common_paths.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMON_PATHS_H_ -#define _COMMON_PATHS_H_ - -// Make sure we pick up USER_DIR if set in config.h -#include "common.h" - -// Directory seperators, do we need this? -#define DIR_SEP "/" -#define DIR_SEP_CHR '/' - -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - -// The user data dir -#define ROOT_DIR "." -#ifdef _WIN32 - #define USERDATA_DIR "user" - #define EMU_DATA_DIR "emu" -#else - #define USERDATA_DIR "user" - #ifdef USER_DIR - #define EMU_DATA_DIR USER_DIR - #else - #define EMU_DATA_DIR ".emu" - #endif -#endif - -// Shared data dirs (Sys and shared User for linux) -#ifdef _WIN32 - #define SYSDATA_DIR "sys" -#else - #ifdef DATA_DIR - #define SYSDATA_DIR DATA_DIR "sys" - #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP - #else - #define SYSDATA_DIR "sys" - #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP - #endif -#endif - -// Dirs in both User and Sys -#define EUR_DIR "EUR" -#define USA_DIR "USA" -#define JAP_DIR "JAP" - -// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) -#define CONFIG_DIR "config" -#define GAMECONFIG_DIR "game_config" -#define MAPS_DIR "maps" -#define CACHE_DIR "cache" -#define SHADERCACHE_DIR "shader_cache" -#define STATESAVES_DIR "state_saves" -#define SCREENSHOTS_DIR "screenShots" -#define DUMP_DIR "dump" -#define DUMP_TEXTURES_DIR "textures" -#define DUMP_FRAMES_DIR "frames" -#define DUMP_AUDIO_DIR "audio" -#define LOGS_DIR "logs" -#define SHADERS_DIR "shaders" -#define SYSCONF_DIR "sysconf" - -// Filenames -// Files in the directory returned by GetUserPath(D_CONFIG_IDX) -#define EMU_CONFIG "emu.ini" -#define DEBUGGER_CONFIG "debugger.ini" -#define LOGGER_CONFIG "logger.ini" - -// Files in the directory returned by GetUserPath(D_LOGS_IDX) -#define MAIN_LOG "emu.log" - -// Files in the directory returned by GetUserPath(D_SYSCONF_IDX) -#define SYSCONF "SYSCONF" - -#endif // _COMMON_PATHS_H_ diff --git a/src/common/src/common_types.h b/src/common/src/common_types.h deleted file mode 100644 index af1cd0e2..00000000 --- a/src/common/src/common_types.h +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file common_types.h - * @author ShizZy - * @date 2012-02-11 - * @brief Common types used throughout the project - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#pragma once - -#include -#include // data_types__m128.cpp - -#ifdef _WIN32 - -#include - -typedef unsigned __int8 u8; ///< 8-bit unsigned byte -typedef unsigned __int16 u16; ///< 16-bit unsigned short -typedef unsigned __int32 u32; ///< 32-bit unsigned word -typedef unsigned __int64 u64; ///< 64-bit unsigned int - -typedef signed __int8 s8; ///< 8-bit signed byte -typedef signed __int16 s16; ///< 16-bit signed short -typedef signed __int32 s32; ///< 32-bit signed word -typedef signed __int64 s64; ///< 64-bit signed int - -#else - -typedef unsigned char u8; ///< 8-bit unsigned byte -typedef unsigned short u16; ///< 16-bit unsigned short -typedef unsigned int u32; ///< 32-bit unsigned word -typedef unsigned long long u64; ///< 64-bit unsigned int - -typedef signed char s8; ///< 8-bit signed byte -typedef signed short s16; ///< 16-bit signed short -typedef signed int s32; ///< 32-bit signed word -typedef signed long long s64; ///< 64-bit signed int - -// For using windows lock code -#define TCHAR char -#define LONG int - -#endif // _WIN32 - -typedef float f32; ///< 32-bit floating point -typedef double f64; ///< 64-bit floating point - -#include "swap.h" - -/// Union for fast 16-bit type casting -union t16 { - u8 _u8[2]; ///< 8-bit unsigned char(s) - u16 _u16; ///< 16-bit unsigned shorts(s) -}; - -/// Union for fast 32-bit type casting -union t32 { - f32 _f32; ///< 32-bit floating point(s) - u32 _u32; ///< 32-bit unsigned int(s) - s32 _s32; ///< 32-bit signed int(s) - u16 _u16[2]; ///< 16-bit unsigned shorts(s) - u8 _u8[4]; ///< 8-bit unsigned char(s) -}; - -/// Union for fast 64-bit type casting -union t64 { - f64 _f64; ///< 64-bit floating point - u64 _u64; ///< 64-bit unsigned long - f32 _f32[2]; ///< 32-bit floating point(s) - u32 _u32[2]; ///< 32-bit unsigned int(s) - s32 _s32[2]; ///< 32-bit signed int(s) - u16 _u16[4]; ///< 16-bit unsigned shorts(s) - u8 _u8[8]; ///< 8-bit unsigned char(s) -}; - -/// Union for fast 128-bit type casting -union t128 { - struct - { - t64 ps0; ///< 64-bit paired single 0 - t64 ps1; ///< 64-bit paired single 1 - }; - __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) -}; - -/// 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 abs(x1_ - x0_); } - inline u32 height() const { return abs(y1_ - y0_); } - - inline bool operator == (const Rect& val) const { - return (x0_ == val.x0_ && y0_ == val.y0_ && x1_ == val.x1_ && y1_ == val.y1_); - } -}; diff --git a/src/common/src/console_listener.cpp b/src/common/src/console_listener.cpp deleted file mode 100644 index 270ad9ce..00000000 --- a/src/common/src/console_listener.cpp +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include // min -#include // System: To be able to add strings with "+" -#include -#include -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -#include "common.h" -#include "log_manager.h" // Common -#include "console_listener.h" // Common - -ConsoleListener::ConsoleListener() -{ -#ifdef _WIN32 - hConsole = NULL; - bUseColor = true; -#else - bUseColor = isatty(fileno(stdout)); -#endif -} - -ConsoleListener::~ConsoleListener() -{ - Close(); -} - -// 100, 100, "Dolphin Log Console" -// Open console window - width and height is the size of console window -// Name is the window title -void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title) -{ -#ifdef _WIN32 - if (!GetConsoleWindow()) - { - // Open the console window and create the window handle for GetStdHandle() - AllocConsole(); - // Hide - if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE); - // Save the window handle that AllocConsole() created - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - // Set the console window title - SetConsoleTitle(UTF8ToTStr(Title).c_str()); - // Set letter space - LetterSpace(80, 4000); - //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); - } - else - { - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - } -#endif -} - -void ConsoleListener::UpdateHandle() -{ -#ifdef _WIN32 - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); -#endif -} - -// Close the console window and close the eventual file handle -void ConsoleListener::Close() -{ -#ifdef _WIN32 - if (hConsole == NULL) - return; - FreeConsole(); - hConsole = NULL; -#else - fflush(NULL); -#endif -} - -bool ConsoleListener::IsOpen() -{ -#ifdef _WIN32 - return (hConsole != NULL); -#else - return true; -#endif -} - -/* - LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are - dependent on each other, that's the reason for the additional checks. -*/ -void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) -{ -#ifdef _WIN32 - BOOL SB, SW; - if (BufferFirst) - { - // Change screen buffer size - COORD Co = {BufferWidth, BufferHeight}; - SB = SetConsoleScreenBufferSize(hConsole, Co); - // Change the screen buffer window size - SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom - SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); - } - else - { - // Change the screen buffer window size - SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom - SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); - // Change screen buffer size - COORD Co = {BufferWidth, BufferHeight}; - SB = SetConsoleScreenBufferSize(hConsole, Co); - } -#endif -} -void ConsoleListener::LetterSpace(int Width, int Height) -{ -#ifdef _WIN32 - // Get console info - CONSOLE_SCREEN_BUFFER_INFO ConInfo; - GetConsoleScreenBufferInfo(hConsole, &ConInfo); - - // - int OldBufferWidth = ConInfo.dwSize.X; - int OldBufferHeight = ConInfo.dwSize.Y; - int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); - int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); - // - int NewBufferWidth = Width; - int NewBufferHeight = Height; - int NewScreenWidth = NewBufferWidth - 1; - int NewScreenHeight = OldScreenHeight; - - // Width - BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1)); - // Height - BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); - - // Resize the window too - //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); -#endif -} -#ifdef _WIN32 -COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) -{ - COORD Ret = {0, 0}; - // Full rows - int Step = (int)floor((float)BytesRead / (float)BufferWidth); - Ret.Y += Step; - // Partial row - Ret.X = BytesRead - (BufferWidth * Step); - return Ret; -} -#endif -void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) -{ -#ifdef _WIN32 - // Check size - if (Width < 8 || Height < 12) return; - - bool DBef = true; - bool DAft = true; - std::string SLog = ""; - - const HWND hWnd = GetConsoleWindow(); - const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - // Get console info - CONSOLE_SCREEN_BUFFER_INFO ConInfo; - GetConsoleScreenBufferInfo(hConsole, &ConInfo); - DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y; - - // --------------------------------------------------------------------- - // Save the current text - // ------------------------ - DWORD cCharsRead = 0; - COORD coordScreen = { 0, 0 }; - - static const int MAX_BYTES = 1024 * 16; - - std::vector> Str; - std::vector> Attr; - - // ReadConsoleOutputAttribute seems to have a limit at this level - static const int ReadBufferSize = MAX_BYTES - 32; - - DWORD cAttrRead = ReadBufferSize; - DWORD BytesRead = 0; - while (BytesRead < BufferSize) - { - Str.resize(Str.size() + 1); - if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); - - Attr.resize(Attr.size() + 1); - if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); - - // Break on error - if (cAttrRead == 0) break; - BytesRead += cAttrRead; - coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X); - } - // Letter space - int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f); - int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f); - int LBufWidth = LWidth + 1; - int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth); - // Change screen buffer size - LetterSpace(LBufWidth, LBufHeight); - - - ClearScreen(true); - coordScreen.Y = 0; - coordScreen.X = 0; - DWORD cCharsWritten = 0; - - int BytesWritten = 0; - DWORD cAttrWritten = 0; - for (size_t i = 0; i < Attr.size(); i++) - { - if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); - if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); - - BytesWritten += cAttrWritten; - coordScreen = GetCoordinates(BytesWritten, LBufWidth); - } - - const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; - COORD Coo = GetCoordinates(OldCursor, LBufWidth); - SetConsoleCursorPosition(hConsole, Coo); - - if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str()); - - // Resize the window too - if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); -#endif -} - -void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) -{ -#if defined(_WIN32) - /* - const int MAX_BYTES = 1024*10; - char Str[MAX_BYTES]; - va_list ArgPtr; - int Cnt; - va_start(ArgPtr, Text); - Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); - va_end(ArgPtr); - */ - DWORD cCharsWritten; - WORD Color; - - switch (Level) - { - case NOTICE_LEVEL: // light green - Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; - break; - case ERROR_LEVEL: // light red - Color = FOREGROUND_RED | FOREGROUND_INTENSITY; - break; - case WARNING_LEVEL: // light yellow - Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; - break; - case INFO_LEVEL: // cyan - Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; - break; - case DEBUG_LEVEL: // gray - Color = FOREGROUND_INTENSITY; - break; - default: // off-white - Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - break; - } - if (strlen(Text) > 10) - { - // First 10 chars white - SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); - Text += 10; - } - SetConsoleTextAttribute(hConsole, Color); - WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); -#else - char ColorAttr[16] = ""; - char ResetAttr[16] = ""; - - if (bUseColor) - { - strcpy(ResetAttr, "\033[0m"); - switch (Level) - { - case NOTICE_LEVEL: // light green - strcpy(ColorAttr, "\033[92m"); - break; - case ERROR_LEVEL: // light red - strcpy(ColorAttr, "\033[91m"); - break; - case WARNING_LEVEL: // light yellow - strcpy(ColorAttr, "\033[93m"); - break; - default: - break; - } - } - fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); -#endif -} -// Clear console screen -void ConsoleListener::ClearScreen(bool Cursor) -{ -#if defined(_WIN32) - COORD coordScreen = { 0, 0 }; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; - - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - GetConsoleScreenBufferInfo(hConsole, &csbi); - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - // Write space to the entire console - FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); - GetConsoleScreenBufferInfo(hConsole, &csbi); - FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); - // Reset cursor - if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); -#endif -} - - diff --git a/src/common/src/console_listener.h b/src/common/src/console_listener.h deleted file mode 100644 index a2936050..00000000 --- a/src/common/src/console_listener.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _CONSOLELISTENER_H -#define _CONSOLELISTENER_H - -#include "log_manager.h" - -#ifdef _WIN32 -#include -#endif - -class ConsoleListener : public LogListener -{ -public: - ConsoleListener(); - ~ConsoleListener(); - - void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console"); - void UpdateHandle(); - void Close(); - bool IsOpen(); - void LetterSpace(int Width, int Height); - void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst); - void PixelSpace(int Left, int Top, int Width, int Height, bool); -#ifdef _WIN32 - COORD GetCoordinates(int BytesRead, int BufferWidth); -#endif - void Log(LogTypes::LOG_LEVELS, const char *Text); - void ClearScreen(bool Cursor = true); - -private: -#ifdef _WIN32 - HWND GetHwnd(void); - HANDLE hConsole; -#endif - bool bUseColor; -}; - -#endif // _CONSOLELISTENER_H diff --git a/src/common/src/cpu_detect.h b/src/common/src/cpu_detect.h deleted file mode 100644 index e93cf333..00000000 --- a/src/common/src/cpu_detect.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -// Detect the cpu, so we'll know which optimizations to use -#ifndef _CPUDETECT_H_ -#define _CPUDETECT_H_ - -#include - -enum CPUVendor -{ - VENDOR_INTEL = 0, - VENDOR_AMD = 1, - VENDOR_ARM = 2, - VENDOR_OTHER = 3, -}; - -struct CPUInfo -{ - CPUVendor vendor; - - char cpu_string[0x21]; - char brand_string[0x41]; - bool OS64bit; - bool CPU64bit; - bool Mode64bit; - - bool HTT; - int num_cores; - int logical_cpu_count; - - bool bSSE; - bool bSSE2; - bool bSSE3; - bool bSSSE3; - bool bPOPCNT; - bool bSSE4_1; - bool bSSE4_2; - bool bLZCNT; - bool bSSE4A; - bool bAVX; - bool bAES; - bool bLAHFSAHF64; - bool bLongMode; - - // ARM specific CPUInfo - bool bSwp; - bool bHalf; - bool bThumb; - bool bFastMult; - bool bVFP; - bool bEDSP; - bool bThumbEE; - bool bNEON; - bool bVFPv3; - bool bTLS; - bool bVFPv4; - bool bIDIVa; - bool bIDIVt; - bool bArmV7; // enable MOVT, MOVW etc - - // ARMv8 specific - bool bFP; - bool bASIMD; - - // Call Detect() - explicit CPUInfo(); - - // Turn the cpu info into a string we can show - std::string Summarize(); - -private: - // Detects the various cpu features - void Detect(); -}; - -extern CPUInfo cpu_info; - -#endif // _CPUDETECT_H_ diff --git a/src/common/src/debug_interface.h b/src/common/src/debug_interface.h deleted file mode 100644 index 49cc54a8..00000000 --- a/src/common/src/debug_interface.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _DEBUGINTERFACE_H -#define _DEBUGINTERFACE_H - -#include -#include - -class DebugInterface -{ -protected: - virtual ~DebugInterface() {} - -public: - virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual int getInstructionSize(int /*instruction*/) {return 1;} - virtual bool isAlive() {return true;} - virtual bool isBreakpoint(unsigned int /*address*/) {return false;} - virtual void setBreakpoint(unsigned int /*address*/){} - virtual void clearBreakpoint(unsigned int /*address*/){} - virtual void clearAllBreakpoints() {} - virtual void toggleBreakpoint(unsigned int /*address*/){} - virtual bool isMemCheck(unsigned int /*address*/) {return false;} - virtual void toggleMemCheck(unsigned int /*address*/){} - virtual unsigned int readMemory(unsigned int /*address*/){return 0;} - virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} - virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} - virtual unsigned int readInstruction(unsigned int /*address*/){return 0;} - virtual unsigned int getPC() {return 0;} - virtual void setPC(unsigned int /*address*/) {} - virtual void step() {} - virtual void runToBreakpoint() {} - virtual void breakNow() {} - virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} - virtual void showJitResults(unsigned int /*address*/) {}; - virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} - virtual std::string getDescription(unsigned int /*address*/) = 0; -}; - -#endif diff --git a/src/common/src/emu_window.h b/src/common/src/emu_window.h deleted file mode 100644 index f4936705..00000000 --- a/src/common/src/emu_window.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file emu_window.h - * @author Neobrain - * @date 2012-06-01 - * @brief Interface for implementing an emulator window manager - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#ifndef CORE_EMUWINDOW_H_ -#define CORE_EMUWINDOW_H_ - -#include "common.h" - -//namespace input_common -//{ -//class KeyboardInput; -//} - -// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, -// QGLWidget, GLFW, etc...) -class EmuWindow -{ - -public: - /// Data structure to store an emuwindow configuration - struct Config{ - bool fullscreen; - int res_width; - int res_height; - }; - - /// Swap buffers to display the next frame - virtual void SwapBuffers() = 0; - - /// Polls window events - virtual void PollEvents() = 0; - - /// Makes the graphics context current for the caller thread - virtual void MakeCurrent() = 0; - - /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - virtual void DoneCurrent() = 0; - - /** - * @brief Called from KeyboardInput constructor to notify EmuWindow about its presence - * @param controller_interface Pointer to a running KeyboardInput interface - */ - //void set_controller_interface(input_common::KeyboardInput* controller_interface) { - // controller_interface_ = controller_interface; - //} - //input_common::KeyboardInput* controller_interface() { return controller_interface_; } - - Config config() { return config_; } - void set_config(Config val) { config_ = val; } - - int client_area_width() { return client_area_width_; } - void set_client_area_width(int val) { client_area_width_ = val; } - - int client_area_height() { return client_area_height_; } - void set_client_area_height(int val) { client_area_height_ = val; } - - std::string window_title() { return window_title_; } - void set_window_title(std::string val) { window_title_ = val; } - -protected: - EmuWindow() : client_area_width_(640), client_area_height_(480) { - char window_title[255]; - sprintf(window_title, "citra [%s|%s] - %s", - "null-cpu", - "null-renderer", - __DATE__); - window_title_ = window_title; - } - virtual ~EmuWindow() {} - - std::string window_title_; ///< Current window title, should be used by window impl. - - int client_area_width_; ///< Current client width, should be set by window impl. - int client_area_height_; ///< Current client height, should be set by window impl. - -private: - Config config_; ///< Internal configuration - -}; - -#endif // CORE_EMUWINDOW_H_ diff --git a/src/common/src/extended_trace.cpp b/src/common/src/extended_trace.cpp deleted file mode 100644 index 9f717dba..00000000 --- a/src/common/src/extended_trace.cpp +++ /dev/null @@ -1,433 +0,0 @@ -// -------------------------------------------------------------------------------------- -// -// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com -// For companies(Austin,TX): If you would like to get my resume, send an email. -// -// The source is free, but if you want to use it, mention my name and e-mail address -// -// History: -// 1.0 Initial version Zoltan Csizmadia -// 1.1 WhineCube version Masken -// 1.2 Dolphin version Masken -// -// -------------------------------------------------------------------------------------- - -#if defined(WIN32) - -#include -#include -#include "extended_trace.h" -#include "string_util.h" -using namespace std; - -#include -#include - -#define BUFFERSIZE 0x200 -#pragma warning(disable:4996) - -// Unicode safe char* -> TCHAR* conversion -void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) -{ -#if defined(UNICODE)||defined(_UNICODE) - ULONG index = 0; - PCSTR lpAct = lpszIn; - - for( ; ; lpAct++ ) - { - lpszOut[index++] = (TCHAR)(*lpAct); - if ( *lpAct == 0 ) - break; - } -#else - // This is trivial :) - strcpy( lpszOut, lpszIn ); -#endif -} - -// Let's figure out the path for the symbol files -// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath -// Note: There is no size check for lpszSymbolPath! -static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath ) -{ - CHAR lpszPath[BUFFERSIZE]; - - // Creating the default path - // ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" - strcpy( lpszSymbolPath, "." ); - - // environment variable _NT_SYMBOL_PATH - if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - } - - // environment variable _NT_ALTERNATE_SYMBOL_PATH - if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - } - - // environment variable SYSTEMROOT - if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - strcat( lpszSymbolPath, ";" ); - - // SYSTEMROOT\System32 - strcat( lpszSymbolPath, lpszPath ); - strcat( lpszSymbolPath, "\\System32" ); - } - - // Add user defined path - if ( lpszIniPath != NULL ) - if ( lpszIniPath[0] != '\0' ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszIniPath ); - } -} - -// Uninitialize the loaded symbol files -BOOL UninitSymInfo() { - return SymCleanup( GetCurrentProcess() ); -} - -// Initializes the symbol files -BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) -{ - CHAR lpszSymbolPath[BUFFERSIZE]; - DWORD symOptions = SymGetOptions(); - - symOptions |= SYMOPT_LOAD_LINES; - symOptions &= ~SYMOPT_UNDNAME; - SymSetOptions( symOptions ); - InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); - - return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE); -} - -// Get the module name from a given address -static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) -{ - BOOL ret = FALSE; - IMAGEHLP_MODULE moduleInfo; - - ::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); - moduleInfo.SizeOfStruct = sizeof(moduleInfo); - - if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) - { - // Got it! - PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule ); - ret = TRUE; - } - else - // Not found :( - _tcscpy( lpszModule, _T("?") ); - - return ret; -} - -// Get function prototype and parameter info from ip address and stack address -static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) -{ - BOOL ret = FALSE; - DWORD dwSymSize = 10000; - TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); - CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; - LPTSTR lpszParamSep = NULL; - LPTSTR lpszParsed = lpszUnDSymbol; - PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize ); - - ::ZeroMemory( pSym, dwSymSize ); - pSym->SizeOfStruct = dwSymSize; - pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL); - - // Set the default to unknown - _tcscpy( lpszSymbol, _T("?") ); - - // Get symbol info for IP -#ifndef _M_X64 - DWORD dwDisp = 0; - if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) -#else - //makes it compile but hell im not sure if this works... - DWORD64 dwDisp = 0; - if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) -#endif - { - // Make the symbol readable for humans - UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, - UNDNAME_COMPLETE | - UNDNAME_NO_THISTYPE | - UNDNAME_NO_SPECIAL_SYMS | - UNDNAME_NO_MEMBER_TYPE | - UNDNAME_NO_MS_KEYWORDS | - UNDNAME_NO_ACCESS_SPECIFIERS ); - - // Symbol information is ANSI string - PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol ); - - // I am just smarter than the symbol file :) - if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("mainCRTStartup()")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()")); - - lpszSymbol[0] = _T('\0'); - - // Let's go through the stack, and modify the function prototype, and insert the actual - // parameter values from the stack - if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL) - { - ULONG index = 0; - for( ; ; index++ ) - { - lpszParamSep = _tcschr( lpszParsed, _T(',') ); - if ( lpszParamSep == NULL ) - break; - - *lpszParamSep = _T('\0'); - - _tcscat( lpszSymbol, lpszParsed ); - _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) ); - - lpszParsed = lpszParamSep + 1; - } - - lpszParamSep = _tcschr( lpszParsed, _T(')') ); - if ( lpszParamSep != NULL ) - { - *lpszParamSep = _T('\0'); - - _tcscat( lpszSymbol, lpszParsed ); - _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) ); - - lpszParsed = lpszParamSep + 1; - } - } - - _tcscat( lpszSymbol, lpszParsed ); - - ret = TRUE; - } - GlobalFree( pSym ); - - return ret; -} - -// Get source file name and line number from IP address -// The output format is: "sourcefile(linenumber)" or -// "modulename!address" or -// "address" -static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ) -{ - BOOL ret = FALSE; - IMAGEHLP_LINE lineInfo; - DWORD dwDisp; - TCHAR lpszFileName[BUFFERSIZE] = _T(""); - TCHAR lpModuleInfo[BUFFERSIZE] = _T(""); - - _tcscpy( lpszSourceInfo, _T("?(?)") ); - - ::ZeroMemory( &lineInfo, sizeof( lineInfo ) ); - lineInfo.SizeOfStruct = sizeof( lineInfo ); - - if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) ) - { - // Got it. Let's use "sourcefile(linenumber)" format - PCSTR2LPTSTR( lineInfo.FileName, lpszFileName ); - TCHAR fname[_MAX_FNAME]; - TCHAR ext[_MAX_EXT]; - _tsplitpath(lpszFileName, NULL, NULL, fname, ext); - _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber ); - ret = TRUE; - } - else - { - // There is no source file information. :( - // Let's use the "modulename!address" format - GetModuleNameFromAddress( address, lpModuleInfo ); - - if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0')) - // There is no modulename information. :(( - // Let's use the "address" format - _stprintf( lpszSourceInfo, _T("0x%08X"), address ); - else - _stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address ); - - ret = FALSE; - } - - return ret; -} - -void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) -{ - TCHAR symInfo[BUFFERSIZE] = _T("?"); - TCHAR srcInfo[BUFFERSIZE] = _T("?"); - - GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); - GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); - etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); -} - -void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) -{ - STACKFRAME callStack; - BOOL bResult; - CONTEXT context; - HANDLE hProcess = GetCurrentProcess(); - - // If it's not this thread, let's suspend it, and resume it at the end - if ( hThread != GetCurrentThread() ) - if ( SuspendThread( hThread ) == -1 ) - { - // whaaat ?! - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &context, sizeof(context) ); - context.ContextFlags = CONTEXT_FULL; - - if ( !GetThreadContext( hThread, &context ) ) - { - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &callStack, sizeof(callStack) ); -#ifndef _M_X64 - callStack.AddrPC.Offset = context.Eip; - callStack.AddrStack.Offset = context.Esp; - callStack.AddrFrame.Offset = context.Ebp; -#else - callStack.AddrPC.Offset = context.Rip; - callStack.AddrStack.Offset = context.Rsp; - callStack.AddrFrame.Offset = context.Rbp; -#endif - callStack.AddrPC.Mode = AddrModeFlat; - callStack.AddrStack.Mode = AddrModeFlat; - callStack.AddrFrame.Mode = AddrModeFlat; - - etfprint(file, "Call stack info: \n"); - etfprint(file, lpszMessage); - - PrintFunctionAndSourceInfo(file, callStack); - - for( ULONG index = 0; ; index++ ) - { - bResult = StackWalk( - IMAGE_FILE_MACHINE_I386, - hProcess, - hThread, - &callStack, - NULL, - NULL, - SymFunctionTableAccess, - SymGetModuleBase, - NULL); - - if ( index == 0 ) - continue; - - if( !bResult || callStack.AddrFrame.Offset == 0 ) - break; - - PrintFunctionAndSourceInfo(file, callStack); - - } - - if ( hThread != GetCurrentThread() ) - ResumeThread( hThread ); -} - -void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) -{ - STACKFRAME callStack; - BOOL bResult; - TCHAR symInfo[BUFFERSIZE] = _T("?"); - TCHAR srcInfo[BUFFERSIZE] = _T("?"); - HANDLE hProcess = GetCurrentProcess(); - - // If it's not this thread, let's suspend it, and resume it at the end - if ( hThread != GetCurrentThread() ) - if ( SuspendThread( hThread ) == -1 ) - { - // whaaat ?! - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &callStack, sizeof(callStack) ); - callStack.AddrPC.Offset = eip; - callStack.AddrStack.Offset = esp; - callStack.AddrFrame.Offset = ebp; - callStack.AddrPC.Mode = AddrModeFlat; - callStack.AddrStack.Mode = AddrModeFlat; - callStack.AddrFrame.Mode = AddrModeFlat; - - etfprint(file, "Call stack info: \n"); - etfprint(file, lpszMessage); - - PrintFunctionAndSourceInfo(file, callStack); - - for( ULONG index = 0; ; index++ ) - { - bResult = StackWalk( - IMAGE_FILE_MACHINE_I386, - hProcess, - hThread, - &callStack, - NULL, - NULL, - SymFunctionTableAccess, - SymGetModuleBase, - NULL); - - if ( index == 0 ) - continue; - - if( !bResult || callStack.AddrFrame.Offset == 0 ) - break; - - PrintFunctionAndSourceInfo(file, callStack); - } - - if ( hThread != GetCurrentThread() ) - ResumeThread( hThread ); -} - -char g_uefbuf[2048]; - -void etfprintf(FILE *file, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int len = vsprintf(g_uefbuf, format, ap); - fwrite(g_uefbuf, 1, len, file); - va_end(ap); -} - -void etfprint(FILE *file, const std::string &text) -{ - size_t len = text.length(); - fwrite(text.data(), 1, len, file); -} - -#endif //WIN32 diff --git a/src/common/src/extended_trace.h b/src/common/src/extended_trace.h deleted file mode 100644 index 1552e901..00000000 --- a/src/common/src/extended_trace.h +++ /dev/null @@ -1,53 +0,0 @@ -// ----------------------------------------------------------------------------------------- -// -// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com -// For companies(Austin,TX): If you would like to get my resume, send an email. -// -// The source is free, but if you want to use it, mention my name and e-mail address -// -// History: -// 1.0 Initial version Zoltan Csizmadia -// 1.1 WhineCube version Masken -// 1.2 Dolphin version Masken -// -// ---------------------------------------------------------------------------------------- - -#ifndef _EXTENDEDTRACE_H_INCLUDED_ -#define _EXTENDEDTRACE_H_INCLUDED_ - -#if defined(WIN32) - -#include -#include - -#include - -#pragma comment( lib, "imagehlp.lib" ) - -#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath ) -#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() -#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file) -#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp) -// class File; - -BOOL InitSymInfo( PCSTR ); -BOOL UninitSymInfo(); -void StackTrace(HANDLE, char const* msg, FILE *file); -void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp); - -// functions by Masken -void etfprintf(FILE *file, const char *format, ...); -void etfprint(FILE *file, const std::string &text); -#define UEFBUFSIZE 2048 -extern char g_uefbuf[UEFBUFSIZE]; - -#else // not WIN32 - -#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) -#define EXTENDEDTRACEUNINITIALIZE() ((void)0) -#define STACKTRACE(file) ((void)0) -#define STACKTRACE2(file, eip, esp, ebp) ((void)0) - -#endif // WIN32 - -#endif // _EXTENDEDTRACE_H_INCLUDED_ diff --git a/src/common/src/fifo_queue.h b/src/common/src/fifo_queue.h deleted file mode 100644 index 57efcd83..00000000 --- a/src/common/src/fifo_queue.h +++ /dev/null @@ -1,115 +0,0 @@ - -#ifndef _FIFO_QUEUE_H_ -#define _FIFO_QUEUE_H_ - -// a simple lockless thread-safe, -// single reader, single writer queue - -#include "atomic.h" - -namespace Common -{ - -template -class FifoQueue -{ -public: - FifoQueue() : m_size(0) - { - m_write_ptr = m_read_ptr = new ElementPtr(); - } - - ~FifoQueue() - { - // this will empty out the whole queue - delete m_read_ptr; - } - - u32 Size() const - { - return m_size; - } - - bool Empty() const - { - //return (m_read_ptr == m_write_ptr); - return (0 == m_size); - } - - T& Front() const - { - return *m_read_ptr->current; - } - - template - void Push(Arg&& t) - { - // create the element, add it to the queue - m_write_ptr->current = new T(std::forward(t)); - // set the next pointer to a new element ptr - // then advance the write pointer - m_write_ptr = m_write_ptr->next = new ElementPtr(); - Common::AtomicIncrement(m_size); - } - - void Pop() - { - Common::AtomicDecrement(m_size); - ElementPtr *const tmpptr = m_read_ptr; - // advance the read pointer - m_read_ptr = m_read_ptr->next; - // set the next element to NULL to stop the recursive deletion - tmpptr->next = NULL; - delete tmpptr; // this also deletes the element - } - - bool Pop(T& t) - { - if (Empty()) - return false; - - t = std::move(Front()); - Pop(); - - return true; - } - - // not thread-safe - void Clear() - { - m_size = 0; - delete m_read_ptr; - m_write_ptr = m_read_ptr = new ElementPtr(); - } - -private: - // stores a pointer to element - // and a pointer to the next ElementPtr - class ElementPtr - { - public: - ElementPtr() : current(NULL), next(NULL) {} - - ~ElementPtr() - { - if (current) - { - delete current; - // recusion ftw - if (next) - delete next; - } - } - - T *volatile current; - ElementPtr *volatile next; - }; - - ElementPtr *volatile m_write_ptr; - ElementPtr *volatile m_read_ptr; - volatile u32 m_size; -}; - -} - -#endif diff --git a/src/common/src/file_search.cpp b/src/common/src/file_search.cpp deleted file mode 100644 index 59f64010..00000000 --- a/src/common/src/file_search.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "common_paths.h" -#ifndef _WIN32 -#include -#include -#else -#include -#endif - -#include -#include - -#include "file_search.h" - -#include "string_util.h" - - -CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories) -{ - // Reverse the loop order for speed? - for (size_t j = 0; j < _rSearchStrings.size(); j++) - { - for (size_t i = 0; i < _rDirectories.size(); i++) - { - FindFiles(_rSearchStrings[j], _rDirectories[i]); - } - } -} - - -void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) -{ - std::string GCMSearchPath; - BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); -#ifdef _WIN32 - WIN32_FIND_DATA findData; - HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); - - if (FindFirst != INVALID_HANDLE_VALUE) - { - bool bkeepLooping = true; - - while (bkeepLooping) - { - if (findData.cFileName[0] != '.') - { - std::string strFilename; - BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); - m_FileNames.push_back(strFilename); - } - - bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false; - } - } - FindClose(FindFirst); - - -#else - // TODO: super lame/broken - - auto end_match(_searchString); - - // assuming we have a "*.blah"-like pattern - if (!end_match.empty() && end_match[0] == '*') - end_match.erase(0, 1); - - // ugly - if (end_match == ".*") - end_match.clear(); - - DIR* dir = opendir(_strPath.c_str()); - - if (!dir) - return; - - while (auto const dp = readdir(dir)) - { - std::string found(dp->d_name); - - if ((found != ".") && (found != "..") - && (found.size() >= end_match.size()) - && std::equal(end_match.rbegin(), end_match.rend(), found.rbegin())) - { - std::string full_name; - if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR) - full_name = _strPath + found; - else - full_name = _strPath + DIR_SEP + found; - - m_FileNames.push_back(full_name); - } - } - - closedir(dir); -#endif -} - -const CFileSearch::XStringVector& CFileSearch::GetFileNames() const -{ - return m_FileNames; -} diff --git a/src/common/src/file_search.h b/src/common/src/file_search.h deleted file mode 100644 index 2a9ff801..00000000 --- a/src/common/src/file_search.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FILESEARCH_H_ -#define _FILESEARCH_H_ - -#include -#include - -class CFileSearch -{ -public: - typedef std::vectorXStringVector; - - CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories); - const XStringVector& GetFileNames() const; - -private: - - void FindFiles(const std::string& _searchString, const std::string& _strPath); - - XStringVector m_FileNames; -}; - -#endif // _FILESEARCH_H_ - diff --git a/src/common/src/file_util.cpp b/src/common/src/file_util.cpp deleted file mode 100644 index 8b47cb3e..00000000 --- a/src/common/src/file_util.cpp +++ /dev/null @@ -1,910 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "common_paths.h" -#include "file_util.h" -#include "string_util.h" - -#ifdef _WIN32 -#include -#include // for SHGetFolderPath -#include -#include // for GetSaveFileName -#include -#include // getcwd -#else -#include -#include -#include -#include -#include -#endif - -#if defined(__APPLE__) -#include -#include -#include -#endif - -#include -#include - -#include "string_util.h" - -#ifndef S_ISDIR -#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) -#endif - -#ifdef BSD4_4 -#define stat64 stat -#define fstat64 fstat -#endif - -// This namespace has various generic functions related to files and paths. -// The code still needs a ton of cleanup. -// REMEMBER: strdup considered harmful! -namespace File -{ - -// Remove any ending forward slashes from directory paths -// Modifies argument. -static void StripTailDirSlashes(std::string &fname) -{ - if (fname.length() > 1) - { - size_t i = fname.length() - 1; - while (fname[i] == DIR_SEP_CHR) - fname[i--] = '\0'; - } - return; -} - -// Returns true if file filename exists -bool Exists(const std::string &filename) -{ - struct stat64 file_info; - - std::string copy(filename); - StripTailDirSlashes(copy); - -#ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); -#else - int result = stat64(copy.c_str(), &file_info); -#endif - - return (result == 0); -} - -// Returns true if filename is a directory -bool IsDirectory(const std::string &filename) -{ - struct stat64 file_info; - - std::string copy(filename); - StripTailDirSlashes(copy); - -#ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); -#else - int result = stat64(copy.c_str(), &file_info); -#endif - - if (result < 0) { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } - - return S_ISDIR(file_info.st_mode); -} - -// Deletes a given filename, return true on success -// Doesn't supports deleting a directory -bool Delete(const std::string &filename) -{ - INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); - - // Return true because we care about the file no - // being there, not the actual delete. - if (!Exists(filename)) - { - WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); - return true; - } - - // We can't delete a directory - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); - return false; - } - -#ifdef _WIN32 - if (!DeleteFile(UTF8ToTStr(filename).c_str())) - { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } -#else - if (unlink(filename.c_str()) == -1) { - WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } -#endif - - return true; -} - -// Returns true if successful, or path already exists. -bool CreateDir(const std::string &path) -{ - INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); -#ifdef _WIN32 - if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) - return true; - DWORD error = GetLastError(); - if (error == ERROR_ALREADY_EXISTS) - { - WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); - return true; - } - ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error); - return false; -#else - if (mkdir(path.c_str(), 0755) == 0) - return true; - - int err = errno; - - if (err == EEXIST) - { - WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); - return true; - } - - ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); - return false; -#endif -} - -// Creates the full path of fullPath returns true on success -bool CreateFullPath(const std::string &fullPath) -{ - int panicCounter = 100; - INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - - if (File::Exists(fullPath)) - { - INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); - return true; - } - - size_t position = 0; - while (true) - { - // Find next sub path - position = fullPath.find(DIR_SEP_CHR, position); - - // we're done, yay! - if (position == fullPath.npos) - return true; - - // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") - std::string const subPath(fullPath.substr(0, position + 1)); - if (!File::IsDirectory(subPath)) - File::CreateDir(subPath); - - // A safety check - panicCounter--; - if (panicCounter <= 0) - { - ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); - return false; - } - position++; - } -} - - -// Deletes a directory filename, returns true on success -bool DeleteDir(const std::string &filename) -{ - INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); - - // check if a directory - if (!File::IsDirectory(filename)) - { - ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); - return false; - } - -#ifdef _WIN32 - if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) - return true; -#else - if (rmdir(filename.c_str()) == 0) - return true; -#endif - ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); - - return false; -} - -// renames file srcFilename to destFilename, returns true on success -bool Rename(const std::string &srcFilename, const std::string &destFilename) -{ - INFO_LOG(COMMON, "Rename: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); - if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) - return true; - ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; -} - -// copies file srcFilename to destFilename, returns true on success -bool Copy(const std::string &srcFilename, const std::string &destFilename) -{ - INFO_LOG(COMMON, "Copy: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); -#ifdef _WIN32 - if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) - return true; - - ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; -#else - - // buffer size -#define BSIZE 1024 - - char buffer[BSIZE]; - - // Open input file - FILE *input = fopen(srcFilename.c_str(), "rb"); - if (!input) - { - ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; - } - - // open output file - FILE *output = fopen(destFilename.c_str(), "wb"); - if (!output) - { - fclose(input); - ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; - } - - // copy loop - while (!feof(input)) - { - // read input - int rnum = fread(buffer, sizeof(char), BSIZE, input); - if (rnum != BSIZE) - { - if (ferror(input) != 0) - { - ERROR_LOG(COMMON, - "Copy: failed reading from source, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - goto bail; - } - } - - // write output - int wnum = fwrite(buffer, sizeof(char), rnum, output); - if (wnum != rnum) - { - ERROR_LOG(COMMON, - "Copy: failed writing to output, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - goto bail; - } - } - // close files - fclose(input); - fclose(output); - return true; -bail: - if (input) - fclose(input); - if (output) - fclose(output); - return false; -#endif -} - -// Returns the size of filename (64bit) -u64 GetSize(const std::string &filename) -{ - if (!Exists(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); - return 0; - } - - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); - return 0; - } - - struct stat64 buf; -#ifdef _WIN32 - if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) -#else - if (stat64(filename.c_str(), &buf) == 0) -#endif - { - DEBUG_LOG(COMMON, "GetSize: %s: %lld", - filename.c_str(), (long long)buf.st_size); - return buf.st_size; - } - - ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", - filename.c_str(), GetLastErrorMsg()); - return 0; -} - -// Overloaded GetSize, accepts file descriptor -u64 GetSize(const int fd) -{ - struct stat64 buf; - if (fstat64(fd, &buf) != 0) { - ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", - fd, GetLastErrorMsg()); - return 0; - } - return buf.st_size; -} - -// Overloaded GetSize, accepts FILE* -u64 GetSize(FILE *f) -{ - // can't use off_t here because it can be 32-bit - u64 pos = ftello(f); - if (fseeko(f, 0, SEEK_END) != 0) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); - return 0; - } - u64 size = ftello(f); - if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); - return 0; - } - return size; -} - -// creates an empty file filename, returns true on success -bool CreateEmptyFile(const std::string &filename) -{ - INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - - if (!File::IOFile(filename, "wb")) - { - ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } - - return true; -} - - -// Scans the directory tree gets, starting from _Directory and adds the -// results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) -{ - INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); - // How many files + directories we found - u32 foundEntries = 0; -#ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; - - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return foundEntries; - } - // windows loop - do - { - FSTEntry entry; - const std::string virtualName(TStrToUTF8(ffd.cFileName)); -#else - struct dirent dirent, *result = NULL; - - DIR *dirp = opendir(directory.c_str()); - if (!dirp) - return 0; - - // non windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - FSTEntry entry; - const std::string virtualName(result->d_name); -#endif - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; - entry.virtualName = virtualName; - entry.physicalName = directory; - entry.physicalName += DIR_SEP + entry.virtualName; - - if (IsDirectory(entry.physicalName.c_str())) - { - entry.isDirectory = true; - // is a directory, lets go inside - entry.size = ScanDirectoryTree(entry.physicalName, entry); - foundEntries += (u32)entry.size; - } - else - { // is a file - entry.isDirectory = false; - entry.size = GetSize(entry.physicalName.c_str()); - } - ++foundEntries; - // Push into the tree - parentEntry.children.push_back(entry); -#ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); -#else - } - closedir(dirp); -#endif - // Return number of entries found. - return foundEntries; -} - - -// Deletes the given directory and anything under it. Returns true on success. -bool DeleteDirRecursively(const std::string &directory) -{ - INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); -#ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return false; - } - - // windows loop - do - { - const std::string virtualName(TStrToUTF8(ffd.cFileName)); -#else - struct dirent dirent, *result = NULL; - DIR *dirp = opendir(directory.c_str()); - if (!dirp) - return false; - - // non windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtualName = result->d_name; -#endif - - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; - - std::string newPath = directory + DIR_SEP_CHR + virtualName; - if (IsDirectory(newPath)) - { - if (!DeleteDirRecursively(newPath)) - { - #ifndef _WIN32 - closedir(dirp); - #endif - - return false; - } - } - else - { - if (!File::Delete(newPath)) - { - #ifndef _WIN32 - closedir(dirp); - #endif - - return false; - } - } - -#ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); -#else - } - closedir(dirp); -#endif - File::DeleteDir(directory); - - return true; -} - -// Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string &source_path, const std::string &dest_path) -{ -#ifndef _WIN32 - if (source_path == dest_path) return; - if (!File::Exists(source_path)) return; - if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); - - struct dirent dirent, *result = NULL; - DIR *dirp = opendir(source_path.c_str()); - if (!dirp) return; - - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtualName(result->d_name); - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; - - std::string source, dest; - source = source_path + virtualName; - dest = dest_path + virtualName; - if (IsDirectory(source)) - { - source += '/'; - dest += '/'; - if (!File::Exists(dest)) File::CreateFullPath(dest); - CopyDir(source, dest); - } - else if (!File::Exists(dest)) File::Copy(source, dest); - } - closedir(dirp); -#endif -} - -// Returns the current directory -std::string GetCurrentDir() -{ - char *dir; - // Get the current working directory (getcwd uses malloc) - if (!(dir = __getcwd(NULL, 0))) { - - ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", - GetLastErrorMsg()); - return NULL; - } - std::string strDir = dir; - free(dir); - return strDir; -} - -// Sets the current directory to the given directory -bool SetCurrentDir(const std::string &directory) -{ - return __chdir(directory.c_str()) == 0; -} - -#if defined(__APPLE__) -std::string GetBundleDirectory() -{ - CFURLRef BundleRef; - char AppBundlePath[MAXPATHLEN]; - // Get the main bundle for the app - BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); - CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); - CFRelease(BundleRef); - CFRelease(BundlePath); - - return AppBundlePath; -} -#endif - -#ifdef _WIN32 -std::string& GetExeDirectory() -{ - static std::string DolphinPath; - if (DolphinPath.empty()) - { - TCHAR Dolphin_exe_Path[2048]; - GetModuleFileName(NULL, Dolphin_exe_Path, 2048); - DolphinPath = TStrToUTF8(Dolphin_exe_Path); - DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); - } - return DolphinPath; -} -#endif - -std::string GetSysDirectory() -{ - std::string sysDir; - -#if defined (__APPLE__) - sysDir = GetBundleDirectory(); - sysDir += DIR_SEP; - sysDir += SYSDATA_DIR; -#else - sysDir = SYSDATA_DIR; -#endif - sysDir += DIR_SEP; - - INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); - return sysDir; -} - -// Returns a string with a Dolphin data dir or file in the user's home -// directory. To be used in "multi-user" mode (that is, installed). -const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) -{ - static std::string paths[NUM_PATH_INDICES]; - - // Set up all paths and files on the first run - if (paths[D_USER_IDX].empty()) - { -#ifdef _WIN32 - paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; -#else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) - paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; - else - paths[D_USER_IDX] = std::string(getenv("HOME") ? - getenv("HOME") : getenv("PWD") ? - getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; -#endif - - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; - paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; - paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; - paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - } - - if (!newPath.empty()) - { - if (!File::IsDirectory(newPath)) - { - WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); - return paths[DirIDX]; - } - else - { - paths[DirIDX] = newPath; - } - - switch (DirIDX) - { - case D_ROOT_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; - paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; - break; - - case D_USER_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; - paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; - paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; - paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - break; - - case D_CONFIG_IDX: - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - break; - - case D_DUMP_IDX: - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - break; - - case D_LOGS_IDX: - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - } - } - - return paths[DirIDX]; -} - -//std::string GetThemeDir(const std::string& theme_name) -//{ -// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; -// -//#if !defined(_WIN32) -// // If theme does not exist in user's dir load from shared directory -// if (!File::Exists(dir)) -// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; -//#endif -// -// return dir; -//} - -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) -{ - return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); -} - -bool ReadFileToString(bool text_file, const char *filename, std::string &str) -{ - File::IOFile file(filename, text_file ? "r" : "rb"); - auto const f = file.GetHandle(); - - if (!f) - return false; - - str.resize(static_cast(GetSize(f))); - return file.ReadArray(&str[0], str.size()); -} - -IOFile::IOFile() - : m_file(NULL), m_good(true) -{} - -IOFile::IOFile(std::FILE* file) - : m_file(file), m_good(true) -{} - -IOFile::IOFile(const std::string& filename, const char openmode[]) - : m_file(NULL), m_good(true) -{ - Open(filename, openmode); -} - -IOFile::~IOFile() -{ - Close(); -} - -IOFile::IOFile(IOFile&& other) - : m_file(NULL), m_good(true) -{ - Swap(other); -} - -IOFile& IOFile::operator=(IOFile&& other) -{ - Swap(other); - return *this; -} - -void IOFile::Swap(IOFile& other) -{ - std::swap(m_file, other.m_file); - std::swap(m_good, other.m_good); -} - -bool IOFile::Open(const std::string& filename, const char openmode[]) -{ - Close(); -#ifdef _WIN32 - _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); -#else - m_file = fopen(filename.c_str(), openmode); -#endif - - m_good = IsOpen(); - return m_good; -} - -bool IOFile::Close() -{ - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; - - m_file = NULL; - return m_good; -} - -std::FILE* IOFile::ReleaseHandle() -{ - std::FILE* const ret = m_file; - m_file = NULL; - return ret; -} - -void IOFile::SetHandle(std::FILE* file) -{ - Close(); - Clear(); - m_file = file; -} - -u64 IOFile::GetSize() -{ - if (IsOpen()) - return File::GetSize(m_file); - else - return 0; -} - -bool IOFile::Seek(s64 off, int origin) -{ - if (!IsOpen() || 0 != fseeko(m_file, off, origin)) - m_good = false; - - return m_good; -} - -u64 IOFile::Tell() -{ - if (IsOpen()) - return ftello(m_file); - else - return -1; -} - -bool IOFile::Flush() -{ - if (!IsOpen() || 0 != std::fflush(m_file)) - m_good = false; - - return m_good; -} - -bool IOFile::Resize(u64 size) -{ - if (!IsOpen() || 0 != -#ifdef _WIN32 - // ector: _chsize sucks, not 64-bit safe - // F|RES: changed to _chsize_s. i think it is 64-bit safe - _chsize_s(_fileno(m_file), size) -#else - // TODO: handle 64bit and growing - ftruncate(fileno(m_file), size) -#endif - ) - m_good = false; - - return m_good; -} - -} // namespace diff --git a/src/common/src/file_util.h b/src/common/src/file_util.h deleted file mode 100644 index f4ef949d..00000000 --- a/src/common/src/file_util.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FILEUTIL_H_ -#define _FILEUTIL_H_ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "string_util.h" - -// User directory indices for GetUserPath -enum { - D_USER_IDX, - D_ROOT_IDX, - D_CONFIG_IDX, - D_GAMECONFIG_IDX, - D_MAPS_IDX, - D_CACHE_IDX, - D_SHADERCACHE_IDX, - D_SHADERS_IDX, - D_STATESAVES_IDX, - D_SCREENSHOTS_IDX, - D_HIRESTEXTURES_IDX, - D_DUMP_IDX, - D_DUMPFRAMES_IDX, - D_DUMPAUDIO_IDX, - D_DUMPTEXTURES_IDX, - D_DUMPDSP_IDX, - D_LOGS_IDX, - D_SYSCONF_IDX, - F_EMUCONFIG_IDX, - F_DEBUGGERCONFIG_IDX, - F_LOGGERCONFIG_IDX, - F_MAINLOG_IDX, - F_RAMDUMP_IDX, - F_ARAMDUMP_IDX, - F_SYSCONF_IDX, - NUM_PATH_INDICES -}; - -namespace File -{ - -// FileSystem tree node/ -struct FSTEntry -{ - bool isDirectory; - u64 size; // file length or number of entries from children - std::string physicalName; // name on disk - std::string virtualName; // name in FST names table - std::vector children; -}; - -// Returns true if file filename exists -bool Exists(const std::string &filename); - -// Returns true if filename is a directory -bool IsDirectory(const std::string &filename); - -// Returns the size of filename (64bit) -u64 GetSize(const std::string &filename); - -// Overloaded GetSize, accepts file descriptor -u64 GetSize(const int fd); - -// Overloaded GetSize, accepts FILE* -u64 GetSize(FILE *f); - -// Returns true if successful, or path already exists. -bool CreateDir(const std::string &filename); - -// Creates the full path of fullPath returns true on success -bool CreateFullPath(const std::string &fullPath); - -// Deletes a given filename, return true on success -// Doesn't supports deleting a directory -bool Delete(const std::string &filename); - -// Deletes a directory filename, returns true on success -bool DeleteDir(const std::string &filename); - -// renames file srcFilename to destFilename, returns true on success -bool Rename(const std::string &srcFilename, const std::string &destFilename); - -// copies file srcFilename to destFilename, returns true on success -bool Copy(const std::string &srcFilename, const std::string &destFilename); - -// creates an empty file filename, returns true on success -bool CreateEmptyFile(const std::string &filename); - -// Scans the directory tree gets, starting from _Directory and adds the -// results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry); - -// deletes the given directory and anything under it. Returns true on success. -bool DeleteDirRecursively(const std::string &directory); - -// Returns the current directory -std::string GetCurrentDir(); - -// Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string &source_path, const std::string &dest_path); - -// Set the current directory to given directory -bool SetCurrentDir(const std::string &directory); - -// Returns a pointer to a string with a Dolphin data dir in the user's home -// directory. To be used in "multi-user" mode (that is, installed). -const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); - -// probably doesn't belong here -//std::string GetThemeDir(const std::string& theme_name); - -// Returns the path to where the sys file are -std::string GetSysDirectory(); - -#ifdef __APPLE__ -std::string GetBundleDirectory(); -#endif - -#ifdef _WIN32 -std::string &GetExeDirectory(); -#endif - -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); -bool ReadFileToString(bool text_file, const char *filename, std::string &str); - -// simple wrapper for cstdlib file functions to -// hopefully will make error checking easier -// and make forgetting an fclose() harder -class IOFile : public NonCopyable -{ -public: - IOFile(); - IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); - - ~IOFile(); - - IOFile(IOFile&& other); - IOFile& operator=(IOFile&& other); - - void Swap(IOFile& other); - - bool Open(const std::string& filename, const char openmode[]); - bool Close(); - - template - bool ReadArray(T* data, size_t length) - { - if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) - m_good = false; - - return m_good; - } - - template - bool WriteArray(const T* data, size_t length) - { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) - m_good = false; - - return m_good; - } - - bool ReadBytes(void* data, size_t length) - { - return ReadArray(reinterpret_cast(data), length); - } - - bool WriteBytes(const void* data, size_t length) - { - return WriteArray(reinterpret_cast(data), length); - } - - bool IsOpen() { return NULL != m_file; } - - // m_good is set to false when a read, write or other function fails - bool IsGood() { return m_good; } - operator void*() { return m_good ? m_file : NULL; } - - std::FILE* ReleaseHandle(); - - std::FILE* GetHandle() { return m_file; } - - void SetHandle(std::FILE* file); - - bool Seek(s64 off, int origin); - u64 Tell(); - u64 GetSize(); - bool Resize(u64 size); - bool Flush(); - - // clear error state - void Clear() { m_good = true; std::clearerr(m_file); } - - std::FILE* m_file; - bool m_good; -private: - IOFile(IOFile&); - IOFile& operator=(IOFile& other); -}; - -} // namespace - -// To deal with Windows being dumb at unicode: -template -void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) -{ -#ifdef _WIN32 - fstream.open(UTF8ToTStr(filename).c_str(), openmode); -#else - fstream.open(filename.c_str(), openmode); -#endif -} - -#endif diff --git a/src/common/src/fixed_size_queue.h b/src/common/src/fixed_size_queue.h deleted file mode 100644 index 1f507f4a..00000000 --- a/src/common/src/fixed_size_queue.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FIXED_SIZE_QUEUE_H_ -#define _FIXED_SIZE_QUEUE_H_ - -// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the -// real STL classes. - -// Not fully featured, no safety checking yet. Add features as needed. - -// TODO: "inline" storage? - -template -class fixed_size_queue.h -{ - T *storage; - int head; - int tail; - int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. - - // Make copy constructor private for now. - fixed_size_queue.h(fixed_size_queue.h &other) { } - -public: - fixed_size_queue.h() - { - storage = new T[N]; - clear(); - } - - ~fixed_size_queue.h() - { - delete [] storage; - } - - void clear() { - head = 0; - tail = 0; - count = 0; - } - - void push(T t) { - storage[tail] = t; - tail++; - if (tail == N) - tail = 0; - count++; - } - - void pop() { - head++; - if (head == N) - head = 0; - count--; - } - - T pop_front() { - const T &temp = storage[head]; - pop(); - return temp; - } - - T &front() { return storage[head]; } - const T &front() const { return storage[head]; } - - size_t size() const { - return count; - } -}; - -#endif // _FIXED_SIZE_QUEUE_H_ - diff --git a/src/common/src/hash.cpp b/src/common/src/hash.cpp deleted file mode 100644 index 5303f07b..00000000 --- a/src/common/src/hash.cpp +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "hash.h" -#if _M_SSE >= 0x402 -#include "cpu_detect.h" -#include -#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 = 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 = 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 = 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 = 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 = 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 = 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/src/hash.h b/src/common/src/hash.h deleted file mode 100644 index addfa4b5..00000000 --- a/src/common/src/hash.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _HASH_H_ -#define _HASH_H_ - -#include "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); -#endif // _HASH_H_ diff --git a/src/common/src/linear_disk_cache.h b/src/common/src/linear_disk_cache.h deleted file mode 100644 index da5d6b9b..00000000 --- a/src/common/src/linear_disk_cache.h +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _LINEAR_DISKCACHE -#define _LINEAR_DISKCACHE - -#include "common.h" -#include - -// defined in Version.cpp -extern const char *scm_rev_git_str; - -// On disk format: -//header{ -// u32 'DCAC'; -// u32 version; // svn_rev -// u16 sizeof(key_type); -// u16 sizeof(value_type); -//} - -//key_value_pair{ -// u32 value_size; -// key_type key; -// value_type[value_size] value; -//} - -template -class LinearDiskCacheReader -{ -public: - virtual void Read(const K &key, const V *value, u32 value_size) = 0; -}; - -// Dead simple unsorted key-value store with append functionality. -// No random read functionality, all reading is done in OpenAndRead. -// Keys and values can contain any characters, including \0. -// -// Suitable for caching generated shader bytecode between executions. -// Not tuned for extreme performance but should be reasonably fast. -// Does not support keys or values larger than 2GB, which should be reasonable. -// Keys must have non-zero length; values can have zero length. - -// K and V are some POD type -// K : the key type -// V : value array type -template -class LinearDiskCache -{ -public: - // return number of read entries - u32 OpenAndRead(const char *filename, LinearDiskCacheReader &reader) - { - using std::ios_base; - - // close any currently opened file - Close(); - m_num_entries = 0; - - // try opening for reading/writing - OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); - - m_file.seekg(0, std::ios::end); - std::fstream::pos_type end_pos = m_file.tellg(); - m_file.seekg(0, std::ios::beg); - std::fstream::pos_type start_pos = m_file.tellg(); - std::streamoff file_size = end_pos - start_pos; - - if (m_file.is_open() && ValidateHeader()) - { - // good header, read some key/value pairs - K key; - - V *value = NULL; - u32 value_size; - u32 entry_number; - - std::fstream::pos_type last_pos = m_file.tellg(); - - while (Read(&value_size)) - { - std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; - if (next_extent > file_size) - break; - - delete[] value; - value = new V[value_size]; - - // read key/value and pass to reader - if (Read(&key) && - Read(value, value_size) && - Read(&entry_number) && - entry_number == m_num_entries+1) - { - reader.Read(key, value, value_size); - } - else - { - break; - } - - m_num_entries++; - last_pos = m_file.tellg(); - } - m_file.seekp(last_pos); - m_file.clear(); - - delete[] value; - return m_num_entries; - } - - // failed to open file for reading or bad header - // close and recreate file - Close(); - m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); - WriteHeader(); - return 0; - } - - void Sync() - { - m_file.flush(); - } - - void Close() - { - if (m_file.is_open()) - m_file.close(); - // clear any error flags - m_file.clear(); - } - - // Appends a key-value pair to the store. - void Append(const K &key, const V *value, u32 value_size) - { - // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) - Write(&value_size); - Write(&key); - Write(value, value_size); - m_num_entries++; - Write(&m_num_entries); - } - -private: - void WriteHeader() - { - Write(&m_header); - } - - bool ValidateHeader() - { - char file_header[sizeof(Header)]; - - return (Read(file_header, sizeof(Header)) - && !memcmp((const char*)&m_header, file_header, sizeof(Header))); - } - - template - bool Write(const D *data, u32 count = 1) - { - return m_file.write((const char*)data, count * sizeof(D)).good(); - } - - template - bool Read(const D *data, u32 count = 1) - { - return m_file.read((char*)data, count * sizeof(D)).good(); - } - - struct Header - { - Header() - : id(*(u32*)"DCAC") - , key_t_size(sizeof(K)) - , value_t_size(sizeof(V)) - { - memcpy(ver, scm_rev_git_str, 40); - } - - const u32 id; - const u16 key_t_size, value_t_size; - char ver[40]; - - } m_header; - - std::fstream m_file; - u32 m_num_entries; -}; - -#endif // _LINEAR_DISKCACHE diff --git a/src/common/src/log.h b/src/common/src/log.h deleted file mode 100644 index 432a307f..00000000 --- a/src/common/src/log.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _LOG_H_ -#define _LOG_H_ - -#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. -#define ERROR_LEVEL 2 // Critical errors -#define WARNING_LEVEL 3 // Something is suspicious. -#define INFO_LEVEL 4 // General information. -#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. - -namespace LogTypes -{ - -enum LOG_TYPE { - ACTIONREPLAY, - AUDIO, - AUDIO_INTERFACE, - BOOT, - COMMANDPROCESSOR, - COMMON, - CONSOLE, - DISCIO, - FILEMON, - DSPHLE, - DSPLLE, - DSP_MAIL, - DSPINTERFACE, - DVDINTERFACE, - DYNA_REC, - EXPANSIONINTERFACE, - GDB_STUB, - ARM11, - GPFIFO, - OSHLE, - MASTER_LOG, - MEMMAP, - MEMCARD_MANAGER, - OSREPORT, - PAD, - PROCESSORINTERFACE, - PIXELENGINE, - SERIALINTERFACE, - SP1, - STREAMINGINTERFACE, - VIDEO, - VIDEOINTERFACE, - LOADER, - FILESYS, - WII_IPC_DVD, - WII_IPC_ES, - WII_IPC_FILEIO, - WII_IPC_HID, - WII_IPC_HLE, - WII_IPC_NET, - WII_IPC_WC24, - WII_IPC_SSL, - RENDER, - LCD, - HW, - TIME, - NETPLAY, - - NUMBER_OF_LOGS // Must be last -}; - -// FIXME: should this be removed? -enum LOG_LEVELS { - LNOTICE = NOTICE_LEVEL, - LERROR = ERROR_LEVEL, - LWARNING = WARNING_LEVEL, - LINFO = INFO_LEVEL, - LDEBUG = DEBUG_LEVEL, -}; - -#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS -#define LOGTYPES_TYPE LogTypes::LOG_TYPE - -} // namespace - -void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, - const char *file, int line, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 5, 6))) -#endif - ; - -#if defined LOGGING || defined _DEBUG || defined DEBUGFAST -#define MAX_LOGLEVEL DEBUG_LEVEL -#else -#ifndef MAX_LOGLEVEL -#define MAX_LOGLEVEL WARNING_LEVEL -#endif // loglevel -#endif // logging - -#ifdef GEKKO -#define GENERIC_LOG(t, v, ...) -#else -// Let the compiler optimize this out -#define GENERIC_LOG(t, v, ...) { \ - if (v <= MAX_LOGLEVEL) \ - GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ - } -#endif - -#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) -#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) -#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) -#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0) -#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0) - -#if MAX_LOGLEVEL >= DEBUG_LEVEL -#define _dbg_assert_(_t_, _a_) \ - if (!(_a_)) {\ - ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \ - __LINE__, __FILE__, __TIME__); \ - if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \ - } -#define _dbg_assert_msg_(_t_, _a_, ...)\ - if (!(_a_)) {\ - ERROR_LOG(_t_, __VA_ARGS__); \ - if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ - } -#define _dbg_update_() Host_UpdateLogDisplay(); - -#else // not debug -#define _dbg_update_() ; - -#ifndef _dbg_assert_ -#define _dbg_assert_(_t_, _a_) {} -#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} -#endif // dbg_assert -#endif // MAX_LOGLEVEL DEBUG - -#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_) - -#ifndef GEKKO -#ifdef _WIN32 -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ - } -#else // not win32 -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ - } -#endif // WIN32 -#else // GEKKO -#define _assert_msg_(_t_, _a_, _fmt_, ...) -#endif - -#endif // _LOG_H_ diff --git a/src/common/src/log_manager.cpp b/src/common/src/log_manager.cpp deleted file mode 100644 index b5b03484..00000000 --- a/src/common/src/log_manager.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#ifdef ANDROID -#include "Host.h" -#endif -#include "log_manager.h" -#include "console_listener.h" -#include "timer.h" -#include "thread.h" -#include "file_util.h" - -void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - if (LogManager::GetInstance()) - LogManager::GetInstance()->Log(level, type, - file, line, fmt, args); - va_end(args); -} - -LogManager *LogManager::m_logManager = NULL; - -LogManager::LogManager() -{ - // create log files - m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); - m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); - m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); - m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); - m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); - m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); - m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); - m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); - m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt"); - m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt"); - m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); - m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); - m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); - m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); - m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); - m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); - m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); - m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); - m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); - m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); - m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11"); - m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); - m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); - m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); - m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); - m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); - m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); - m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT"); - m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); - m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); - m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing"); - m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader"); - m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); - m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); - m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); - m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); - m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); - m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); - m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); - m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); - m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); - m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); - m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); - m_Log[LogTypes::HW] = new LogContainer("HARDWARE", "HARDWARE"); - m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); - m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); - m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); - - m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); - m_consoleLog = new ConsoleListener(); - m_debuggerLog = new DebuggerLogListener(); - - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_Log[i]->SetEnable(true); - m_Log[i]->AddListener(m_fileLog); - m_Log[i]->AddListener(m_consoleLog); -#ifdef _MSC_VER - if (IsDebuggerPresent()) - m_Log[i]->AddListener(m_debuggerLog); -#endif - } -} - -LogManager::~LogManager() -{ - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog); - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog); - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog); - } - - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - delete m_Log[i]; - - delete m_fileLog; - delete m_consoleLog; - delete m_debuggerLog; -} - -void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char *format, va_list args) -{ - char temp[MAX_MSGLEN]; - char msg[MAX_MSGLEN * 2]; - LogContainer *log = m_Log[type]; - - if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) - return; - - CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); - - static const char level_to_char[7] = "-NEWID"; - sprintf(msg, "%s %s:%u %c[%s]: %s\n", - Common::Timer::GetTimeFormatted().c_str(), - file, line, level_to_char[(int)level], - log->GetShortName(), temp); -#ifdef ANDROID - Host_SysMessage(msg); -#endif - printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this - log->Trigger(level, msg); -} - -void LogManager::Init() -{ - m_logManager = new LogManager(); -} - -void LogManager::Shutdown() -{ - delete m_logManager; - m_logManager = NULL; -} - -LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable) - : m_enable(enable) -{ - strncpy(m_fullName, fullName, 128); - strncpy(m_shortName, shortName, 32); - m_level = LogTypes::LWARNING; -} - -// LogContainer -void LogContainer::AddListener(LogListener *listener) -{ - std::lock_guard lk(m_listeners_lock); - m_listeners.insert(listener); -} - -void LogContainer::RemoveListener(LogListener *listener) -{ - std::lock_guard lk(m_listeners_lock); - m_listeners.erase(listener); -} - -void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) -{ - std::lock_guard lk(m_listeners_lock); - - std::set::const_iterator i; - for (i = m_listeners.begin(); i != m_listeners.end(); ++i) - { - (*i)->Log(level, msg); - } -} - -FileLogListener::FileLogListener(const char *filename) -{ - OpenFStream(m_logfile, filename, std::ios::app); - SetEnable(true); -} - -void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) -{ - if (!IsEnabled() || !IsValid()) - return; - - std::lock_guard lk(m_log_lock); - m_logfile << msg << std::flush; -} - -void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) -{ -#if _MSC_VER - ::OutputDebugStringA(msg); -#endif -} diff --git a/src/common/src/log_manager.h b/src/common/src/log_manager.h deleted file mode 100644 index 579198ff..00000000 --- a/src/common/src/log_manager.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _LOGMANAGER_H_ -#define _LOGMANAGER_H_ - -#include "log.h" -#include "string_util.h" -#include "thread.h" -#include "file_util.h" - -#include -#include - -#define MAX_MESSAGES 8000 -#define MAX_MSGLEN 1024 - - -// pure virtual interface -class LogListener -{ -public: - virtual ~LogListener() {} - - virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0; -}; - -class FileLogListener : public LogListener -{ -public: - FileLogListener(const char *filename); - - void Log(LogTypes::LOG_LEVELS, const char *msg); - - bool IsValid() { return !m_logfile.fail(); } - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - const char* GetName() const { return "file"; } - -private: - std::mutex m_log_lock; - std::ofstream m_logfile; - bool m_enable; -}; - -class DebuggerLogListener : public LogListener -{ -public: - void Log(LogTypes::LOG_LEVELS, const char *msg); -}; - -class LogContainer -{ -public: - LogContainer(const char* shortName, const char* fullName, bool enable = false); - - const char* GetShortName() const { return m_shortName; } - const char* GetFullName() const { return m_fullName; } - - void AddListener(LogListener* listener); - void RemoveListener(LogListener* listener); - - void Trigger(LogTypes::LOG_LEVELS, const char *msg); - - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - LogTypes::LOG_LEVELS GetLevel() const { return m_level; } - - void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } - - bool HasListeners() const { return !m_listeners.empty(); } - -private: - char m_fullName[128]; - char m_shortName[32]; - bool m_enable; - LogTypes::LOG_LEVELS m_level; - std::mutex m_listeners_lock; - std::set m_listeners; -}; - -class ConsoleListener; - -class LogManager : NonCopyable -{ -private: - LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; - FileLogListener *m_fileLog; - ConsoleListener *m_consoleLog; - DebuggerLogListener *m_debuggerLog; - static LogManager *m_logManager; // Singleton. Ugh. - - LogManager(); - ~LogManager(); -public: - - static u32 GetMaxLevel() { return MAX_LOGLEVEL; } - - void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char *fmt, va_list args); - - void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) - { - m_Log[type]->SetLevel(level); - } - - void SetEnable(LogTypes::LOG_TYPE type, bool enable) - { - m_Log[type]->SetEnable(enable); - } - - bool IsEnabled(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->IsEnabled(); - } - - const char* GetShortName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetShortName(); - } - - const char* GetFullName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetFullName(); - } - - void AddListener(LogTypes::LOG_TYPE type, LogListener *listener) - { - m_Log[type]->AddListener(listener); - } - - void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener) - { - m_Log[type]->RemoveListener(listener); - } - - FileLogListener *GetFileListener() const - { - return m_fileLog; - } - - ConsoleListener *GetConsoleListener() const - { - return m_consoleLog; - } - - DebuggerLogListener *GetDebuggerListener() const - { - return m_debuggerLog; - } - - static LogManager* GetInstance() - { - return m_logManager; - } - - static void SetInstance(LogManager *logManager) - { - m_logManager = logManager; - } - - static void Init(); - static void Shutdown(); -}; - -#endif // _LOGMANAGER_H_ diff --git a/src/common/src/math_util.cpp b/src/common/src/math_util.cpp deleted file mode 100644 index da90f8d7..00000000 --- a/src/common/src/math_util.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "math_util.h" - -#include -#include - -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& 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/src/math_util.h b/src/common/src/math_util.h deleted file mode 100644 index 4410c5e0..00000000 --- a/src/common/src/math_util.h +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _MATH_UTIL_H_ -#define _MATH_UTIL_H_ - -#include "common.h" - -#include - -namespace MathUtil -{ - -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 -struct Rectangle -{ - T left; - T top; - T right; - T bottom; - - 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; } - - T GetWidth() const { return abs(right - left); } - T GetHeight() const { return abs(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&); - -#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]; -}; - -#endif // _MATH_UTIL_H_ diff --git a/src/common/src/mem_arena.cpp b/src/common/src/mem_arena.cpp deleted file mode 100644 index 1a6fcf44..00000000 --- a/src/common/src/mem_arena.cpp +++ /dev/null @@ -1,477 +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 - -#include "memory_util.h" -#include "mem_arena.h" - -#ifdef _WIN32 -//#include "CommonWindows.h" -#else -#include -#include -#include -#include -#include -#ifdef ANDROID -#include -#include -#endif -#endif - -#ifdef IOS -void* globalbase = NULL; -#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: - ERROR_LOG(MEMMAP, "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 - - - -#ifndef _WIN32 -// do not make this "static" -#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) -std::string ram_temp_file = "/home/user/gc_mem.tmp"; -#else -std::string ram_temp_file = "/tmp/gc_mem.tmp"; -#endif -#elif !defined(_XBOX) -SYSTEM_INFO sysInfo; -#endif - - -// Windows mappings need to be on 64K boundaries, due to Alpha legacy. -#ifdef _WIN32 -size_t roundup(size_t x) { -#ifndef _XBOX - int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; -#else - int gran = 0x10000; // 64k in 360 -#endif - return (x + gran - 1) & ~(gran - 1); -} -#else -size_t roundup(size_t x) { - return x; -} -#endif - - -void MemArena::GrabLowMemSpace(size_t size) -{ -#ifdef _WIN32 -#ifndef _XBOX - hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); - GetSystemInfo(&sysInfo); -#endif -#elif defined(ANDROID) - // Use ashmem so we don't have to allocate a file on disk! - fd = ashmem_create_region("PPSSPP_RAM", size); - // Note that it appears that ashmem is pinned by default, so no need to pin. - if (fd < 0) - { - ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); - return; - } -#else - mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); - if (fd < 0) - { - ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno)); - return; - } - // delete immediately, we keep the fd so it still lives - unlink(ram_temp_file.c_str()); - if (ftruncate(fd, size) != 0) - { - ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size); - } - return; -#endif -} - - -void MemArena::ReleaseSpace() -{ -#ifdef _WIN32 - CloseHandle(hMemoryMapping); - hMemoryMapping = 0; -#elif defined(__SYMBIAN32__) - memmap->Close(); - delete memmap; -#else - close(fd); -#endif -} - - -void *MemArena::CreateView(s64 offset, size_t size, void *base) -{ -#ifdef _WIN32 -#ifdef _XBOX - size = roundup(size); - // use 64kb pages - void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); - return ptr; -#else - size = roundup(size); - void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); - return ptr; -#endif -#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 BLACKBERRY - MAP_NOSYNCFILE | -#elif defined(__FreeBSD__) - MAP_NOSYNC | -#endif - ((base == 0) ? 0 : MAP_FIXED), fd, offset); - - if (retval == MAP_FAILED) - { - NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd); - return 0; - } - return retval; -#endif -} - - -void MemArena::ReleaseView(void* view, size_t size) -{ -#ifdef _WIN32 -#ifndef _XBOX - UnmapViewOfFile(view); -#endif -#elif defined(__SYMBIAN32__) - memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); -#else - munmap(view, size); -#endif -} - -#ifndef __SYMBIAN32__ -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(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 -#ifdef IOS - void* base = NULL; - if (globalbase == NULL){ - base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno)); - return 0; - } - munmap(base, 0x08000000); - globalbase = base; - } - else{ base = globalbase; } -#else - void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); - return 0; - } - munmap(base, 0x10000000); -#endif - return static_cast(base); -#endif -#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; - -#if defined(_XBOX) - void *ptr; -#endif - - // 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 { -#ifdef __SYMBIAN32__ - *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); - arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - } - *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); -#elif defined(_XBOX) - *(view.out_ptr_low) = (u8*)(base + view.virtual_address); - //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); - } - *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); -#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 - -#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 = NULL; - } - 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 = NULL; - } - } - 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 ... -#ifndef __SYMBIAN32__ - arena->GrabLowMemSpace(total_mem); -#endif - - // 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)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#elif defined(_XBOX) - // Reserve 256MB - u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - exit(0); - 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 = NULL; - - 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)) - { - INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); - base_attempts = 0; - break; - } - } -#elif defined(__SYMBIAN32__) - arena->memmap = new RChunk(); - arena->memmap->CreateDisconnectedLocal(0, 0, 0x10000000); - if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } - u8* base = arena->memmap->Base(); -#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)) - { - ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#endif - if (base_attempts) - PanicAlert("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 = NULL; - if (views[i].out_ptr_low) - *views[i].out_ptr_low = NULL; - } -} diff --git a/src/common/src/mem_arena.h b/src/common/src/mem_arena.h deleted file mode 100644 index 8bdf9f18..00000000 --- a/src/common/src/mem_arena.h +++ /dev/null @@ -1,81 +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/ - -#ifndef _MEMARENA_H_ -#define _MEMARENA_H_ - -#ifdef _WIN32 -#include -#endif - -#ifdef __SYMBIAN32__ -#include -#endif - -#include "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); - -#ifdef __SYMBIAN32__ - RChunk* memmap; -#else - // This only finds 1 GB in 32-bit - static u8 *Find4GBBase(); -#endif -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); - -#endif // _MEMARENA_H_ diff --git a/src/common/src/memory_util.cpp b/src/common/src/memory_util.cpp deleted file mode 100644 index cc6e77b3..00000000 --- a/src/common/src/memory_util.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "memory_util.h" -#include "string_util.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#endif - -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) -#include -#define PAGE_MASK (getpagesize() - 1) -#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) -#endif - -// This is purposely not a full wrapper for virtualalloc/mmap, but it -// provides exactly the primitive operations that Dolphin needs. - -void* AllocateExecutableMemory(size_t size, bool low) -{ -#if defined(_WIN32) - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - static char *map_hint = 0; -#if defined(__x86_64__) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ -#endif - void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE -#if defined(__x86_64__) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) -#endif - , -1, 0); -#endif /* defined(_WIN32) */ - - // printf("Mapped executable memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - -#if defined(__FreeBSD__) - if (ptr == MAP_FAILED) - { - ptr = NULL; -#else - if (ptr == NULL) - { -#endif - PanicAlert("Failed to allocate executable memory"); - } -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) - else - { - if (low) - { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - // printf("Next map will (hopefully) be at %p\n", map_hint); - } - } -#endif - -#if defined(_M_X64) - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); -#endif - - return ptr; -} - -void* AllocateMemoryPages(size_t size) -{ -#ifdef _WIN32 - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); -#else - void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate raw memory"); - - return ptr; -} - -void* AllocateAlignedMemory(size_t size,size_t alignment) -{ -#ifdef _WIN32 - void* ptr = _aligned_malloc(size,alignment); -#else - void* ptr = NULL; -#ifdef ANDROID - ptr = memalign(alignment, size); -#else - if (posix_memalign(&ptr, alignment, size) != 0) - ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); -#endif -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate aligned memory"); - - return ptr; -} - -void FreeMemoryPages(void* ptr, size_t size) -{ - if (ptr) - { -#ifdef _WIN32 - - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); - ptr = NULL; // Is this our responsibility? - -#else - munmap(ptr, size); -#endif - } -} - -void FreeAlignedMemory(void* ptr) -{ - if (ptr) - { -#ifdef _WIN32 - _aligned_free(ptr); -#else - free(ptr); -#endif - } -} - -void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); -#endif -} - -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) - PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); -#endif -} - -std::string MemUsage() -{ -#ifdef _WIN32 -#pragma comment(lib, "psapi") - DWORD processID = GetCurrentProcessId(); - HANDLE hProcess; - PROCESS_MEMORY_COUNTERS pmc; - std::string Ret; - - // Print information about the memory usage of the process. - - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (NULL == hProcess) return "MemUsage Error"; - - if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); - - CloseHandle(hProcess); - return Ret; -#else - return ""; -#endif -} diff --git a/src/common/src/memory_util.h b/src/common/src/memory_util.h deleted file mode 100644 index 49b2589d..00000000 --- a/src/common/src/memory_util.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _MEMORYUTIL_H -#define _MEMORYUTIL_H - -#ifndef _WIN32 -#include -#endif -#include - -void* AllocateExecutableMemory(size_t size, bool low = true); -void* AllocateMemoryPages(size_t size); -void FreeMemoryPages(void* ptr, size_t size); -void* AllocateAlignedMemory(size_t size,size_t alignment); -void FreeAlignedMemory(void* ptr); -void WriteProtectMemory(void* ptr, size_t size, bool executable = false); -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); -std::string MemUsage(); - -inline int GetPageSize() { return 4096; } - -#endif diff --git a/src/common/src/misc.cpp b/src/common/src/misc.cpp deleted file mode 100644 index 93580547..00000000 --- a/src/common/src/misc.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" - -#ifdef _WIN32 -#include -#endif - -// Neither Android nor OS X support TLS -#if defined(__APPLE__) || (ANDROID && __clang__) -#define __thread -#endif - -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -const char* GetLastErrorMsg() -{ - static const size_t buff_size = 255; - -#ifdef _WIN32 - static __declspec(thread) char err_str[buff_size] = {}; - - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - err_str, buff_size, NULL); -#else - static __thread char err_str[buff_size] = {}; - - // Thread safe (XSI-compliant) - strerror_r(errno, err_str, buff_size); -#endif - - return err_str; -} diff --git a/src/common/src/msg_handler.cpp b/src/common/src/msg_handler.cpp deleted file mode 100644 index 8e9fe218..00000000 --- a/src/common/src/msg_handler.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include // System - -#include "common.h" // Local -#include "string_util.h" - -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); -static MsgAlertHandler msg_handler = DefaultMsgHandler; -static bool AlertEnabled = true; - -std::string DefaultStringTranslator(const char* text); -static StringTranslator str_translator = DefaultStringTranslator; - -// Select which of these functions that are used for message boxes. If -// wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp -void RegisterMsgAlertHandler(MsgAlertHandler handler) -{ - msg_handler = handler; -} - -// Select translation function. For wxWidgets use wxStringTranslator in Main.cpp -void RegisterStringTranslator(StringTranslator translator) -{ - str_translator = translator; -} - -// enable/disable the alert handler -void SetEnableAlert(bool enable) -{ - AlertEnabled = enable; -} - -// This is the first stop for gui alerts where the log is updated and the -// correct window is shown -bool MsgAlert(bool yes_no, int Style, const char* format, ...) -{ - // Read message and write it to the log - std::string caption; - char buffer[2048]; - - static std::string info_caption; - static std::string warn_caption; - static std::string ques_caption; - static std::string crit_caption; - - if (!info_caption.length()) - { - info_caption = str_translator(_trans("Information")); - ques_caption = str_translator(_trans("Question")); - warn_caption = str_translator(_trans("Warning")); - crit_caption = str_translator(_trans("Critical")); - } - - switch(Style) - { - case INFORMATION: - caption = info_caption; - break; - case QUESTION: - caption = ques_caption; - break; - case WARNING: - caption = warn_caption; - break; - case CRITICAL: - caption = crit_caption; - break; - } - - va_list args; - va_start(args, format); - CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); - va_end(args); - - ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); - - // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored - if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) - return msg_handler(caption.c_str(), buffer, yes_no, Style); - - return true; -} - -// Default non library dependent panic alert -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) -{ -//#ifdef _WIN32 -// int STYLE = MB_ICONINFORMATION; -// if (Style == QUESTION) STYLE = MB_ICONQUESTION; -// if (Style == WARNING) STYLE = MB_ICONWARNING; -// -// return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); -//#else - printf("%s\n", text); - return true; -//#endif -} - -// Default (non) translator -std::string DefaultStringTranslator(const char* text) -{ - return text; -} - diff --git a/src/common/src/msg_handler.h b/src/common/src/msg_handler.h deleted file mode 100644 index bde2808f..00000000 --- a/src/common/src/msg_handler.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _MSGHANDLER_H_ -#define _MSGHANDLER_H_ - -#include - -// Message alerts -enum MSG_TYPE -{ - INFORMATION, - QUESTION, - WARNING, - CRITICAL -}; - -typedef bool (*MsgAlertHandler)(const char* caption, const char* text, - bool yes_no, int Style); -typedef std::string (*StringTranslator)(const char* text); - -void RegisterMsgAlertHandler(MsgAlertHandler handler); -void RegisterStringTranslator(StringTranslator translator); - -extern bool MsgAlert(bool yes_no, int Style, const char* format, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) -#endif - ; -void SetEnableAlert(bool enable); - -#ifndef GEKKO -#ifdef _WIN32 - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) -#else - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) -#endif -#else -// GEKKO - #define SuccessAlert(format, ...) ; - #define PanicAlert(format, ...) ; - #define PanicYesNo(format, ...) ; - #define AskYesNo(format, ...) ; - #define CriticalAlert(format, ...) ; - #define SuccessAlertT(format, ...) ; - #define PanicAlertT(format, ...) ; - #define PanicYesNoT(format, ...) ; - #define AskYesNoT(format, ...) ; - #define CriticalAlertT(format, ...) ; -#endif - -#endif // _MSGHANDLER_H_ diff --git a/src/common/src/platform.h b/src/common/src/platform.h deleted file mode 100644 index 84c6b636..00000000 --- a/src/common/src/platform.h +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file platform.h - * @author ShizZy - * @date 2012-02-11 - * @brief Platform detection macros for portable compilation - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#ifndef COMMON_PLATFORM_H_ -#define COMMON_PLATFORM_H_ - -#include "common_types.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Platform definitions - -/// Enumeration for defining the supported platforms -#define PLATFORM_NULL 0 -#define PLATFORM_WINDOWS 1 -#define PLATFORM_MACOSX 2 -#define PLATFORM_LINUX 3 -#define PLATFORM_ANDROID 4 -#define PLATFORM_IOS 5 - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Platform detection - -#ifndef EMU_PLATFORM - -#if defined( __WIN32__ ) || defined( _WIN32 ) -#define EMU_PLATFORM PLATFORM_WINDOWS - -#elif defined( __APPLE__ ) || defined( __APPLE_CC__ ) -#define EMU_PLATFORM PLATFORM_MAXOSX - -#elif defined(__linux__) -#define EMU_PLATFORM PLATFORM_LINUX - -#else // Assume linux otherwise -#define EMU_PLATFORM PLATFORM_LINUX - -#endif - -#endif - -#if defined(__x86_64__) || defined(_M_X64) || defined(__alpha__) || defined(__ia64__) -#define EMU_ARCHITECTURE_X64 -#else -#define EMU_ARCHITECTURE_X86 -#endif - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Compiler-Specific Definitions - -#if EMU_PLATFORM == PLATFORM_WINDOWS - -#include - -#define NOMINMAX -#define EMU_FASTCALL __fastcall - -inline struct tm* localtime_r(const time_t *clock, struct tm *result) { - if (localtime_s(result, clock) == 0) - return result; - return NULL; -} - -#else - -#define EMU_FASTCALL __attribute__((fastcall)) -#define __stdcall -#define __cdecl - -#define LONG long -#define BOOL bool -#define DWORD u32 - -#endif - -#if EMU_PLATFORM != PLATFORM_WINDOWS - -// TODO: Hacks.. -#include -#define MAX_PATH PATH_MAX - -#include -#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; - -inline u32 _rotl(u32 x, int shift) { - shift &= 31; - if (0 == shift) { - return x; - } - return (x << shift) | (x >> (32 - shift)); -} - -inline u64 _rotl64(u64 x, u32 shift){ - u32 n = shift % 64; - return (x << n) | (x >> (64 - n)); -} - -inline u32 _rotr(u32 x, int shift) { - shift &= 31; - if (0 == shift) { - return x; - } - return (x >> shift) | (x << (32 - shift)); -} - -inline u64 _rotr64(u64 x, u32 shift){ - u32 n = shift % 64; - return (x >> n) | (x << (64 - n)); -} - -#endif - -#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \ - (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) - -#endif // COMMON_PLATFORM_H_ diff --git a/src/common/src/scm_rev.h b/src/common/src/scm_rev.h deleted file mode 100644 index 69962c58..00000000 --- a/src/common/src/scm_rev.h +++ /dev/null @@ -1,4 +0,0 @@ -#define SCM_REV_STR "a7b06698ff012aa7b1094414e796ffae1ca1eb4d" -#define SCM_DESC_STR "a7b0669" -#define SCM_BRANCH_STR "master" -#define SCM_IS_MASTER 1 diff --git a/src/common/src/std_condition_variable.h b/src/common/src/std_condition_variable.h deleted file mode 100644 index cee7a9dc..00000000 --- a/src/common/src/std_condition_variable.h +++ /dev/null @@ -1,170 +0,0 @@ - -#ifndef CONDITION_VARIABLE_H_ -#define CONDITION_VARIABLE_H_ - -#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) -#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ - -// GCC 4.4 provides -#include - -#elif __has_include() && !ANDROID - -// clang and libc++ provide on OSX. However, the version -// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable. -// -// We work around this issue by undefining and redefining _. - -#undef _ -#include -#define _(s) wxGetTranslation((s)) - -#else - -// partial std::condition_variable implementation for win32/pthread - -#include "std_mutex.h" - -#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) -#define USE_RVALUE_REFERENCES -#endif - -#if defined(_WIN32) && defined(_M_X64) -#define USE_CONDITION_VARIABLES -#elif defined(_WIN32) -#define USE_EVENTS -#endif - -namespace std -{ - -class condition_variable -{ -#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) - typedef CONDITION_VARIABLE native_type; -#elif defined(_WIN32) - typedef HANDLE native_type; -#else - typedef pthread_cond_t native_type; -#endif - -public: - -#ifdef USE_EVENTS - typedef native_type native_handle_type; -#else - typedef native_type* native_handle_type; -#endif - - condition_variable() - { -#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) - InitializeConditionVariable(&m_handle); -#elif defined(_WIN32) - m_handle = CreateEvent(NULL, false, false, NULL); -#else - pthread_cond_init(&m_handle, NULL); -#endif - } - - ~condition_variable() - { -#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES) - CloseHandle(m_handle); -#elif !defined(_WIN32) - pthread_cond_destroy(&m_handle); -#endif - } - - condition_variable(const condition_variable&) /*= delete*/; - condition_variable& operator=(const condition_variable&) /*= delete*/; - - void notify_one() - { -#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) - WakeConditionVariable(&m_handle); -#elif defined(_WIN32) - SetEvent(m_handle); -#else - pthread_cond_signal(&m_handle); -#endif - } - - void notify_all() - { -#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) - WakeAllConditionVariable(&m_handle); -#elif defined(_WIN32) - // TODO: broken - SetEvent(m_handle); -#else - pthread_cond_broadcast(&m_handle); -#endif - } - - void wait(unique_lock& lock) - { -#ifdef _WIN32 - #ifdef USE_SRWLOCKS - SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0); - #elif defined(USE_CONDITION_VARIABLES) - SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE); - #else - // TODO: broken, the unlock and wait need to be atomic - lock.unlock(); - WaitForSingleObject(m_handle, INFINITE); - lock.lock(); - #endif -#else - pthread_cond_wait(&m_handle, lock.mutex()->native_handle()); -#endif - } - - template - void wait(unique_lock& lock, Predicate pred) - { - while (!pred()) - wait(lock); - } - - //template - //cv_status wait_until(unique_lock& lock, - // const chrono::time_point& abs_time); - - //template - // bool wait_until(unique_lock& lock, - // const chrono::time_point& abs_time, - // Predicate pred); - - //template - //cv_status wait_for(unique_lock& lock, - // const chrono::duration& rel_time); - - //template - // bool wait_for(unique_lock& lock, - // const chrono::duration& rel_time, - // Predicate pred); - - native_handle_type native_handle() - { -#ifdef USE_EVENTS - return m_handle; -#else - return &m_handle; -#endif - } - -private: - native_type m_handle; -}; - -} - -#endif -#endif diff --git a/src/common/src/std_mutex.h b/src/common/src/std_mutex.h deleted file mode 100644 index 26eb58b6..00000000 --- a/src/common/src/std_mutex.h +++ /dev/null @@ -1,365 +0,0 @@ - -#ifndef MUTEX_H_ -#define MUTEX_H_ - -#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) -#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ -// GCC 4.4 provides -#include -#elif __has_include() && !ANDROID -// Clang + libc++ -#include -#else - -// partial implementation for win32/pthread - -#include - -#if defined(_WIN32) -// WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -#else -// POSIX -#include - -#endif - -#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) -#define USE_RVALUE_REFERENCES -#endif - -#if defined(_WIN32) && defined(_M_X64) -#define USE_SRWLOCKS -#endif - -namespace std -{ - -class recursive_mutex -{ -#ifdef _WIN32 - typedef CRITICAL_SECTION native_type; -#else - typedef pthread_mutex_t native_type; -#endif - -public: - typedef native_type* native_handle_type; - - recursive_mutex(const recursive_mutex&) /*= delete*/; - recursive_mutex& operator=(const recursive_mutex&) /*= delete*/; - - recursive_mutex() - { -#ifdef _WIN32 - InitializeCriticalSection(&m_handle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_handle, &attr); -#endif - } - - ~recursive_mutex() - { -#ifdef _WIN32 - DeleteCriticalSection(&m_handle); -#else - pthread_mutex_destroy(&m_handle); -#endif - } - - void lock() - { -#ifdef _WIN32 - EnterCriticalSection(&m_handle); -#else - pthread_mutex_lock(&m_handle); -#endif - } - - void unlock() - { -#ifdef _WIN32 - LeaveCriticalSection(&m_handle); -#else - pthread_mutex_unlock(&m_handle); -#endif - } - - bool try_lock() - { -#ifdef _WIN32 - return (0 != TryEnterCriticalSection(&m_handle)); -#else - return !pthread_mutex_trylock(&m_handle); -#endif - } - - native_handle_type native_handle() - { - return &m_handle; - } - -private: - native_type m_handle; -}; - -#if !defined(_WIN32) || defined(USE_SRWLOCKS) - -class mutex -{ -#ifdef _WIN32 - typedef SRWLOCK native_type; -#else - typedef pthread_mutex_t native_type; -#endif - -public: - typedef native_type* native_handle_type; - - mutex(const mutex&) /*= delete*/; - mutex& operator=(const mutex&) /*= delete*/; - - mutex() - { -#ifdef _WIN32 - InitializeSRWLock(&m_handle); -#else - pthread_mutex_init(&m_handle, NULL); -#endif - } - - ~mutex() - { -#ifdef _WIN32 -#else - pthread_mutex_destroy(&m_handle); -#endif - } - - void lock() - { -#ifdef _WIN32 - AcquireSRWLockExclusive(&m_handle); -#else - pthread_mutex_lock(&m_handle); -#endif - } - - void unlock() - { -#ifdef _WIN32 - ReleaseSRWLockExclusive(&m_handle); -#else - pthread_mutex_unlock(&m_handle); -#endif - } - - bool try_lock() - { -#ifdef _WIN32 - // XXX TryAcquireSRWLockExclusive requires Windows 7! - // return (0 != TryAcquireSRWLockExclusive(&m_handle)); - return false; -#else - return !pthread_mutex_trylock(&m_handle); -#endif - } - - native_handle_type native_handle() - { - return &m_handle; - } - -private: - native_type m_handle; -}; - -#else -typedef recursive_mutex mutex; // just use CriticalSections - -#endif - -enum defer_lock_t { defer_lock }; -enum try_to_lock_t { try_to_lock }; -enum adopt_lock_t { adopt_lock }; - -template -class lock_guard -{ -public: - typedef Mutex mutex_type; - - explicit lock_guard(mutex_type& m) - : pm(m) - { - m.lock(); - } - - lock_guard(mutex_type& m, adopt_lock_t) - : pm(m) - { - } - - ~lock_guard() - { - pm.unlock(); - } - - lock_guard(lock_guard const&) /*= delete*/; - lock_guard& operator=(lock_guard const&) /*= delete*/; - -private: - mutex_type& pm; -}; - -template -class unique_lock -{ -public: - typedef Mutex mutex_type; - - unique_lock() - : pm(NULL), owns(false) - {} - - /*explicit*/ unique_lock(mutex_type& m) - : pm(&m), owns(true) - { - m.lock(); - } - - unique_lock(mutex_type& m, defer_lock_t) - : pm(&m), owns(false) - {} - - unique_lock(mutex_type& m, try_to_lock_t) - : pm(&m), owns(m.try_lock()) - {} - - unique_lock(mutex_type& m, adopt_lock_t) - : pm(&m), owns(true) - {} - - //template - //unique_lock(mutex_type& m, const chrono::time_point& abs_time); - - //template - //unique_lock(mutex_type& m, const chrono::duration& rel_time); - - ~unique_lock() - { - if (owns_lock()) - mutex()->unlock(); - } - -#ifdef USE_RVALUE_REFERENCES - unique_lock& operator=(const unique_lock&) /*= delete*/; - - unique_lock& operator=(unique_lock&& other) - { -#else - unique_lock& operator=(const unique_lock& u) - { - // ugly const_cast to get around lack of rvalue references - unique_lock& other = const_cast(u); -#endif - swap(other); - return *this; - } - -#ifdef USE_RVALUE_REFERENCES - unique_lock(const unique_lock&) /*= delete*/; - - unique_lock(unique_lock&& other) - : pm(NULL), owns(false) - { -#else - unique_lock(const unique_lock& u) - : pm(NULL), owns(false) - { - // ugly const_cast to get around lack of rvalue references - unique_lock& other = const_cast(u); -#endif - swap(other); - } - - void lock() - { - mutex()->lock(); - owns = true; - } - - bool try_lock() - { - owns = mutex()->try_lock(); - return owns; - } - - //template - //bool try_lock_for(const chrono::duration& rel_time); - //template - //bool try_lock_until(const chrono::time_point& abs_time); - - void unlock() - { - mutex()->unlock(); - owns = false; - } - - void swap(unique_lock& u) - { - std::swap(pm, u.pm); - std::swap(owns, u.owns); - } - - mutex_type* release() - { - auto const ret = mutex(); - - pm = NULL; - owns = false; - - return ret; - } - - bool owns_lock() const - { - return owns; - } - - //explicit operator bool () const - //{ - // return owns_lock(); - //} - - mutex_type* mutex() const - { - return pm; - } - -private: - mutex_type* pm; - bool owns; -}; - -template -void swap(unique_lock& x, unique_lock& y) -{ - x.swap(y); -} - -} - -#endif -#endif diff --git a/src/common/src/std_thread.h b/src/common/src/std_thread.h deleted file mode 100644 index 9ed0072c..00000000 --- a/src/common/src/std_thread.h +++ /dev/null @@ -1,317 +0,0 @@ - -#ifndef STD_THREAD_H_ -#define STD_THREAD_H_ - -#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) -#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ -// GCC 4.4 provides -#ifndef _GLIBCXX_USE_SCHED_YIELD -#define _GLIBCXX_USE_SCHED_YIELD -#endif -#include -#elif __has_include() && !ANDROID -// Clang + libc++ -#include -#else - -// partial std::thread implementation for win32/pthread - -#include - -#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) -#define USE_RVALUE_REFERENCES -#endif - -#ifdef __APPLE__ -#import -#endif - -#if defined(_WIN32) -// WIN32 - -#define WIN32_LEAN_AND_MEAN -#include - -#if defined(_MSC_VER) && defined(_MT) -// When linking with LIBCMT (the multithreaded C library), Microsoft recommends -// using _beginthreadex instead of CreateThread. -#define USE_BEGINTHREADEX -#include -#endif - -#ifdef USE_BEGINTHREADEX -#define THREAD_ID unsigned -#define THREAD_RETURN unsigned __stdcall -#else -#define THREAD_ID DWORD -#define THREAD_RETURN DWORD WINAPI -#endif -#define THREAD_HANDLE HANDLE - -#else -// PTHREAD - -#include - -#ifndef _POSIX_THREADS -#error unsupported platform (no pthreads?) -#endif - -#include - -#define THREAD_ID pthread_t -#define THREAD_HANDLE pthread_t -#define THREAD_RETURN void* - -#endif - -namespace std -{ - -class thread -{ -public: - typedef THREAD_HANDLE native_handle_type; - - class id - { - friend class thread; - public: - id() : m_thread(0) {} - id(THREAD_ID _id) : m_thread(_id) {} - - bool operator==(const id& rhs) const - { - return m_thread == rhs.m_thread; - } - - bool operator!=(const id& rhs) const - { - return !(*this == rhs); - } - - bool operator<(const id& rhs) const - { - return m_thread < rhs.m_thread; - } - - private: - THREAD_ID m_thread; - }; - - // no variadic template support in msvc - //template - //thread(C&& func, A&&... args); - - template - thread(C func) - { - StartThread(new Func(func)); - } - - template - thread(C func, A arg) - { - StartThread(new FuncArg(func, arg)); - } - - thread() /*= default;*/ {} - -#ifdef USE_RVALUE_REFERENCES - thread(const thread&) /*= delete*/; - - thread(thread&& other) - { -#else - thread(const thread& t) - { - // ugly const_cast to get around lack of rvalue references - thread& other = const_cast(t); -#endif - swap(other); - } - -#ifdef USE_RVALUE_REFERENCES - thread& operator=(const thread&) /*= delete*/; - - thread& operator=(thread&& other) - { -#else - thread& operator=(const thread& t) - { - // ugly const_cast to get around lack of rvalue references - thread& other = const_cast(t); -#endif - if (joinable()) - detach(); - swap(other); - return *this; - } - - ~thread() - { - if (joinable()) - detach(); - } - - bool joinable() const - { - return m_id != id(); - } - - id get_id() const - { - return m_id; - } - - native_handle_type native_handle() - { -#ifdef _WIN32 - return m_handle; -#else - return m_id.m_thread; -#endif - } - - void join() - { -#ifdef _WIN32 - WaitForSingleObject(m_handle, INFINITE); - detach(); -#else - pthread_join(m_id.m_thread, NULL); - m_id = id(); -#endif - } - - void detach() - { -#ifdef _WIN32 - CloseHandle(m_handle); -#else - pthread_detach(m_id.m_thread); -#endif - m_id = id(); - } - - void swap(thread& other) - { - std::swap(m_id, other.m_id); -#ifdef _WIN32 - std::swap(m_handle, other.m_handle); -#endif - } - - static unsigned hardware_concurrency() - { -#ifdef _WIN32 - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return static_cast(sysinfo.dwNumberOfProcessors); -#else - return 0; -#endif - } - -private: - id m_id; - -#ifdef _WIN32 - native_handle_type m_handle; -#endif - - template - void StartThread(F* param) - { -#ifdef USE_BEGINTHREADEX - m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); -#elif defined(_WIN32) - m_handle = CreateThread(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); -#else - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 1024 * 1024); - if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete, param)) - m_id = id(); -#endif - } - - template - class Func - { - public: - Func(C _func) : func(_func) {} - - void Run() { func(); } - - private: - C const func; - }; - - template - class FuncArg - { - public: - FuncArg(C _func, A _arg) : func(_func), arg(_arg) {} - - void Run() { func(arg); } - - private: - C const func; - A arg; - }; - - template - static THREAD_RETURN RunAndDelete(void* param) - { -#ifdef __APPLE__ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -#endif - static_cast(param)->Run(); - delete static_cast(param); -#ifdef __APPLE__ - [pool release]; -#endif - return 0; - } -}; - -namespace this_thread -{ - -inline void yield() -{ -#ifdef _WIN32 - SwitchToThread(); -#else - sleep(0); -#endif -} - -inline thread::id get_id() -{ -#ifdef _WIN32 - return GetCurrentThreadId(); -#else - return pthread_self(); -#endif -} - -} // namespace this_thread - -} // namespace std - -#undef USE_RVALUE_REFERENCES -#undef USE_BEGINTHREADEX -#undef THREAD_ID -#undef THREAD_RETURN -#undef THREAD_HANDLE - -#endif -#endif diff --git a/src/common/src/string_util.cpp b/src/common/src/string_util.cpp deleted file mode 100644 index 415dcbbc..00000000 --- a/src/common/src/string_util.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include -#include - -#include "common.h" -#include "common_paths.h" -#include "string_util.h" - -#ifdef _WIN32 - #include -#else - #include - #include -#endif - -// faster than sscanf -bool AsciiToHex(const char* _szValue, u32& result) -{ - char *endptr = NULL; - const u32 value = strtoul(_szValue, &endptr, 16); - - if (!endptr || *endptr) - return false; - - result = value; - return true; -} - -bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) -{ - int writtenCount; - -#ifdef _WIN32 - // You would think *printf are simple, right? Iterate on each character, - // if it's a format specifier handle it properly, etc. - // - // Nooooo. Not according to the C standard. - // - // According to the C99 standard (7.19.6.1 "The fprintf function") - // The format shall be a multibyte character sequence - // - // Because some character encodings might have '%' signs in the middle of - // a multibyte sequence (SJIS for example only specifies that the first - // byte of a 2 byte sequence is "high", the second byte can be anything), - // printf functions have to decode the multibyte sequences and try their - // best to not screw up. - // - // Unfortunately, on Windows, the locale for most languages is not UTF-8 - // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the - // locale, and completely fails when trying to decode UTF-8 as EUC-CN. - // - // On the other hand, the fix is simple: because we use UTF-8, no such - // multibyte handling is required as we can simply assume that no '%' char - // will be present in the middle of a multibyte sequence. - // - // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. - static locale_t c_locale = NULL; - if (!c_locale) - c_locale = _create_locale(LC_ALL, ".1252"); - writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); -#else - writtenCount = vsnprintf(out, outsize, format, args); -#endif - - if (writtenCount > 0 && writtenCount < outsize) - { - out[writtenCount] = '\0'; - return true; - } - else - { - out[outsize - 1] = '\0'; - return false; - } -} - -std::string StringFromFormat(const char* format, ...) -{ - va_list args; - char *buf = NULL; -#ifdef _WIN32 - int required = 0; - - va_start(args, format); - required = _vscprintf(format, args); - buf = new char[required + 1]; - CharArrayFromFormatV(buf, required + 1, format, args); - va_end(args); - - std::string temp = buf; - delete[] buf; -#else - va_start(args, format); - if (vasprintf(&buf, format, args) < 0) - ERROR_LOG(COMMON, "Unable to allocate memory for string"); - va_end(args); - - std::string temp = buf; - free(buf); -#endif - return temp; -} - -// For Debugging. Read out an u8 array. -std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) -{ - std::ostringstream oss; - oss << std::setfill('0') << std::hex; - - for (int line = 0; size; ++data, --size) - { - oss << std::setw(2) << (int)*data; - - if (line_len == ++line) - { - oss << '\n'; - line = 0; - } - else if (spaces) - oss << ' '; - } - - return oss.str(); -} - -// Turns " hej " into "hej". Also handles tabs. -std::string StripSpaces(const std::string &str) -{ - const size_t s = str.find_first_not_of(" \t\r\n"); - - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; -} - -// "\"hello\"" is turned to "hello" -// This one assumes that the string has already been space stripped in both -// ends, as done by StripSpaces above, for example. -std::string StripQuotes(const std::string& s) -{ - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; -} - -bool TryParse(const std::string &str, u32 *const output) -{ - char *endptr = NULL; - - // Reset errno to a value other than ERANGE - errno = 0; - - unsigned long value = strtoul(str.c_str(), &endptr, 0); - - if (!endptr || *endptr) - return false; - - if (errno == ERANGE) - return false; - -#if ULONG_MAX > UINT_MAX - if (value >= 0x100000000ull - && value <= 0xFFFFFFFF00000000ull) - return false; -#endif - - *output = static_cast(value); - return true; -} - -bool TryParse(const std::string &str, bool *const output) -{ - if ("1" == str || !strcasecmp("true", str.c_str())) - *output = true; - else if ("0" == str || !strcasecmp("false", str.c_str())) - *output = false; - else - return false; - - return true; -} - -std::string StringFromInt(int value) -{ - char temp[16]; - sprintf(temp, "%i", value); - return temp; -} - -std::string StringFromBool(bool value) -{ - return value ? "True" : "False"; -} - -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) -{ - if (full_path.empty()) - return false; - - size_t dir_end = full_path.find_last_of("/" - // windows needs the : included for something like just "C:" to be considered a directory -#ifdef _WIN32 - ":" -#endif - ); - if (std::string::npos == dir_end) - dir_end = 0; - else - dir_end += 1; - - size_t fname_end = full_path.rfind('.'); - if (fname_end < dir_end || std::string::npos == fname_end) - fname_end = full_path.size(); - - if (_pPath) - *_pPath = full_path.substr(0, dir_end); - - if (_pFilename) - *_pFilename = full_path.substr(dir_end, fname_end - dir_end); - - if (_pExtension) - *_pExtension = full_path.substr(fname_end); - - return true; -} - -void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) -{ - _CompleteFilename = _Path; - - // check for seperator - if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) - _CompleteFilename += DIR_SEP_CHR; - - // add the filename - _CompleteFilename += _Filename; -} - -void SplitString(const std::string& str, const char delim, std::vector& output) -{ - std::istringstream iss(str); - output.resize(1); - - while (std::getline(iss, *output.rbegin(), delim)) - output.push_back(""); - - output.pop_back(); -} - -std::string TabsToSpaces(int tab_size, const std::string &in) -{ - const std::string spaces(tab_size, ' '); - std::string out(in); - - size_t i = 0; - while (out.npos != (i = out.find('\t'))) - out.replace(i, 1, spaces); - - return out; -} - -std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) -{ - while(1) - { - size_t pos = result.find(src); - if (pos == std::string::npos) break; - result.replace(pos, src.size(), dest); - } - 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 -//#include - -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 _WIN32 - -std::string UTF16ToUTF8(const std::wstring& input) -{ - auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); - - std::string output; - output.resize(size); - - if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) - output.clear(); - - return output; -} - -std::wstring CPToUTF16(u32 code_page, const std::string& input) -{ - auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); - - std::wstring output; - output.resize(size); - - if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size())) - output.clear(); - - return output; -} - -std::wstring UTF8ToUTF16(const std::string& input) -{ - return CPToUTF16(CP_UTF8, input); -} - -std::string SHIFTJISToUTF8(const std::string& input) -{ - return UTF16ToUTF8(CPToUTF16(932, input)); -} - -std::string CP1252ToUTF8(const std::string& input) -{ - return UTF16ToUTF8(CPToUTF16(1252, input)); -} - -#else - -template -std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) -{ - std::string result; - - iconv_t const conv_desc = iconv_open("UTF-8", fromcode); - if ((iconv_t)-1 == conv_desc) - { - ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); - } - else - { - size_t const in_bytes = sizeof(T) * input.size(); - size_t const out_buffer_size = 4 * in_bytes; - - std::string out_buffer; - out_buffer.resize(out_buffer_size); - - auto src_buffer = &input[0]; - size_t src_bytes = in_bytes; - auto dst_buffer = &out_buffer[0]; - size_t dst_bytes = out_buffer.size(); - - while (src_bytes != 0) - { - size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, - &dst_buffer, &dst_bytes); - - if ((size_t)-1 == iconv_result) - { - if (EILSEQ == errno || EINVAL == errno) - { - // Try to skip the bad character - if (src_bytes != 0) - { - --src_bytes; - ++src_buffer; - } - } - else - { - ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); - break; - } - } - } - - out_buffer.resize(out_buffer_size - dst_bytes); - out_buffer.swap(result); - - iconv_close(conv_desc); - } - - return result; -} - -std::string CP1252ToUTF8(const std::string& input) -{ - //return CodeToUTF8("CP1252//TRANSLIT", input); - //return CodeToUTF8("CP1252//IGNORE", input); - return CodeToUTF8("CP1252", input); -} - -std::string SHIFTJISToUTF8(const std::string& input) -{ - //return CodeToUTF8("CP932", input); - return CodeToUTF8("SJIS", input); -} - -std::string UTF16ToUTF8(const std::wstring& input) -{ - std::string result = - // CodeToUTF8("UCS-2", input); - // CodeToUTF8("UCS-2LE", input); - // CodeToUTF8("UTF-16", input); - CodeToUTF8("UTF-16LE", input); - - // TODO: why is this needed? - result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); - return result; -} - -#endif diff --git a/src/common/src/string_util.h b/src/common/src/string_util.h deleted file mode 100644 index fcbae471..00000000 --- a/src/common/src/string_util.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _STRINGUTIL_H_ -#define _STRINGUTIL_H_ - -#include - -#include -#include -#include -#include - -#include "common.h" - -std::string StringFromFormat(const char* format, ...); -// Cheap! -bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); - -template -inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) -{ - va_list args; - va_start(args, format); - CharArrayFromFormatV(out, Count, format, args); - va_end(args); -} - -// Good -std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); - -std::string StripSpaces(const std::string &s); -std::string StripQuotes(const std::string &s); - -// Thousand separator. Turns 12345678 into 12,345,678 -template -std::string ThousandSeparate(I value, int spaces = 0) -{ - std::ostringstream oss; - -// std::locale("") seems to be broken on many platforms -#if defined _WIN32 || (defined __linux__ && !defined __clang__) - oss.imbue(std::locale("")); -#endif - oss << std::setw(spaces) << value; - - return oss.str(); -} - -std::string StringFromInt(int value); -std::string StringFromBool(bool value); - -bool TryParse(const std::string &str, bool *output); -bool TryParse(const std::string &str, u32 *output); - -template -static bool TryParse(const std::string &str, N *const output) -{ - std::istringstream iss(str); - - N tmp = 0; - if (iss >> tmp) - { - *output = tmp; - return true; - } - else - return false; -} - -// TODO: kill this -bool AsciiToHex(const char* _szValue, u32& result); - -std::string TabsToSpaces(int tab_size, const std::string &in); - -void SplitString(const std::string& str, char delim, std::vector& output); - -// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); - -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 CP1252ToUTF8(const std::string& str); -std::string SHIFTJISToUTF8(const std::string& str); -std::string UTF16ToUTF8(const std::wstring& str); - -#ifdef _WIN32 - -std::wstring UTF8ToUTF16(const std::string& str); - -#ifdef _UNICODE -inline std::string TStrToUTF8(const std::wstring& str) -{ return UTF16ToUTF8(str); } - -inline std::wstring UTF8ToTStr(const std::string& str) -{ return UTF8ToUTF16(str); } -#else -inline std::string TStrToUTF8(const std::string& str) -{ return str; } - -inline std::string UTF8ToTStr(const std::string& str) -{ return str; } -#endif - -#endif - -#endif // _STRINGUTIL_H_ diff --git a/src/common/src/swap.h b/src/common/src/swap.h deleted file mode 100644 index d07d9fcc..00000000 --- a/src/common/src/swap.h +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project / 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -// Android -#if defined(ANDROID) -#include - -#if _BYTE_ORDER == _LITTLE_ENDIAN && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif _BYTE_ORDER == _BIG_ENDIAN && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// GCC 4.6+ -#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - -#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// LLVM/clang -#elif __clang__ - -#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// MSVC -#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) - -#ifdef _XBOX -#define COMMON_BIG_ENDIAN 1 -#else -#define COMMON_LITTLE_ENDIAN 1 -#endif - -#endif - -// Worst case, default to little endian. -#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN -#define COMMON_LITTLE_ENDIAN 1 -#endif - -template -struct swap_struct_t { - typedef swap_struct_t swapped_t; - -protected: - T value; - - static T swap(T v) { - return F::swap(v); - } -public: - T const swap() const { - return swap(value); - - } - swap_struct_t() : value((T)0) {} - swap_struct_t(const T &v): value(swap(v)) {} - - template - swapped_t& operator=(const S &source) { - value = swap((T)source); - return *this; - } - - operator long() const { return (long)swap(); } - operator s8() const { return (s8)swap(); } - operator u8() const { return (u8)swap(); } - operator s16() const { return (s16)swap(); } - operator u16() const { return (u16)swap(); } - operator s32() const { return (s32)swap(); } - operator u32() const { return (u32)swap(); } - operator s64() const { return (s64)swap(); } - operator u64() const { return (u64)swap(); } - operator float() const { return (float)swap(); } - operator double() const { return (double)swap(); } - - // +v - swapped_t operator +() const { - return +swap(); - } - // -v - swapped_t operator -() const { - return -swap(); - } - - // v / 5 - swapped_t operator/(const swapped_t &i) const { - return swap() / i.swap(); - } - template - swapped_t operator/(const S &i) const { - return swap() / i; - } - - // v * 5 - swapped_t operator*(const swapped_t &i) const { - return swap() * i.swap(); - } - template - swapped_t operator*(const S &i) const { - return swap() * i; - } - - // v + 5 - swapped_t operator+(const swapped_t &i) const { - return swap() + i.swap(); - } - template - swapped_t operator+(const S &i) const { - return swap() + (T)i; - } - // v - 5 - swapped_t operator-(const swapped_t &i) const { - return swap() - i.swap(); - } - template - swapped_t operator-(const S &i) const { - return swap() - (T)i; - } - - // v += 5 - swapped_t& operator+=(const swapped_t &i) { - value = swap(swap() + i.swap()); - return *this; - } - template - swapped_t& operator+=(const S &i) { - value = swap(swap() + (T)i); - return *this; - } - // v -= 5 - swapped_t& operator-=(const swapped_t &i) { - value = swap(swap() - i.swap()); - return *this; - } - template - swapped_t& operator-=(const S &i) { - value = swap(swap() - (T)i); - return *this; - } - - // ++v - swapped_t& operator++() { - value = swap(swap()+1); - return *this; - } - // --v - swapped_t& operator--() { - value = swap(swap()-1); - return *this; - } - - // v++ - swapped_t operator++(int) { - swapped_t old = *this; - value = swap(swap()+1); - return old; - } - // v-- - swapped_t operator--(int) { - swapped_t old = *this; - value = swap(swap()-1); - return old; - } - // Comparaison - // v == i - bool operator==(const swapped_t &i) const { - return swap() == i.swap(); - } - template - bool operator==(const S &i) const { - return swap() == i; - } - - // v != i - bool operator!=(const swapped_t &i) const { - return swap() != i.swap(); - } - template - bool operator!=(const S &i) const { - return swap() != i; - } - - // v > i - bool operator>(const swapped_t &i) const { - return swap() > i.swap(); - } - template - bool operator>(const S &i) const { - return swap() > i; - } - - // v < i - bool operator<(const swapped_t &i) const { - return swap() < i.swap(); - } - template - bool operator<(const S &i) const { - return swap() < i; - } - - // v >= i - bool operator>=(const swapped_t &i) const { - return swap() >= i.swap(); - } - template - bool operator>=(const S &i) const { - return swap() >= i; - } - - // v <= i - bool operator<=(const swapped_t &i) const { - return swap() <= i.swap(); - } - template - bool operator<=(const S &i) const { - return swap() <= i; - } - - // logical - swapped_t operator !() const { - return !swap(); - } - - // bitmath - swapped_t operator ~() const { - return ~swap(); - } - - swapped_t operator &(const swapped_t &b) const { - return swap() & b.swap(); - } - template - swapped_t operator &(const S &b) const { - return swap() & b; - } - swapped_t& operator &=(const swapped_t &b) { - value = swap(swap() & b.swap()); - return *this; - } - template - swapped_t& operator &=(const S b) { - value = swap(swap() & b); - return *this; - } - - swapped_t operator |(const swapped_t &b) const { - return swap() | b.swap(); - } - template - swapped_t operator |(const S &b) const { - return swap() | b; - } - swapped_t& operator |=(const swapped_t &b) { - value = swap(swap() | b.swap()); - return *this; - } - template - swapped_t& operator |=(const S &b) { - value = swap(swap() | b); - return *this; - } - - swapped_t operator ^(const swapped_t &b) const { - return swap() ^ b.swap(); - } - template - swapped_t operator ^(const S &b) const { - return swap() ^ b; - } - swapped_t& operator ^=(const swapped_t &b) { - value = swap(swap() ^ b.swap()); - return *this; - } - template - swapped_t& operator ^=(const S &b) { - value = swap(swap() ^ b); - return *this; - } - - template - swapped_t operator <<(const S &b) const { - return swap() << b; - } - template - swapped_t& operator <<=(const S &b) const { - value = swap(swap() << b); - return *this; - } - - template - swapped_t operator >>(const S &b) const { - return swap() >> b; - } - template - swapped_t& operator >>=(const S &b) const { - value = swap(swap() >> b); - return *this; - } - - // Member - /** todo **/ - - - // Arithmetics - template - friend S operator+(const S &p, const swapped_t v); - - template - friend S operator-(const S &p, const swapped_t v); - - template - friend S operator/(const S &p, const swapped_t v); - - template - friend S operator*(const S &p, const swapped_t v); - - template - friend S operator%(const S &p, const swapped_t v); - - // Arithmetics + assignements - template - friend S operator+=(const S &p, const swapped_t v); - - template - friend S operator-=(const S &p, const swapped_t v); - - // Bitmath - template - friend S operator&(const S &p, const swapped_t v); - - // Comparison - template - friend bool operator<(const S &p, const swapped_t v); - - template - friend bool operator>(const S &p, const swapped_t v); - - template - friend bool operator<=(const S &p, const swapped_t v); - - template - friend bool operator>=(const S &p, const swapped_t v); - - template - friend bool operator!=(const S &p, const swapped_t v); - - template - friend bool operator==(const S &p, const swapped_t v); -}; - - -// Arithmetics -template -S operator+(const S &i, const swap_struct_t v) { - return i + v.swap(); -} - -template -S operator-(const S &i, const swap_struct_t v) { - return i - v.swap(); -} - -template -S operator/(const S &i, const swap_struct_t v) { - return i / v.swap(); -} - -template -S operator*(const S &i, const swap_struct_t v) { - return i * v.swap(); -} - -template -S operator%(const S &i, const swap_struct_t v) { - return i % v.swap(); -} - -// Arithmetics + assignements -template -S &operator+=(S &i, const swap_struct_t v) { - i += v.swap(); - return i; -} - -template -S &operator-=(S &i, const swap_struct_t v) { - i -= v.swap(); - return i; -} - -// Logical -template -S operator&(const S &i, const swap_struct_t v) { - return i & v.swap(); -} - -template -S operator&(const swap_struct_t v, const S &i) { - return (S)(v.swap() & i); -} - - -// Comparaison -template -bool operator<(const S &p, const swap_struct_t v) { - return p < v.swap(); -} -template -bool operator>(const S &p, const swap_struct_t v) { - return p > v.swap(); -} -template -bool operator<=(const S &p, const swap_struct_t v) { - return p <= v.swap(); -} -template -bool operator>=(const S &p, const swap_struct_t v) { - return p >= v.swap(); -} -template -bool operator!=(const S &p, const swap_struct_t v) { - return p != v.swap(); -} -template -bool operator==(const S &p, const swap_struct_t v) { - return p == v.swap(); -} - -template -struct swap_64_t { - static T swap(T x) { - return (T)bswap64(*(u64 *)&x); - } -}; - -template -struct swap_32_t { - static T swap(T x) { - return (T)bswap32(*(u32 *)&x); - } -}; - -template -struct swap_16_t { - static T swap(T x) { - return (T)bswap16(*(u16 *)&x); - } -}; - -template -struct swap_float_t { - static T swap(T x) { - return (T)bswapf(*(float *)&x); - } -}; - -template -struct swap_double_t { - static T swap(T x) { - return (T)bswapd(*(double *)&x); - } -}; - -#if COMMON_LITTLE_ENDIAN -typedef u32 u32_le; -typedef u16 u16_le; -typedef u64 u64_le; - -typedef s32 s32_le; -typedef s16 s16_le; -typedef s64 s64_le; - -typedef float float_le; -typedef double double_le; - -typedef swap_struct_t> u64_be; -typedef swap_struct_t> s64_be; - -typedef swap_struct_t> u32_be; -typedef swap_struct_t> s32_be; - -typedef swap_struct_t> u16_be; -typedef swap_struct_t> s16_be; - -typedef swap_struct_t > float_be; -typedef swap_struct_t > double_be; -#else - -typedef swap_struct_t> u64_le; -typedef swap_struct_t> s64_le; - -typedef swap_struct_t> u32_le; -typedef swap_struct_t> s32_le; - -typedef swap_struct_t> u16_le; -typedef swap_struct_t> s16_le; - -typedef swap_struct_t > float_le; -typedef swap_struct_t > double_le; - -typedef u32 u32_be; -typedef u16 u16_be; -typedef u64 u64_be; - -typedef s32 s32_be; -typedef s16 s16_be; -typedef s64 s64_be; - -typedef float float_be; -typedef double double_be; -#endif \ No newline at end of file diff --git a/src/common/src/thread.cpp b/src/common/src/thread.cpp deleted file mode 100644 index 27dbf3f9..00000000 --- a/src/common/src/thread.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "thread.h" -#include "common.h" - -#ifdef __APPLE__ -#include -#elif defined BSD4_4 -#include -#endif - -#ifdef USE_BEGINTHREADEX -#include -#endif - -namespace Common -{ - -int CurrentThreadId() -{ -#ifdef _WIN32 - return GetCurrentThreadId(); -#elif defined __APPLE__ - return mach_thread_self(); -#else - return 0; -#endif -} - -#ifdef _WIN32 - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) -{ - SetThreadAffinityMask(thread, mask); -} - -void SetCurrentThreadAffinity(u32 mask) -{ - SetThreadAffinityMask(GetCurrentThread(), mask); -} - -// Supporting functions -void SleepCurrentThread(int ms) -{ - Sleep(ms); -} - -void SwitchCurrentThread() -{ - SwitchToThread(); -} - -// Sets the debugger-visible name of the current thread. -// Uses undocumented (actually, it is now documented) trick. -// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp - -// This is implemented much nicer in upcoming msvc++, see: -// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx -void SetCurrentThreadName(const char* szThreadName) -{ - static const DWORD MS_VC_EXCEPTION = 0x406D1388; - - #pragma pack(push,8) - struct THREADNAME_INFO - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } info; - #pragma pack(pop) - - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = -1; //dwThreadID; - info.dwFlags = 0; - - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - {} -} - -#else // !WIN32, so must be POSIX threads - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) -{ -#ifdef __APPLE__ - thread_policy_set(pthread_mach_thread_np(thread), - THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); -#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) - cpu_set_t cpu_set; - CPU_ZERO(&cpu_set); - - for (int i = 0; i != sizeof(mask) * 8; ++i) - if ((mask >> i) & 1) - CPU_SET(i, &cpu_set); - - pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); -#endif -} - -void SetCurrentThreadAffinity(u32 mask) -{ - SetThreadAffinity(pthread_self(), mask); -} - -void SleepCurrentThread(int ms) -{ - usleep(1000 * ms); -} - -void SwitchCurrentThread() -{ - usleep(1000 * 1); -} - -void SetCurrentThreadName(const char* szThreadName) -{ -#ifdef __APPLE__ - pthread_setname_np(szThreadName); -#else - pthread_setname_np(pthread_self(), szThreadName); -#endif -} - -#endif - -} // namespace Common diff --git a/src/common/src/thread.h b/src/common/src/thread.h deleted file mode 100644 index 6384a44a..00000000 --- a/src/common/src/thread.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _THREAD_H_ -#define _THREAD_H_ - -#include "std_condition_variable.h" -#include "std_mutex.h" -#include "std_thread.h" - -// Don't include common.h here as it will break LogManager -#include "common_types.h" -#include -#include - -// This may not be defined outside _WIN32 -#ifndef _WIN32 -#ifndef INFINITE -#define INFINITE 0xffffffff -#endif - -//for gettimeofday and struct time(spec|val) -#include -#include -#endif - -namespace Common -{ - -int CurrentThreadId(); - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); -void SetCurrentThreadAffinity(u32 mask); - -class Event -{ -public: - Event() - : is_set(false) - {}; - - void Set() - { - std::lock_guard lk(m_mutex); - if (!is_set) - { - is_set = true; - m_condvar.notify_one(); - } - } - - void Wait() - { - std::unique_lock lk(m_mutex); - m_condvar.wait(lk, IsSet(this)); - is_set = false; - } - - void Reset() - { - std::unique_lock 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; - std::condition_variable m_condvar; - std::mutex m_mutex; -}; - -// TODO: doesn't work on windows with (count > 2) -class Barrier -{ -public: - Barrier(size_t count) - : m_count(count), m_waiting(0) - {} - - // block until "count" threads call Sync() - bool Sync() - { - std::unique_lock 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) - { - m_waiting = 0; - m_condvar.notify_all(); - return true; - } - else - { - m_condvar.wait(lk, IsDoneWating(this)); - return false; - } - } - -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; -}; - -void SleepCurrentThread(int ms); -void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms - -// Use this function during a spin-wait to make the current thread -// relax while another thread is working. This may be more efficient -// than using events because event functions use kernel calls. -inline void YieldCPU() -{ - std::this_thread::yield(); -} - -void SetCurrentThreadName(const char *name); - -} // namespace Common - -#endif // _THREAD_H_ diff --git a/src/common/src/thunk.h b/src/common/src/thunk.h deleted file mode 100644 index c9e6fd39..00000000 --- a/src/common/src/thunk.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _THUNK_H_ -#define _THUNK_H_ - -#include - -#include "common.h" -#include "x64Emitter.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 -// call functions from generated code, without inflicting the performance hit and increase -// of complexity that it means to protect the generated code from this problem. - -// This process is called thunking. - -// There will only ever be one level of thunking on the stack, plus, -// we don't want to pollute the stack, so we store away regs somewhere global. -// NOT THREAD SAFE. This may only be used from the CPU thread. -// Any other thread using this stuff will be FATAL. - -class ThunkManager : public Gen::XCodeBlock -{ - std::map thunks; - - const u8 *save_regs; - const u8 *load_regs; - -public: - ThunkManager() { - Init(); - } - ~ThunkManager() { - Shutdown(); - } - void *ProtectFunction(void *function, int num_params); -private: - void Init(); - void Shutdown(); - void Reset(); -}; - -#endif // _THUNK_H_ diff --git a/src/common/src/timer.cpp b/src/common/src/timer.cpp deleted file mode 100644 index 90604292..00000000 --- a/src/common/src/timer.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#endif - -#include "common.h" -#include "timer.h" -#include "string_util.h" - -namespace Common -{ - -u32 Timer::GetTimeMs() -{ -#ifdef _WIN32 - return timeGetTime(); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); -#endif -} - -// -------------------------------------------- -// Initiate, Start, Stop, and Update the time -// -------------------------------------------- - -// Set initial values for the class -Timer::Timer() - : m_LastTime(0), m_StartTime(0), m_Running(false) -{ - Update(); -} - -// Write the starting time -void Timer::Start() -{ - m_StartTime = GetTimeMs(); - m_Running = true; -} - -// Stop the timer -void Timer::Stop() -{ - // Write the final time - m_LastTime = GetTimeMs(); - m_Running = false; -} - -// Update the last time variable -void Timer::Update() -{ - m_LastTime = GetTimeMs(); - //TODO(ector) - QPF -} - -// ------------------------------------- -// Get time difference and elapsed time -// ------------------------------------- - -// Get the number of milliseconds since the last Update() -u64 Timer::GetTimeDifference() -{ - return GetTimeMs() - m_LastTime; -} - -// Add the time difference since the last Update() to the starting time. -// This is used to compensate for a paused game. -void Timer::AddTimeDifference() -{ - m_StartTime += GetTimeDifference(); -} - -// Get the time elapsed since the Start() -u64 Timer::GetTimeElapsed() -{ - // If we have not started yet, return 1 (because then I don't - // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) return 1; - - // Return the final timer time if the timer is stopped - if (!m_Running) return (m_LastTime - m_StartTime); - - return (GetTimeMs() - m_StartTime); -} - -// Get the formatted time elapsed since the Start() -std::string Timer::GetTimeElapsedFormatted() const -{ - // If we have not started yet, return zero - if (m_StartTime == 0) - return "00:00:00:000"; - - // The number of milliseconds since the start. - // Use a different value if the timer is stopped. - u64 Milliseconds; - if (m_Running) - Milliseconds = GetTimeMs() - m_StartTime; - else - Milliseconds = m_LastTime - m_StartTime; - // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); - // Minutes - u32 Minutes = Seconds / 60; - // Hours - u32 Hours = Minutes / 60; - - std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", - Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); - return TmpStr; -} - -// Get current time -void Timer::IncreaseResolution() -{ -#ifdef _WIN32 - timeBeginPeriod(1); -#endif -} - -void Timer::RestoreResolution() -{ -#ifdef _WIN32 - timeEndPeriod(1); -#endif -} - -// Get the number of seconds since January 1 1970 -u64 Timer::GetTimeSinceJan1970() -{ - time_t ltime; - time(<ime); - return((u64)ltime); -} - -u64 Timer::GetLocalTimeSinceJan1970() -{ - time_t sysTime, tzDiff, tzDST; - struct tm * gmTime; - - time(&sysTime); - - // Account for DST where needed - gmTime = localtime(&sysTime); - if(gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; - - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); - - return (u64)(sysTime + tzDiff + tzDST); -} - -// Return the current time formatted as Minutes:Seconds:Milliseconds -// in the form 00:00:000. -std::string Timer::GetTimeFormatted() -{ - time_t sysTime; - struct tm * gmTime; - char formattedTime[13]; - char tmp[13]; - - time(&sysTime); - gmTime = localtime(&sysTime); - - strftime(tmp, 6, "%M:%S", gmTime); - - // Now tack on the milliseconds -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); - sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); -#endif - - return std::string(formattedTime); -} - -// Returns a timestamp with decimals for precise time comparisons -// ---------------- -double Timer::GetDoubleTime() -{ -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); -#endif - // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); - - // Remove a few years. We only really want enough seconds to make - // sure that we are detecting actual actions, perhaps 60 seconds is - // enough really, but I leave a year of seconds anyway, in case the - // user's clock is incorrect or something like that. - TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); - - // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; -#ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; -#else - double ms = t.tv_usec / 1000000.0; -#endif - double TmpTime = Seconds + ms; - - return TmpTime; -} - -} // Namespace Common diff --git a/src/common/src/timer.h b/src/common/src/timer.h deleted file mode 100644 index 20c86762..00000000 --- a/src/common/src/timer.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include "common.h" -#include - -namespace Common -{ -class Timer -{ -public: - Timer(); - - void Start(); - void Stop(); - void Update(); - - // The time difference is always returned in milliseconds, regardless of alternative internal representation - u64 GetTimeDifference(); - void AddTimeDifference(); - - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); - static double GetDoubleTime(); - - static std::string GetTimeFormatted(); - std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed(); - - static u32 GetTimeMs(); - -private: - u64 m_LastTime; - u64 m_StartTime; - bool m_Running; -}; - -} // Namespace Common - -#endif // _TIMER_H_ diff --git a/src/common/src/utf8.cpp b/src/common/src/utf8.cpp deleted file mode 100644 index 9aa8088e..00000000 --- a/src/common/src/utf8.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/* - Basic UTF-8 manipulation routines - by Jeff Bezanson - placed in the public domain Fall 2005 - - This code is designed to provide the utilities you need to manipulate - UTF-8 as an internal string encoding. These functions do not perform the - error checking normally needed when handling UTF-8 data, so if you happen - to be from the Unicode Consortium you will want to flay me alive. - I do this because error checking can be performed at the boundaries (I/O), - with these routines reserved for higher performance on data known to be - valid. -*/ - -#ifdef _WIN32 -#include -#undef min -#undef max -#endif - -#include -#include -#include -#include - -#include -#include - -#include "common_types.h" -#include "utf8.h" - -// is start of UTF sequence -inline bool isutf(char c) { - return (c & 0xC0) != 0x80; -} - -static const u32 offsetsFromUTF8[6] = { - 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL -}; - -static const u8 trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5, -}; - -/* returns length of next utf-8 sequence */ -int u8_seqlen(const char *s) -{ - return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1; -} - -/* conversions without error checking - only works for valid UTF-8, i.e. no 5- or 6-byte sequences - srcsz = source size in bytes, or -1 if 0-terminated - sz = dest size in # of wide characters - - returns # characters converted - dest will always be L'\0'-terminated, even if there isn't enough room - for all the characters. - if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. -*/ -int u8_toucs(u32 *dest, int sz, const char *src, int srcsz) -{ - u32 ch; - const char *src_end = src + srcsz; - int nb; - int i=0; - - while (i < sz-1) { - nb = trailingBytesForUTF8[(unsigned char)*src]; - if (srcsz == -1) { - if (*src == 0) - goto done_toucs; - } - else { - if (src + nb >= src_end) - goto done_toucs; - } - ch = 0; - switch (nb) { - /* these fall through deliberately */ - case 3: ch += (unsigned char)*src++; ch <<= 6; - case 2: ch += (unsigned char)*src++; ch <<= 6; - case 1: ch += (unsigned char)*src++; ch <<= 6; - case 0: ch += (unsigned char)*src++; - } - ch -= offsetsFromUTF8[nb]; - dest[i++] = ch; - } - done_toucs: - dest[i] = 0; - return i; -} - -/* srcsz = number of source characters, or -1 if 0-terminated - sz = size of dest buffer in bytes - - returns # characters converted - dest will only be '\0'-terminated if there is enough space. this is - for consistency; imagine there are 2 bytes of space left, but the next - character requires 3 bytes. in this case we could NUL-terminate, but in - general we can't when there's insufficient space. therefore this function - only NUL-terminates if all the characters fit, and there's space for - the NUL as well. - the destination string will never be bigger than the source string. -*/ -int u8_toutf8(char *dest, int sz, u32 *src, int srcsz) -{ - u32 ch; - int i = 0; - char *dest_end = dest + sz; - - while (srcsz<0 ? src[i]!=0 : i < srcsz) { - ch = src[i]; - if (ch < 0x80) { - if (dest >= dest_end) - return i; - *dest++ = (char)ch; - } - else if (ch < 0x800) { - if (dest >= dest_end-1) - return i; - *dest++ = (ch>>6) | 0xC0; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x10000) { - if (dest >= dest_end-2) - return i; - *dest++ = (ch>>12) | 0xE0; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x110000) { - if (dest >= dest_end-3) - return i; - *dest++ = (ch>>18) | 0xF0; - *dest++ = ((ch>>12) & 0x3F) | 0x80; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - i++; - } - if (dest < dest_end) - *dest = '\0'; - return i; -} - -int u8_wc_toutf8(char *dest, u32 ch) -{ - if (ch < 0x80) { - dest[0] = (char)ch; - return 1; - } - if (ch < 0x800) { - dest[0] = (ch>>6) | 0xC0; - dest[1] = (ch & 0x3F) | 0x80; - return 2; - } - if (ch < 0x10000) { - dest[0] = (ch>>12) | 0xE0; - dest[1] = ((ch>>6) & 0x3F) | 0x80; - dest[2] = (ch & 0x3F) | 0x80; - return 3; - } - if (ch < 0x110000) { - dest[0] = (ch>>18) | 0xF0; - dest[1] = ((ch>>12) & 0x3F) | 0x80; - dest[2] = ((ch>>6) & 0x3F) | 0x80; - dest[3] = (ch & 0x3F) | 0x80; - return 4; - } - return 0; -} - -/* charnum => byte offset */ -int u8_offset(const char *str, int charnum) -{ - int offs=0; - - while (charnum > 0 && str[offs]) { - (void)(isutf(str[++offs]) || isutf(str[++offs]) || - isutf(str[++offs]) || ++offs); - charnum--; - } - return offs; -} - -/* byte offset => charnum */ -int u8_charnum(const char *s, int offset) -{ - int charnum = 0, offs=0; - - while (offs < offset && s[offs]) { - (void)(isutf(s[++offs]) || isutf(s[++offs]) || - isutf(s[++offs]) || ++offs); - charnum++; - } - return charnum; -} - -/* number of characters */ -int u8_strlen(const char *s) -{ - int count = 0; - int i = 0; - - while (u8_nextchar(s, &i) != 0) - count++; - - return count; -} - -/* reads the next utf-8 sequence out of a string, updating an index */ -u32 u8_nextchar(const char *s, int *i) -{ - u32 ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += (unsigned char)s[(*i)++]; - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; -} - -void u8_inc(const char *s, int *i) -{ - (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || - isutf(s[++(*i)]) || ++(*i)); -} - -void u8_dec(const char *s, int *i) -{ - (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || - isutf(s[--(*i)]) || --(*i)); -} - -int octal_digit(char c) -{ - return (c >= '0' && c <= '7'); -} - -int hex_digit(char c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f')); -} - -/* assumes that src points to the character after a backslash - returns number of input characters processed */ -int u8_read_escape_sequence(const char *str, u32 *dest) -{ - u32 ch; - char digs[9]="\0\0\0\0\0\0\0\0"; - int dno=0, i=1; - - ch = (u32)str[0]; /* take literal character */ - if (str[0] == 'n') - ch = L'\n'; - else if (str[0] == 't') - ch = L'\t'; - else if (str[0] == 'r') - ch = L'\r'; - else if (str[0] == 'b') - ch = L'\b'; - else if (str[0] == 'f') - ch = L'\f'; - else if (str[0] == 'v') - ch = L'\v'; - else if (str[0] == 'a') - ch = L'\a'; - else if (octal_digit(str[0])) { - i = 0; - do { - digs[dno++] = str[i++]; - } while (octal_digit(str[i]) && dno < 3); - ch = strtol(digs, NULL, 8); - } - else if (str[0] == 'x') { - while (hex_digit(str[i]) && dno < 2) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'u') { - while (hex_digit(str[i]) && dno < 4) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'U') { - while (hex_digit(str[i]) && dno < 8) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - *dest = ch; - - return i; -} - -/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 - example: u8_unescape(mybuf, 256, "hello\\u220e") - note the double backslash is needed if called on a C string literal */ -int u8_unescape(char *buf, int sz, char *src) -{ - int c=0, amt; - u32 ch; - char temp[4]; - - while (*src && c < sz) { - if (*src == '\\') { - src++; - amt = u8_read_escape_sequence(src, &ch); - } - else { - ch = (u32)*src; - amt = 1; - } - src += amt; - amt = u8_wc_toutf8(temp, ch); - if (amt > sz-c) - break; - memcpy(&buf[c], temp, amt); - c += amt; - } - if (c < sz) - buf[c] = '\0'; - return c; -} - -const char *u8_strchr(const char *s, u32 ch, int *charn) -{ - int i = 0, lasti=0; - u32 c; - - *charn = 0; - while (s[i]) { - c = u8_nextchar(s, &i); - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn) -{ - u32 i = 0, lasti=0; - u32 c; - int csz; - - *charn = 0; - while (i < sz) { - c = csz = 0; - do { - c <<= 6; - c += (unsigned char)s[i++]; - csz++; - } while (i < sz && !isutf(s[i])); - c -= offsetsFromUTF8[csz-1]; - - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -int u8_is_locale_utf8(const char *locale) -{ - /* this code based on libutf8 */ - const char* cp = locale; - - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { - if (*cp == '.') { - const char* encoding = ++cp; - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) - ; - if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) - || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) - return 1; /* it's UTF-8 */ - break; - } - } - return 0; -} - -int UTF8StringNonASCIICount(const char *utf8string) { - UTF8 utf(utf8string); - int count = 0; - while (!utf.end()) { - int c = utf.next(); - if (c > 127) - ++count; - } - return count; -} - -bool UTF8StringHasNonASCII(const char *utf8string) { - return UTF8StringNonASCIICount(utf8string) > 0; -} - -#ifdef _WIN32 - -std::string ConvertWStringToUTF8(const wchar_t *wstr) { - int len = (int)wcslen(wstr); - int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL); - std::string s; - s.resize(size); - if (size > 0) { - WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL); - } - return s; -} - -std::string ConvertWStringToUTF8(const std::wstring &wstr) { - int len = (int)wstr.size(); - int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL); - std::string s; - s.resize(size); - if (size > 0) { - WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL); - } - return s; -} - -void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) { - int len = (int)source.size(); - int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); - MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); -} - -std::wstring ConvertUTF8ToWString(const std::string &source) { - int len = (int)source.size(); - int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); - std::wstring str; - str.resize(size); - if (size > 0) { - MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, &str[0], size); - } - return str; -} - -#endif \ No newline at end of file diff --git a/src/common/src/utf8.h b/src/common/src/utf8.h deleted file mode 100644 index 36cf7571..00000000 --- a/src/common/src/utf8.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Basic UTF-8 manipulation routines - by Jeff Bezanson - placed in the public domain Fall 2005 - - This code is designed to provide the utilities you need to manipulate - UTF-8 as an internal string encoding. These functions do not perform the - error checking normally needed when handling UTF-8 data, so if you happen - to be from the Unicode Consortium you will want to flay me alive. - I do this because error checking can be performed at the boundaries (I/O), - with these routines reserved for higher performance on data known to be - valid. -*/ - -// Further modified, and C++ stuff added, by hrydgard@gmail.com. - -#pragma once - -#include "common_types.h" -#include - -u32 u8_nextchar(const char *s, int *i); -int u8_wc_toutf8(char *dest, u32 ch); -int u8_strlen(const char *s); - -class UTF8 { -public: - static const u32 INVALID = (u32)-1; - UTF8(const char *c) : c_(c), index_(0) {} - bool end() const { return c_[index_] == 0; } - u32 next() { - return u8_nextchar(c_, &index_); - } - u32 peek() { - int tempIndex = index_; - return u8_nextchar(c_, &tempIndex); - } - int length() const { - return u8_strlen(c_); - } - int byteIndex() const { - return index_; - } - static int encode(char *dest, u32 ch) { - return u8_wc_toutf8(dest, ch); - } - -private: - const char *c_; - int index_; -}; - -int UTF8StringNonASCIICount(const char *utf8string); - -bool UTF8StringHasNonASCII(const char *utf8string); - - -// UTF8 to Win32 UTF-16 -// Should be used when calling Win32 api calls -#ifdef _WIN32 - -std::string ConvertWStringToUTF8(const std::wstring &wstr); -std::string ConvertWStringToUTF8(const wchar_t *wstr); -void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source); -std::wstring ConvertUTF8ToWString(const std::string &source); - -#endif \ No newline at end of file diff --git a/src/common/src/version.cpp b/src/common/src/version.cpp deleted file mode 100644 index 01890dbb..00000000 --- a/src/common/src/version.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "scm_rev.h" - -#ifdef _DEBUG - #define BUILD_TYPE_STR "Debug " -#elif defined DEBUGFAST - #define BUILD_TYPE_STR "DebugFast " -#else - #define BUILD_TYPE_STR "" -#endif - -const char *scm_rev_str = "emu " -#if !SCM_IS_MASTER - "[" SCM_BRANCH_STR "] " -#endif - -#ifdef __INTEL_COMPILER - BUILD_TYPE_STR SCM_DESC_STR "-ICC"; -#else - BUILD_TYPE_STR SCM_DESC_STR; -#endif - -#ifdef _M_X64 -#define NP_ARCH "x64" -#else -#ifdef _M_ARM -#define NP_ARCH "ARM" -#else -#define NP_ARCH "x86" -#endif -#endif - -#ifdef _WIN32 -const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH; -#elif __APPLE__ -const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH; -#else -const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH; -#endif - -const char *scm_rev_git_str = SCM_REV_STR; diff --git a/src/common/std_condition_variable.h b/src/common/std_condition_variable.h new file mode 100644 index 00000000..cee7a9dc --- /dev/null +++ b/src/common/std_condition_variable.h @@ -0,0 +1,170 @@ + +#ifndef CONDITION_VARIABLE_H_ +#define CONDITION_VARIABLE_H_ + +#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) +#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ + +// GCC 4.4 provides +#include + +#elif __has_include() && !ANDROID + +// clang and libc++ provide on OSX. However, the version +// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable. +// +// We work around this issue by undefining and redefining _. + +#undef _ +#include +#define _(s) wxGetTranslation((s)) + +#else + +// partial std::condition_variable implementation for win32/pthread + +#include "std_mutex.h" + +#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) +#define USE_RVALUE_REFERENCES +#endif + +#if defined(_WIN32) && defined(_M_X64) +#define USE_CONDITION_VARIABLES +#elif defined(_WIN32) +#define USE_EVENTS +#endif + +namespace std +{ + +class condition_variable +{ +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + typedef CONDITION_VARIABLE native_type; +#elif defined(_WIN32) + typedef HANDLE native_type; +#else + typedef pthread_cond_t native_type; +#endif + +public: + +#ifdef USE_EVENTS + typedef native_type native_handle_type; +#else + typedef native_type* native_handle_type; +#endif + + condition_variable() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + InitializeConditionVariable(&m_handle); +#elif defined(_WIN32) + m_handle = CreateEvent(NULL, false, false, NULL); +#else + pthread_cond_init(&m_handle, NULL); +#endif + } + + ~condition_variable() + { +#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES) + CloseHandle(m_handle); +#elif !defined(_WIN32) + pthread_cond_destroy(&m_handle); +#endif + } + + condition_variable(const condition_variable&) /*= delete*/; + condition_variable& operator=(const condition_variable&) /*= delete*/; + + void notify_one() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + WakeConditionVariable(&m_handle); +#elif defined(_WIN32) + SetEvent(m_handle); +#else + pthread_cond_signal(&m_handle); +#endif + } + + void notify_all() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + WakeAllConditionVariable(&m_handle); +#elif defined(_WIN32) + // TODO: broken + SetEvent(m_handle); +#else + pthread_cond_broadcast(&m_handle); +#endif + } + + void wait(unique_lock& lock) + { +#ifdef _WIN32 + #ifdef USE_SRWLOCKS + SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0); + #elif defined(USE_CONDITION_VARIABLES) + SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE); + #else + // TODO: broken, the unlock and wait need to be atomic + lock.unlock(); + WaitForSingleObject(m_handle, INFINITE); + lock.lock(); + #endif +#else + pthread_cond_wait(&m_handle, lock.mutex()->native_handle()); +#endif + } + + template + void wait(unique_lock& lock, Predicate pred) + { + while (!pred()) + wait(lock); + } + + //template + //cv_status wait_until(unique_lock& lock, + // const chrono::time_point& abs_time); + + //template + // bool wait_until(unique_lock& lock, + // const chrono::time_point& abs_time, + // Predicate pred); + + //template + //cv_status wait_for(unique_lock& lock, + // const chrono::duration& rel_time); + + //template + // bool wait_for(unique_lock& lock, + // const chrono::duration& rel_time, + // Predicate pred); + + native_handle_type native_handle() + { +#ifdef USE_EVENTS + return m_handle; +#else + return &m_handle; +#endif + } + +private: + native_type m_handle; +}; + +} + +#endif +#endif diff --git a/src/common/std_mutex.h b/src/common/std_mutex.h new file mode 100644 index 00000000..26eb58b6 --- /dev/null +++ b/src/common/std_mutex.h @@ -0,0 +1,365 @@ + +#ifndef MUTEX_H_ +#define MUTEX_H_ + +#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) +#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +// GCC 4.4 provides +#include +#elif __has_include() && !ANDROID +// Clang + libc++ +#include +#else + +// partial implementation for win32/pthread + +#include + +#if defined(_WIN32) +// WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +#else +// POSIX +#include + +#endif + +#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) +#define USE_RVALUE_REFERENCES +#endif + +#if defined(_WIN32) && defined(_M_X64) +#define USE_SRWLOCKS +#endif + +namespace std +{ + +class recursive_mutex +{ +#ifdef _WIN32 + typedef CRITICAL_SECTION native_type; +#else + typedef pthread_mutex_t native_type; +#endif + +public: + typedef native_type* native_handle_type; + + recursive_mutex(const recursive_mutex&) /*= delete*/; + recursive_mutex& operator=(const recursive_mutex&) /*= delete*/; + + recursive_mutex() + { +#ifdef _WIN32 + InitializeCriticalSection(&m_handle); +#else + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_handle, &attr); +#endif + } + + ~recursive_mutex() + { +#ifdef _WIN32 + DeleteCriticalSection(&m_handle); +#else + pthread_mutex_destroy(&m_handle); +#endif + } + + void lock() + { +#ifdef _WIN32 + EnterCriticalSection(&m_handle); +#else + pthread_mutex_lock(&m_handle); +#endif + } + + void unlock() + { +#ifdef _WIN32 + LeaveCriticalSection(&m_handle); +#else + pthread_mutex_unlock(&m_handle); +#endif + } + + bool try_lock() + { +#ifdef _WIN32 + return (0 != TryEnterCriticalSection(&m_handle)); +#else + return !pthread_mutex_trylock(&m_handle); +#endif + } + + native_handle_type native_handle() + { + return &m_handle; + } + +private: + native_type m_handle; +}; + +#if !defined(_WIN32) || defined(USE_SRWLOCKS) + +class mutex +{ +#ifdef _WIN32 + typedef SRWLOCK native_type; +#else + typedef pthread_mutex_t native_type; +#endif + +public: + typedef native_type* native_handle_type; + + mutex(const mutex&) /*= delete*/; + mutex& operator=(const mutex&) /*= delete*/; + + mutex() + { +#ifdef _WIN32 + InitializeSRWLock(&m_handle); +#else + pthread_mutex_init(&m_handle, NULL); +#endif + } + + ~mutex() + { +#ifdef _WIN32 +#else + pthread_mutex_destroy(&m_handle); +#endif + } + + void lock() + { +#ifdef _WIN32 + AcquireSRWLockExclusive(&m_handle); +#else + pthread_mutex_lock(&m_handle); +#endif + } + + void unlock() + { +#ifdef _WIN32 + ReleaseSRWLockExclusive(&m_handle); +#else + pthread_mutex_unlock(&m_handle); +#endif + } + + bool try_lock() + { +#ifdef _WIN32 + // XXX TryAcquireSRWLockExclusive requires Windows 7! + // return (0 != TryAcquireSRWLockExclusive(&m_handle)); + return false; +#else + return !pthread_mutex_trylock(&m_handle); +#endif + } + + native_handle_type native_handle() + { + return &m_handle; + } + +private: + native_type m_handle; +}; + +#else +typedef recursive_mutex mutex; // just use CriticalSections + +#endif + +enum defer_lock_t { defer_lock }; +enum try_to_lock_t { try_to_lock }; +enum adopt_lock_t { adopt_lock }; + +template +class lock_guard +{ +public: + typedef Mutex mutex_type; + + explicit lock_guard(mutex_type& m) + : pm(m) + { + m.lock(); + } + + lock_guard(mutex_type& m, adopt_lock_t) + : pm(m) + { + } + + ~lock_guard() + { + pm.unlock(); + } + + lock_guard(lock_guard const&) /*= delete*/; + lock_guard& operator=(lock_guard const&) /*= delete*/; + +private: + mutex_type& pm; +}; + +template +class unique_lock +{ +public: + typedef Mutex mutex_type; + + unique_lock() + : pm(NULL), owns(false) + {} + + /*explicit*/ unique_lock(mutex_type& m) + : pm(&m), owns(true) + { + m.lock(); + } + + unique_lock(mutex_type& m, defer_lock_t) + : pm(&m), owns(false) + {} + + unique_lock(mutex_type& m, try_to_lock_t) + : pm(&m), owns(m.try_lock()) + {} + + unique_lock(mutex_type& m, adopt_lock_t) + : pm(&m), owns(true) + {} + + //template + //unique_lock(mutex_type& m, const chrono::time_point& abs_time); + + //template + //unique_lock(mutex_type& m, const chrono::duration& rel_time); + + ~unique_lock() + { + if (owns_lock()) + mutex()->unlock(); + } + +#ifdef USE_RVALUE_REFERENCES + unique_lock& operator=(const unique_lock&) /*= delete*/; + + unique_lock& operator=(unique_lock&& other) + { +#else + unique_lock& operator=(const unique_lock& u) + { + // ugly const_cast to get around lack of rvalue references + unique_lock& other = const_cast(u); +#endif + swap(other); + return *this; + } + +#ifdef USE_RVALUE_REFERENCES + unique_lock(const unique_lock&) /*= delete*/; + + unique_lock(unique_lock&& other) + : pm(NULL), owns(false) + { +#else + unique_lock(const unique_lock& u) + : pm(NULL), owns(false) + { + // ugly const_cast to get around lack of rvalue references + unique_lock& other = const_cast(u); +#endif + swap(other); + } + + void lock() + { + mutex()->lock(); + owns = true; + } + + bool try_lock() + { + owns = mutex()->try_lock(); + return owns; + } + + //template + //bool try_lock_for(const chrono::duration& rel_time); + //template + //bool try_lock_until(const chrono::time_point& abs_time); + + void unlock() + { + mutex()->unlock(); + owns = false; + } + + void swap(unique_lock& u) + { + std::swap(pm, u.pm); + std::swap(owns, u.owns); + } + + mutex_type* release() + { + auto const ret = mutex(); + + pm = NULL; + owns = false; + + return ret; + } + + bool owns_lock() const + { + return owns; + } + + //explicit operator bool () const + //{ + // return owns_lock(); + //} + + mutex_type* mutex() const + { + return pm; + } + +private: + mutex_type* pm; + bool owns; +}; + +template +void swap(unique_lock& x, unique_lock& y) +{ + x.swap(y); +} + +} + +#endif +#endif diff --git a/src/common/std_thread.h b/src/common/std_thread.h new file mode 100644 index 00000000..9ed0072c --- /dev/null +++ b/src/common/std_thread.h @@ -0,0 +1,317 @@ + +#ifndef STD_THREAD_H_ +#define STD_THREAD_H_ + +#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) +#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +// GCC 4.4 provides +#ifndef _GLIBCXX_USE_SCHED_YIELD +#define _GLIBCXX_USE_SCHED_YIELD +#endif +#include +#elif __has_include() && !ANDROID +// Clang + libc++ +#include +#else + +// partial std::thread implementation for win32/pthread + +#include + +#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) +#define USE_RVALUE_REFERENCES +#endif + +#ifdef __APPLE__ +#import +#endif + +#if defined(_WIN32) +// WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#if defined(_MSC_VER) && defined(_MT) +// When linking with LIBCMT (the multithreaded C library), Microsoft recommends +// using _beginthreadex instead of CreateThread. +#define USE_BEGINTHREADEX +#include +#endif + +#ifdef USE_BEGINTHREADEX +#define THREAD_ID unsigned +#define THREAD_RETURN unsigned __stdcall +#else +#define THREAD_ID DWORD +#define THREAD_RETURN DWORD WINAPI +#endif +#define THREAD_HANDLE HANDLE + +#else +// PTHREAD + +#include + +#ifndef _POSIX_THREADS +#error unsupported platform (no pthreads?) +#endif + +#include + +#define THREAD_ID pthread_t +#define THREAD_HANDLE pthread_t +#define THREAD_RETURN void* + +#endif + +namespace std +{ + +class thread +{ +public: + typedef THREAD_HANDLE native_handle_type; + + class id + { + friend class thread; + public: + id() : m_thread(0) {} + id(THREAD_ID _id) : m_thread(_id) {} + + bool operator==(const id& rhs) const + { + return m_thread == rhs.m_thread; + } + + bool operator!=(const id& rhs) const + { + return !(*this == rhs); + } + + bool operator<(const id& rhs) const + { + return m_thread < rhs.m_thread; + } + + private: + THREAD_ID m_thread; + }; + + // no variadic template support in msvc + //template + //thread(C&& func, A&&... args); + + template + thread(C func) + { + StartThread(new Func(func)); + } + + template + thread(C func, A arg) + { + StartThread(new FuncArg(func, arg)); + } + + thread() /*= default;*/ {} + +#ifdef USE_RVALUE_REFERENCES + thread(const thread&) /*= delete*/; + + thread(thread&& other) + { +#else + thread(const thread& t) + { + // ugly const_cast to get around lack of rvalue references + thread& other = const_cast(t); +#endif + swap(other); + } + +#ifdef USE_RVALUE_REFERENCES + thread& operator=(const thread&) /*= delete*/; + + thread& operator=(thread&& other) + { +#else + thread& operator=(const thread& t) + { + // ugly const_cast to get around lack of rvalue references + thread& other = const_cast(t); +#endif + if (joinable()) + detach(); + swap(other); + return *this; + } + + ~thread() + { + if (joinable()) + detach(); + } + + bool joinable() const + { + return m_id != id(); + } + + id get_id() const + { + return m_id; + } + + native_handle_type native_handle() + { +#ifdef _WIN32 + return m_handle; +#else + return m_id.m_thread; +#endif + } + + void join() + { +#ifdef _WIN32 + WaitForSingleObject(m_handle, INFINITE); + detach(); +#else + pthread_join(m_id.m_thread, NULL); + m_id = id(); +#endif + } + + void detach() + { +#ifdef _WIN32 + CloseHandle(m_handle); +#else + pthread_detach(m_id.m_thread); +#endif + m_id = id(); + } + + void swap(thread& other) + { + std::swap(m_id, other.m_id); +#ifdef _WIN32 + std::swap(m_handle, other.m_handle); +#endif + } + + static unsigned hardware_concurrency() + { +#ifdef _WIN32 + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return static_cast(sysinfo.dwNumberOfProcessors); +#else + return 0; +#endif + } + +private: + id m_id; + +#ifdef _WIN32 + native_handle_type m_handle; +#endif + + template + void StartThread(F* param) + { +#ifdef USE_BEGINTHREADEX + m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); +#elif defined(_WIN32) + m_handle = CreateThread(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); +#else + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 1024 * 1024); + if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete, param)) + m_id = id(); +#endif + } + + template + class Func + { + public: + Func(C _func) : func(_func) {} + + void Run() { func(); } + + private: + C const func; + }; + + template + class FuncArg + { + public: + FuncArg(C _func, A _arg) : func(_func), arg(_arg) {} + + void Run() { func(arg); } + + private: + C const func; + A arg; + }; + + template + static THREAD_RETURN RunAndDelete(void* param) + { +#ifdef __APPLE__ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +#endif + static_cast(param)->Run(); + delete static_cast(param); +#ifdef __APPLE__ + [pool release]; +#endif + return 0; + } +}; + +namespace this_thread +{ + +inline void yield() +{ +#ifdef _WIN32 + SwitchToThread(); +#else + sleep(0); +#endif +} + +inline thread::id get_id() +{ +#ifdef _WIN32 + return GetCurrentThreadId(); +#else + return pthread_self(); +#endif +} + +} // namespace this_thread + +} // namespace std + +#undef USE_RVALUE_REFERENCES +#undef USE_BEGINTHREADEX +#undef THREAD_ID +#undef THREAD_RETURN +#undef THREAD_HANDLE + +#endif +#endif diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp new file mode 100644 index 00000000..415dcbbc --- /dev/null +++ b/src/common/string_util.cpp @@ -0,0 +1,531 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include + +#include "common.h" +#include "common_paths.h" +#include "string_util.h" + +#ifdef _WIN32 + #include +#else + #include + #include +#endif + +// faster than sscanf +bool AsciiToHex(const char* _szValue, u32& result) +{ + char *endptr = NULL; + const u32 value = strtoul(_szValue, &endptr, 16); + + if (!endptr || *endptr) + return false; + + result = value; + return true; +} + +bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) +{ + int writtenCount; + +#ifdef _WIN32 + // You would think *printf are simple, right? Iterate on each character, + // if it's a format specifier handle it properly, etc. + // + // Nooooo. Not according to the C standard. + // + // According to the C99 standard (7.19.6.1 "The fprintf function") + // The format shall be a multibyte character sequence + // + // Because some character encodings might have '%' signs in the middle of + // a multibyte sequence (SJIS for example only specifies that the first + // byte of a 2 byte sequence is "high", the second byte can be anything), + // printf functions have to decode the multibyte sequences and try their + // best to not screw up. + // + // Unfortunately, on Windows, the locale for most languages is not UTF-8 + // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the + // locale, and completely fails when trying to decode UTF-8 as EUC-CN. + // + // On the other hand, the fix is simple: because we use UTF-8, no such + // multibyte handling is required as we can simply assume that no '%' char + // will be present in the middle of a multibyte sequence. + // + // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. + static locale_t c_locale = NULL; + if (!c_locale) + c_locale = _create_locale(LC_ALL, ".1252"); + writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); +#else + writtenCount = vsnprintf(out, outsize, format, args); +#endif + + if (writtenCount > 0 && writtenCount < outsize) + { + out[writtenCount] = '\0'; + return true; + } + else + { + out[outsize - 1] = '\0'; + return false; + } +} + +std::string StringFromFormat(const char* format, ...) +{ + va_list args; + char *buf = NULL; +#ifdef _WIN32 + int required = 0; + + va_start(args, format); + required = _vscprintf(format, args); + buf = new char[required + 1]; + CharArrayFromFormatV(buf, required + 1, format, args); + va_end(args); + + std::string temp = buf; + delete[] buf; +#else + va_start(args, format); + if (vasprintf(&buf, format, args) < 0) + ERROR_LOG(COMMON, "Unable to allocate memory for string"); + va_end(args); + + std::string temp = buf; + free(buf); +#endif + return temp; +} + +// For Debugging. Read out an u8 array. +std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) +{ + std::ostringstream oss; + oss << std::setfill('0') << std::hex; + + for (int line = 0; size; ++data, --size) + { + oss << std::setw(2) << (int)*data; + + if (line_len == ++line) + { + oss << '\n'; + line = 0; + } + else if (spaces) + oss << ' '; + } + + return oss.str(); +} + +// Turns " hej " into "hej". Also handles tabs. +std::string StripSpaces(const std::string &str) +{ + const size_t s = str.find_first_not_of(" \t\r\n"); + + if (str.npos != s) + return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); + else + return ""; +} + +// "\"hello\"" is turned to "hello" +// This one assumes that the string has already been space stripped in both +// ends, as done by StripSpaces above, for example. +std::string StripQuotes(const std::string& s) +{ + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return s.substr(1, s.size() - 2); + else + return s; +} + +bool TryParse(const std::string &str, u32 *const output) +{ + char *endptr = NULL; + + // Reset errno to a value other than ERANGE + errno = 0; + + unsigned long value = strtoul(str.c_str(), &endptr, 0); + + if (!endptr || *endptr) + return false; + + if (errno == ERANGE) + return false; + +#if ULONG_MAX > UINT_MAX + if (value >= 0x100000000ull + && value <= 0xFFFFFFFF00000000ull) + return false; +#endif + + *output = static_cast(value); + return true; +} + +bool TryParse(const std::string &str, bool *const output) +{ + if ("1" == str || !strcasecmp("true", str.c_str())) + *output = true; + else if ("0" == str || !strcasecmp("false", str.c_str())) + *output = false; + else + return false; + + return true; +} + +std::string StringFromInt(int value) +{ + char temp[16]; + sprintf(temp, "%i", value); + return temp; +} + +std::string StringFromBool(bool value) +{ + return value ? "True" : "False"; +} + +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) +{ + if (full_path.empty()) + return false; + + size_t dir_end = full_path.find_last_of("/" + // windows needs the : included for something like just "C:" to be considered a directory +#ifdef _WIN32 + ":" +#endif + ); + if (std::string::npos == dir_end) + dir_end = 0; + else + dir_end += 1; + + size_t fname_end = full_path.rfind('.'); + if (fname_end < dir_end || std::string::npos == fname_end) + fname_end = full_path.size(); + + if (_pPath) + *_pPath = full_path.substr(0, dir_end); + + if (_pFilename) + *_pFilename = full_path.substr(dir_end, fname_end - dir_end); + + if (_pExtension) + *_pExtension = full_path.substr(fname_end); + + return true; +} + +void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) +{ + _CompleteFilename = _Path; + + // check for seperator + if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) + _CompleteFilename += DIR_SEP_CHR; + + // add the filename + _CompleteFilename += _Filename; +} + +void SplitString(const std::string& str, const char delim, std::vector& output) +{ + std::istringstream iss(str); + output.resize(1); + + while (std::getline(iss, *output.rbegin(), delim)) + output.push_back(""); + + output.pop_back(); +} + +std::string TabsToSpaces(int tab_size, const std::string &in) +{ + const std::string spaces(tab_size, ' '); + std::string out(in); + + size_t i = 0; + while (out.npos != (i = out.find('\t'))) + out.replace(i, 1, spaces); + + return out; +} + +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) +{ + while(1) + { + size_t pos = result.find(src); + if (pos == std::string::npos) break; + result.replace(pos, src.size(), dest); + } + 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 +//#include + +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 _WIN32 + +std::string UTF16ToUTF8(const std::wstring& input) +{ + auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); + + std::string output; + output.resize(size); + + if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) + output.clear(); + + return output; +} + +std::wstring CPToUTF16(u32 code_page, const std::string& input) +{ + auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); + + std::wstring output; + output.resize(size); + + if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size())) + output.clear(); + + return output; +} + +std::wstring UTF8ToUTF16(const std::string& input) +{ + return CPToUTF16(CP_UTF8, input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(932, input)); +} + +std::string CP1252ToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(1252, input)); +} + +#else + +template +std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) +{ + std::string result; + + iconv_t const conv_desc = iconv_open("UTF-8", fromcode); + if ((iconv_t)-1 == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + size_t const in_bytes = sizeof(T) * input.size(); + size_t const out_buffer_size = 4 * in_bytes; + + std::string out_buffer; + out_buffer.resize(out_buffer_size); + + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); + + while (src_bytes != 0) + { + size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, + &dst_buffer, &dst_bytes); + + if ((size_t)-1 == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) + { + // Try to skip the bad character + if (src_bytes != 0) + { + --src_bytes; + ++src_buffer; + } + } + else + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + break; + } + } + } + + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + iconv_close(conv_desc); + } + + return result; +} + +std::string CP1252ToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP1252//TRANSLIT", input); + //return CodeToUTF8("CP1252//IGNORE", input); + return CodeToUTF8("CP1252", input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP932", input); + return CodeToUTF8("SJIS", input); +} + +std::string UTF16ToUTF8(const std::wstring& input) +{ + std::string result = + // CodeToUTF8("UCS-2", input); + // CodeToUTF8("UCS-2LE", input); + // CodeToUTF8("UTF-16", input); + CodeToUTF8("UTF-16LE", input); + + // TODO: why is this needed? + result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); + return result; +} + +#endif diff --git a/src/common/string_util.h b/src/common/string_util.h new file mode 100644 index 00000000..fcbae471 --- /dev/null +++ b/src/common/string_util.h @@ -0,0 +1,111 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _STRINGUTIL_H_ +#define _STRINGUTIL_H_ + +#include + +#include +#include +#include +#include + +#include "common.h" + +std::string StringFromFormat(const char* format, ...); +// Cheap! +bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); + +template +inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) +{ + va_list args; + va_start(args, format); + CharArrayFromFormatV(out, Count, format, args); + va_end(args); +} + +// Good +std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); + +std::string StripSpaces(const std::string &s); +std::string StripQuotes(const std::string &s); + +// Thousand separator. Turns 12345678 into 12,345,678 +template +std::string ThousandSeparate(I value, int spaces = 0) +{ + std::ostringstream oss; + +// std::locale("") seems to be broken on many platforms +#if defined _WIN32 || (defined __linux__ && !defined __clang__) + oss.imbue(std::locale("")); +#endif + oss << std::setw(spaces) << value; + + return oss.str(); +} + +std::string StringFromInt(int value); +std::string StringFromBool(bool value); + +bool TryParse(const std::string &str, bool *output); +bool TryParse(const std::string &str, u32 *output); + +template +static bool TryParse(const std::string &str, N *const output) +{ + std::istringstream iss(str); + + N tmp = 0; + if (iss >> tmp) + { + *output = tmp; + return true; + } + else + return false; +} + +// TODO: kill this +bool AsciiToHex(const char* _szValue, u32& result); + +std::string TabsToSpaces(int tab_size, const std::string &in); + +void SplitString(const std::string& str, char delim, std::vector& output); + +// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); + +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 CP1252ToUTF8(const std::string& str); +std::string SHIFTJISToUTF8(const std::string& str); +std::string UTF16ToUTF8(const std::wstring& str); + +#ifdef _WIN32 + +std::wstring UTF8ToUTF16(const std::string& str); + +#ifdef _UNICODE +inline std::string TStrToUTF8(const std::wstring& str) +{ return UTF16ToUTF8(str); } + +inline std::wstring UTF8ToTStr(const std::string& str) +{ return UTF8ToUTF16(str); } +#else +inline std::string TStrToUTF8(const std::string& str) +{ return str; } + +inline std::string UTF8ToTStr(const std::string& str) +{ return str; } +#endif + +#endif + +#endif // _STRINGUTIL_H_ diff --git a/src/common/swap.h b/src/common/swap.h new file mode 100644 index 00000000..d07d9fcc --- /dev/null +++ b/src/common/swap.h @@ -0,0 +1,535 @@ +// Copyright (c) 2012- PPSSPP Project / 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +// Android +#if defined(ANDROID) +#include + +#if _BYTE_ORDER == _LITTLE_ENDIAN && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif _BYTE_ORDER == _BIG_ENDIAN && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// GCC 4.6+ +#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) + +#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// LLVM/clang +#elif __clang__ + +#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// MSVC +#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) + +#ifdef _XBOX +#define COMMON_BIG_ENDIAN 1 +#else +#define COMMON_LITTLE_ENDIAN 1 +#endif + +#endif + +// Worst case, default to little endian. +#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN +#define COMMON_LITTLE_ENDIAN 1 +#endif + +template +struct swap_struct_t { + typedef swap_struct_t swapped_t; + +protected: + T value; + + static T swap(T v) { + return F::swap(v); + } +public: + T const swap() const { + return swap(value); + + } + swap_struct_t() : value((T)0) {} + swap_struct_t(const T &v): value(swap(v)) {} + + template + swapped_t& operator=(const S &source) { + value = swap((T)source); + return *this; + } + + operator long() const { return (long)swap(); } + operator s8() const { return (s8)swap(); } + operator u8() const { return (u8)swap(); } + operator s16() const { return (s16)swap(); } + operator u16() const { return (u16)swap(); } + operator s32() const { return (s32)swap(); } + operator u32() const { return (u32)swap(); } + operator s64() const { return (s64)swap(); } + operator u64() const { return (u64)swap(); } + operator float() const { return (float)swap(); } + operator double() const { return (double)swap(); } + + // +v + swapped_t operator +() const { + return +swap(); + } + // -v + swapped_t operator -() const { + return -swap(); + } + + // v / 5 + swapped_t operator/(const swapped_t &i) const { + return swap() / i.swap(); + } + template + swapped_t operator/(const S &i) const { + return swap() / i; + } + + // v * 5 + swapped_t operator*(const swapped_t &i) const { + return swap() * i.swap(); + } + template + swapped_t operator*(const S &i) const { + return swap() * i; + } + + // v + 5 + swapped_t operator+(const swapped_t &i) const { + return swap() + i.swap(); + } + template + swapped_t operator+(const S &i) const { + return swap() + (T)i; + } + // v - 5 + swapped_t operator-(const swapped_t &i) const { + return swap() - i.swap(); + } + template + swapped_t operator-(const S &i) const { + return swap() - (T)i; + } + + // v += 5 + swapped_t& operator+=(const swapped_t &i) { + value = swap(swap() + i.swap()); + return *this; + } + template + swapped_t& operator+=(const S &i) { + value = swap(swap() + (T)i); + return *this; + } + // v -= 5 + swapped_t& operator-=(const swapped_t &i) { + value = swap(swap() - i.swap()); + return *this; + } + template + swapped_t& operator-=(const S &i) { + value = swap(swap() - (T)i); + return *this; + } + + // ++v + swapped_t& operator++() { + value = swap(swap()+1); + return *this; + } + // --v + swapped_t& operator--() { + value = swap(swap()-1); + return *this; + } + + // v++ + swapped_t operator++(int) { + swapped_t old = *this; + value = swap(swap()+1); + return old; + } + // v-- + swapped_t operator--(int) { + swapped_t old = *this; + value = swap(swap()-1); + return old; + } + // Comparaison + // v == i + bool operator==(const swapped_t &i) const { + return swap() == i.swap(); + } + template + bool operator==(const S &i) const { + return swap() == i; + } + + // v != i + bool operator!=(const swapped_t &i) const { + return swap() != i.swap(); + } + template + bool operator!=(const S &i) const { + return swap() != i; + } + + // v > i + bool operator>(const swapped_t &i) const { + return swap() > i.swap(); + } + template + bool operator>(const S &i) const { + return swap() > i; + } + + // v < i + bool operator<(const swapped_t &i) const { + return swap() < i.swap(); + } + template + bool operator<(const S &i) const { + return swap() < i; + } + + // v >= i + bool operator>=(const swapped_t &i) const { + return swap() >= i.swap(); + } + template + bool operator>=(const S &i) const { + return swap() >= i; + } + + // v <= i + bool operator<=(const swapped_t &i) const { + return swap() <= i.swap(); + } + template + bool operator<=(const S &i) const { + return swap() <= i; + } + + // logical + swapped_t operator !() const { + return !swap(); + } + + // bitmath + swapped_t operator ~() const { + return ~swap(); + } + + swapped_t operator &(const swapped_t &b) const { + return swap() & b.swap(); + } + template + swapped_t operator &(const S &b) const { + return swap() & b; + } + swapped_t& operator &=(const swapped_t &b) { + value = swap(swap() & b.swap()); + return *this; + } + template + swapped_t& operator &=(const S b) { + value = swap(swap() & b); + return *this; + } + + swapped_t operator |(const swapped_t &b) const { + return swap() | b.swap(); + } + template + swapped_t operator |(const S &b) const { + return swap() | b; + } + swapped_t& operator |=(const swapped_t &b) { + value = swap(swap() | b.swap()); + return *this; + } + template + swapped_t& operator |=(const S &b) { + value = swap(swap() | b); + return *this; + } + + swapped_t operator ^(const swapped_t &b) const { + return swap() ^ b.swap(); + } + template + swapped_t operator ^(const S &b) const { + return swap() ^ b; + } + swapped_t& operator ^=(const swapped_t &b) { + value = swap(swap() ^ b.swap()); + return *this; + } + template + swapped_t& operator ^=(const S &b) { + value = swap(swap() ^ b); + return *this; + } + + template + swapped_t operator <<(const S &b) const { + return swap() << b; + } + template + swapped_t& operator <<=(const S &b) const { + value = swap(swap() << b); + return *this; + } + + template + swapped_t operator >>(const S &b) const { + return swap() >> b; + } + template + swapped_t& operator >>=(const S &b) const { + value = swap(swap() >> b); + return *this; + } + + // Member + /** todo **/ + + + // Arithmetics + template + friend S operator+(const S &p, const swapped_t v); + + template + friend S operator-(const S &p, const swapped_t v); + + template + friend S operator/(const S &p, const swapped_t v); + + template + friend S operator*(const S &p, const swapped_t v); + + template + friend S operator%(const S &p, const swapped_t v); + + // Arithmetics + assignements + template + friend S operator+=(const S &p, const swapped_t v); + + template + friend S operator-=(const S &p, const swapped_t v); + + // Bitmath + template + friend S operator&(const S &p, const swapped_t v); + + // Comparison + template + friend bool operator<(const S &p, const swapped_t v); + + template + friend bool operator>(const S &p, const swapped_t v); + + template + friend bool operator<=(const S &p, const swapped_t v); + + template + friend bool operator>=(const S &p, const swapped_t v); + + template + friend bool operator!=(const S &p, const swapped_t v); + + template + friend bool operator==(const S &p, const swapped_t v); +}; + + +// Arithmetics +template +S operator+(const S &i, const swap_struct_t v) { + return i + v.swap(); +} + +template +S operator-(const S &i, const swap_struct_t v) { + return i - v.swap(); +} + +template +S operator/(const S &i, const swap_struct_t v) { + return i / v.swap(); +} + +template +S operator*(const S &i, const swap_struct_t v) { + return i * v.swap(); +} + +template +S operator%(const S &i, const swap_struct_t v) { + return i % v.swap(); +} + +// Arithmetics + assignements +template +S &operator+=(S &i, const swap_struct_t v) { + i += v.swap(); + return i; +} + +template +S &operator-=(S &i, const swap_struct_t v) { + i -= v.swap(); + return i; +} + +// Logical +template +S operator&(const S &i, const swap_struct_t v) { + return i & v.swap(); +} + +template +S operator&(const swap_struct_t v, const S &i) { + return (S)(v.swap() & i); +} + + +// Comparaison +template +bool operator<(const S &p, const swap_struct_t v) { + return p < v.swap(); +} +template +bool operator>(const S &p, const swap_struct_t v) { + return p > v.swap(); +} +template +bool operator<=(const S &p, const swap_struct_t v) { + return p <= v.swap(); +} +template +bool operator>=(const S &p, const swap_struct_t v) { + return p >= v.swap(); +} +template +bool operator!=(const S &p, const swap_struct_t v) { + return p != v.swap(); +} +template +bool operator==(const S &p, const swap_struct_t v) { + return p == v.swap(); +} + +template +struct swap_64_t { + static T swap(T x) { + return (T)bswap64(*(u64 *)&x); + } +}; + +template +struct swap_32_t { + static T swap(T x) { + return (T)bswap32(*(u32 *)&x); + } +}; + +template +struct swap_16_t { + static T swap(T x) { + return (T)bswap16(*(u16 *)&x); + } +}; + +template +struct swap_float_t { + static T swap(T x) { + return (T)bswapf(*(float *)&x); + } +}; + +template +struct swap_double_t { + static T swap(T x) { + return (T)bswapd(*(double *)&x); + } +}; + +#if COMMON_LITTLE_ENDIAN +typedef u32 u32_le; +typedef u16 u16_le; +typedef u64 u64_le; + +typedef s32 s32_le; +typedef s16 s16_le; +typedef s64 s64_le; + +typedef float float_le; +typedef double double_le; + +typedef swap_struct_t> u64_be; +typedef swap_struct_t> s64_be; + +typedef swap_struct_t> u32_be; +typedef swap_struct_t> s32_be; + +typedef swap_struct_t> u16_be; +typedef swap_struct_t> s16_be; + +typedef swap_struct_t > float_be; +typedef swap_struct_t > double_be; +#else + +typedef swap_struct_t> u64_le; +typedef swap_struct_t> s64_le; + +typedef swap_struct_t> u32_le; +typedef swap_struct_t> s32_le; + +typedef swap_struct_t> u16_le; +typedef swap_struct_t> s16_le; + +typedef swap_struct_t > float_le; +typedef swap_struct_t > double_le; + +typedef u32 u32_be; +typedef u16 u16_be; +typedef u64 u64_be; + +typedef s32 s32_be; +typedef s16 s16_be; +typedef s64 s64_be; + +typedef float float_be; +typedef double double_be; +#endif \ No newline at end of file diff --git a/src/common/thread.cpp b/src/common/thread.cpp new file mode 100644 index 00000000..27dbf3f9 --- /dev/null +++ b/src/common/thread.cpp @@ -0,0 +1,133 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "thread.h" +#include "common.h" + +#ifdef __APPLE__ +#include +#elif defined BSD4_4 +#include +#endif + +#ifdef USE_BEGINTHREADEX +#include +#endif + +namespace Common +{ + +int CurrentThreadId() +{ +#ifdef _WIN32 + return GetCurrentThreadId(); +#elif defined __APPLE__ + return mach_thread_self(); +#else + return 0; +#endif +} + +#ifdef _WIN32 + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +{ + SetThreadAffinityMask(thread, mask); +} + +void SetCurrentThreadAffinity(u32 mask) +{ + SetThreadAffinityMask(GetCurrentThread(), mask); +} + +// Supporting functions +void SleepCurrentThread(int ms) +{ + Sleep(ms); +} + +void SwitchCurrentThread() +{ + SwitchToThread(); +} + +// Sets the debugger-visible name of the current thread. +// Uses undocumented (actually, it is now documented) trick. +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp + +// This is implemented much nicer in upcoming msvc++, see: +// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx +void SetCurrentThreadName(const char* szThreadName) +{ + static const DWORD MS_VC_EXCEPTION = 0x406D1388; + + #pragma pack(push,8) + struct THREADNAME_INFO + { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero + } info; + #pragma pack(pop) + + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = -1; //dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_CONTINUE_EXECUTION) + {} +} + +#else // !WIN32, so must be POSIX threads + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +{ +#ifdef __APPLE__ + thread_policy_set(pthread_mach_thread_np(thread), + THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); +#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + + for (int i = 0; i != sizeof(mask) * 8; ++i) + if ((mask >> i) & 1) + CPU_SET(i, &cpu_set); + + pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); +#endif +} + +void SetCurrentThreadAffinity(u32 mask) +{ + SetThreadAffinity(pthread_self(), mask); +} + +void SleepCurrentThread(int ms) +{ + usleep(1000 * ms); +} + +void SwitchCurrentThread() +{ + usleep(1000 * 1); +} + +void SetCurrentThreadName(const char* szThreadName) +{ +#ifdef __APPLE__ + pthread_setname_np(szThreadName); +#else + pthread_setname_np(pthread_self(), szThreadName); +#endif +} + +#endif + +} // namespace Common diff --git a/src/common/thread.h b/src/common/thread.h new file mode 100644 index 00000000..6384a44a --- /dev/null +++ b/src/common/thread.h @@ -0,0 +1,156 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _THREAD_H_ +#define _THREAD_H_ + +#include "std_condition_variable.h" +#include "std_mutex.h" +#include "std_thread.h" + +// Don't include common.h here as it will break LogManager +#include "common_types.h" +#include +#include + +// This may not be defined outside _WIN32 +#ifndef _WIN32 +#ifndef INFINITE +#define INFINITE 0xffffffff +#endif + +//for gettimeofday and struct time(spec|val) +#include +#include +#endif + +namespace Common +{ + +int CurrentThreadId(); + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); +void SetCurrentThreadAffinity(u32 mask); + +class Event +{ +public: + Event() + : is_set(false) + {}; + + void Set() + { + std::lock_guard lk(m_mutex); + if (!is_set) + { + is_set = true; + m_condvar.notify_one(); + } + } + + void Wait() + { + std::unique_lock lk(m_mutex); + m_condvar.wait(lk, IsSet(this)); + is_set = false; + } + + void Reset() + { + std::unique_lock 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; + std::condition_variable m_condvar; + std::mutex m_mutex; +}; + +// TODO: doesn't work on windows with (count > 2) +class Barrier +{ +public: + Barrier(size_t count) + : m_count(count), m_waiting(0) + {} + + // block until "count" threads call Sync() + bool Sync() + { + std::unique_lock 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) + { + m_waiting = 0; + m_condvar.notify_all(); + return true; + } + else + { + m_condvar.wait(lk, IsDoneWating(this)); + return false; + } + } + +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; +}; + +void SleepCurrentThread(int ms); +void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms + +// Use this function during a spin-wait to make the current thread +// relax while another thread is working. This may be more efficient +// than using events because event functions use kernel calls. +inline void YieldCPU() +{ + std::this_thread::yield(); +} + +void SetCurrentThreadName(const char *name); + +} // namespace Common + +#endif // _THREAD_H_ diff --git a/src/common/thunk.h b/src/common/thunk.h new file mode 100644 index 00000000..c9e6fd39 --- /dev/null +++ b/src/common/thunk.h @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _THUNK_H_ +#define _THUNK_H_ + +#include + +#include "common.h" +#include "x64Emitter.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 +// call functions from generated code, without inflicting the performance hit and increase +// of complexity that it means to protect the generated code from this problem. + +// This process is called thunking. + +// There will only ever be one level of thunking on the stack, plus, +// we don't want to pollute the stack, so we store away regs somewhere global. +// NOT THREAD SAFE. This may only be used from the CPU thread. +// Any other thread using this stuff will be FATAL. + +class ThunkManager : public Gen::XCodeBlock +{ + std::map thunks; + + const u8 *save_regs; + const u8 *load_regs; + +public: + ThunkManager() { + Init(); + } + ~ThunkManager() { + Shutdown(); + } + void *ProtectFunction(void *function, int num_params); +private: + void Init(); + void Shutdown(); + void Reset(); +}; + +#endif // _THUNK_H_ diff --git a/src/common/timer.cpp b/src/common/timer.cpp new file mode 100644 index 00000000..90604292 --- /dev/null +++ b/src/common/timer.cpp @@ -0,0 +1,226 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +#include "common.h" +#include "timer.h" +#include "string_util.h" + +namespace Common +{ + +u32 Timer::GetTimeMs() +{ +#ifdef _WIN32 + return timeGetTime(); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); + return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); +#endif +} + +// -------------------------------------------- +// Initiate, Start, Stop, and Update the time +// -------------------------------------------- + +// Set initial values for the class +Timer::Timer() + : m_LastTime(0), m_StartTime(0), m_Running(false) +{ + Update(); +} + +// Write the starting time +void Timer::Start() +{ + m_StartTime = GetTimeMs(); + m_Running = true; +} + +// Stop the timer +void Timer::Stop() +{ + // Write the final time + m_LastTime = GetTimeMs(); + m_Running = false; +} + +// Update the last time variable +void Timer::Update() +{ + m_LastTime = GetTimeMs(); + //TODO(ector) - QPF +} + +// ------------------------------------- +// Get time difference and elapsed time +// ------------------------------------- + +// Get the number of milliseconds since the last Update() +u64 Timer::GetTimeDifference() +{ + return GetTimeMs() - m_LastTime; +} + +// Add the time difference since the last Update() to the starting time. +// This is used to compensate for a paused game. +void Timer::AddTimeDifference() +{ + m_StartTime += GetTimeDifference(); +} + +// Get the time elapsed since the Start() +u64 Timer::GetTimeElapsed() +{ + // If we have not started yet, return 1 (because then I don't + // have to change the FPS calculation in CoreRerecording.cpp . + if (m_StartTime == 0) return 1; + + // Return the final timer time if the timer is stopped + if (!m_Running) return (m_LastTime - m_StartTime); + + return (GetTimeMs() - m_StartTime); +} + +// Get the formatted time elapsed since the Start() +std::string Timer::GetTimeElapsedFormatted() const +{ + // If we have not started yet, return zero + if (m_StartTime == 0) + return "00:00:00:000"; + + // The number of milliseconds since the start. + // Use a different value if the timer is stopped. + u64 Milliseconds; + if (m_Running) + Milliseconds = GetTimeMs() - m_StartTime; + else + Milliseconds = m_LastTime - m_StartTime; + // Seconds + u32 Seconds = (u32)(Milliseconds / 1000); + // Minutes + u32 Minutes = Seconds / 60; + // Hours + u32 Hours = Minutes / 60; + + std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", + Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); + return TmpStr; +} + +// Get current time +void Timer::IncreaseResolution() +{ +#ifdef _WIN32 + timeBeginPeriod(1); +#endif +} + +void Timer::RestoreResolution() +{ +#ifdef _WIN32 + timeEndPeriod(1); +#endif +} + +// Get the number of seconds since January 1 1970 +u64 Timer::GetTimeSinceJan1970() +{ + time_t ltime; + time(<ime); + return((u64)ltime); +} + +u64 Timer::GetLocalTimeSinceJan1970() +{ + time_t sysTime, tzDiff, tzDST; + struct tm * gmTime; + + time(&sysTime); + + // Account for DST where needed + gmTime = localtime(&sysTime); + if(gmTime->tm_isdst == 1) + tzDST = 3600; + else + tzDST = 0; + + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + tzDiff = sysTime - mktime(gmTime); + + return (u64)(sysTime + tzDiff + tzDST); +} + +// Return the current time formatted as Minutes:Seconds:Milliseconds +// in the form 00:00:000. +std::string Timer::GetTimeFormatted() +{ + time_t sysTime; + struct tm * gmTime; + char formattedTime[13]; + char tmp[13]; + + time(&sysTime); + gmTime = localtime(&sysTime); + + strftime(tmp, 6, "%M:%S", gmTime); + + // Now tack on the milliseconds +#ifdef _WIN32 + struct timeb tp; + (void)::ftime(&tp); + sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); + sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); +#endif + + return std::string(formattedTime); +} + +// Returns a timestamp with decimals for precise time comparisons +// ---------------- +double Timer::GetDoubleTime() +{ +#ifdef _WIN32 + struct timeb tp; + (void)::ftime(&tp); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); +#endif + // Get continuous timestamp + u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); + + // Remove a few years. We only really want enough seconds to make + // sure that we are detecting actual actions, perhaps 60 seconds is + // enough really, but I leave a year of seconds anyway, in case the + // user's clock is incorrect or something like that. + TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); + + // Make a smaller integer that fits in the double + u32 Seconds = (u32)TmpSeconds; +#ifdef _WIN32 + double ms = tp.millitm / 1000.0 / 1000.0; +#else + double ms = t.tv_usec / 1000000.0; +#endif + double TmpTime = Seconds + ms; + + return TmpTime; +} + +} // Namespace Common diff --git a/src/common/timer.h b/src/common/timer.h new file mode 100644 index 00000000..20c86762 --- /dev/null +++ b/src/common/timer.h @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "common.h" +#include + +namespace Common +{ +class Timer +{ +public: + Timer(); + + void Start(); + void Stop(); + void Update(); + + // The time difference is always returned in milliseconds, regardless of alternative internal representation + u64 GetTimeDifference(); + void AddTimeDifference(); + + static void IncreaseResolution(); + static void RestoreResolution(); + static u64 GetTimeSinceJan1970(); + static u64 GetLocalTimeSinceJan1970(); + static double GetDoubleTime(); + + static std::string GetTimeFormatted(); + std::string GetTimeElapsedFormatted() const; + u64 GetTimeElapsed(); + + static u32 GetTimeMs(); + +private: + u64 m_LastTime; + u64 m_StartTime; + bool m_Running; +}; + +} // Namespace Common + +#endif // _TIMER_H_ diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp new file mode 100644 index 00000000..9aa8088e --- /dev/null +++ b/src/common/utf8.cpp @@ -0,0 +1,463 @@ +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ + +#ifdef _WIN32 +#include +#undef min +#undef max +#endif + +#include +#include +#include +#include + +#include +#include + +#include "common_types.h" +#include "utf8.h" + +// is start of UTF sequence +inline bool isutf(char c) { + return (c & 0xC0) != 0x80; +} + +static const u32 offsetsFromUTF8[6] = { + 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL +}; + +static const u8 trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5, +}; + +/* returns length of next utf-8 sequence */ +int u8_seqlen(const char *s) +{ + return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1; +} + +/* conversions without error checking + only works for valid UTF-8, i.e. no 5- or 6-byte sequences + srcsz = source size in bytes, or -1 if 0-terminated + sz = dest size in # of wide characters + + returns # characters converted + dest will always be L'\0'-terminated, even if there isn't enough room + for all the characters. + if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. +*/ +int u8_toucs(u32 *dest, int sz, const char *src, int srcsz) +{ + u32 ch; + const char *src_end = src + srcsz; + int nb; + int i=0; + + while (i < sz-1) { + nb = trailingBytesForUTF8[(unsigned char)*src]; + if (srcsz == -1) { + if (*src == 0) + goto done_toucs; + } + else { + if (src + nb >= src_end) + goto done_toucs; + } + ch = 0; + switch (nb) { + /* these fall through deliberately */ + case 3: ch += (unsigned char)*src++; ch <<= 6; + case 2: ch += (unsigned char)*src++; ch <<= 6; + case 1: ch += (unsigned char)*src++; ch <<= 6; + case 0: ch += (unsigned char)*src++; + } + ch -= offsetsFromUTF8[nb]; + dest[i++] = ch; + } + done_toucs: + dest[i] = 0; + return i; +} + +/* srcsz = number of source characters, or -1 if 0-terminated + sz = size of dest buffer in bytes + + returns # characters converted + dest will only be '\0'-terminated if there is enough space. this is + for consistency; imagine there are 2 bytes of space left, but the next + character requires 3 bytes. in this case we could NUL-terminate, but in + general we can't when there's insufficient space. therefore this function + only NUL-terminates if all the characters fit, and there's space for + the NUL as well. + the destination string will never be bigger than the source string. +*/ +int u8_toutf8(char *dest, int sz, u32 *src, int srcsz) +{ + u32 ch; + int i = 0; + char *dest_end = dest + sz; + + while (srcsz<0 ? src[i]!=0 : i < srcsz) { + ch = src[i]; + if (ch < 0x80) { + if (dest >= dest_end) + return i; + *dest++ = (char)ch; + } + else if (ch < 0x800) { + if (dest >= dest_end-1) + return i; + *dest++ = (ch>>6) | 0xC0; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x10000) { + if (dest >= dest_end-2) + return i; + *dest++ = (ch>>12) | 0xE0; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x110000) { + if (dest >= dest_end-3) + return i; + *dest++ = (ch>>18) | 0xF0; + *dest++ = ((ch>>12) & 0x3F) | 0x80; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + i++; + } + if (dest < dest_end) + *dest = '\0'; + return i; +} + +int u8_wc_toutf8(char *dest, u32 ch) +{ + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = (ch>>6) | 0xC0; + dest[1] = (ch & 0x3F) | 0x80; + return 2; + } + if (ch < 0x10000) { + dest[0] = (ch>>12) | 0xE0; + dest[1] = ((ch>>6) & 0x3F) | 0x80; + dest[2] = (ch & 0x3F) | 0x80; + return 3; + } + if (ch < 0x110000) { + dest[0] = (ch>>18) | 0xF0; + dest[1] = ((ch>>12) & 0x3F) | 0x80; + dest[2] = ((ch>>6) & 0x3F) | 0x80; + dest[3] = (ch & 0x3F) | 0x80; + return 4; + } + return 0; +} + +/* charnum => byte offset */ +int u8_offset(const char *str, int charnum) +{ + int offs=0; + + while (charnum > 0 && str[offs]) { + (void)(isutf(str[++offs]) || isutf(str[++offs]) || + isutf(str[++offs]) || ++offs); + charnum--; + } + return offs; +} + +/* byte offset => charnum */ +int u8_charnum(const char *s, int offset) +{ + int charnum = 0, offs=0; + + while (offs < offset && s[offs]) { + (void)(isutf(s[++offs]) || isutf(s[++offs]) || + isutf(s[++offs]) || ++offs); + charnum++; + } + return charnum; +} + +/* number of characters */ +int u8_strlen(const char *s) +{ + int count = 0; + int i = 0; + + while (u8_nextchar(s, &i) != 0) + count++; + + return count; +} + +/* reads the next utf-8 sequence out of a string, updating an index */ +u32 u8_nextchar(const char *s, int *i) +{ + u32 ch = 0; + int sz = 0; + + do { + ch <<= 6; + ch += (unsigned char)s[(*i)++]; + sz++; + } while (s[*i] && !isutf(s[*i])); + ch -= offsetsFromUTF8[sz-1]; + + return ch; +} + +void u8_inc(const char *s, int *i) +{ + (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || + isutf(s[++(*i)]) || ++(*i)); +} + +void u8_dec(const char *s, int *i) +{ + (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || + isutf(s[--(*i)]) || --(*i)); +} + +int octal_digit(char c) +{ + return (c >= '0' && c <= '7'); +} + +int hex_digit(char c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')); +} + +/* assumes that src points to the character after a backslash + returns number of input characters processed */ +int u8_read_escape_sequence(const char *str, u32 *dest) +{ + u32 ch; + char digs[9]="\0\0\0\0\0\0\0\0"; + int dno=0, i=1; + + ch = (u32)str[0]; /* take literal character */ + if (str[0] == 'n') + ch = L'\n'; + else if (str[0] == 't') + ch = L'\t'; + else if (str[0] == 'r') + ch = L'\r'; + else if (str[0] == 'b') + ch = L'\b'; + else if (str[0] == 'f') + ch = L'\f'; + else if (str[0] == 'v') + ch = L'\v'; + else if (str[0] == 'a') + ch = L'\a'; + else if (octal_digit(str[0])) { + i = 0; + do { + digs[dno++] = str[i++]; + } while (octal_digit(str[i]) && dno < 3); + ch = strtol(digs, NULL, 8); + } + else if (str[0] == 'x') { + while (hex_digit(str[i]) && dno < 2) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'u') { + while (hex_digit(str[i]) && dno < 4) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'U') { + while (hex_digit(str[i]) && dno < 8) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + *dest = ch; + + return i; +} + +/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 + example: u8_unescape(mybuf, 256, "hello\\u220e") + note the double backslash is needed if called on a C string literal */ +int u8_unescape(char *buf, int sz, char *src) +{ + int c=0, amt; + u32 ch; + char temp[4]; + + while (*src && c < sz) { + if (*src == '\\') { + src++; + amt = u8_read_escape_sequence(src, &ch); + } + else { + ch = (u32)*src; + amt = 1; + } + src += amt; + amt = u8_wc_toutf8(temp, ch); + if (amt > sz-c) + break; + memcpy(&buf[c], temp, amt); + c += amt; + } + if (c < sz) + buf[c] = '\0'; + return c; +} + +const char *u8_strchr(const char *s, u32 ch, int *charn) +{ + int i = 0, lasti=0; + u32 c; + + *charn = 0; + while (s[i]) { + c = u8_nextchar(s, &i); + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn) +{ + u32 i = 0, lasti=0; + u32 c; + int csz; + + *charn = 0; + while (i < sz) { + c = csz = 0; + do { + c <<= 6; + c += (unsigned char)s[i++]; + csz++; + } while (i < sz && !isutf(s[i])); + c -= offsetsFromUTF8[csz-1]; + + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +int u8_is_locale_utf8(const char *locale) +{ + /* this code based on libutf8 */ + const char* cp = locale; + + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { + if (*cp == '.') { + const char* encoding = ++cp; + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) + ; + if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) + || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) + return 1; /* it's UTF-8 */ + break; + } + } + return 0; +} + +int UTF8StringNonASCIICount(const char *utf8string) { + UTF8 utf(utf8string); + int count = 0; + while (!utf.end()) { + int c = utf.next(); + if (c > 127) + ++count; + } + return count; +} + +bool UTF8StringHasNonASCII(const char *utf8string) { + return UTF8StringNonASCIICount(utf8string) > 0; +} + +#ifdef _WIN32 + +std::string ConvertWStringToUTF8(const wchar_t *wstr) { + int len = (int)wcslen(wstr); + int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL); + std::string s; + s.resize(size); + if (size > 0) { + WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL); + } + return s; +} + +std::string ConvertWStringToUTF8(const std::wstring &wstr) { + int len = (int)wstr.size(); + int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL); + std::string s; + s.resize(size); + if (size > 0) { + WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL); + } + return s; +} + +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) { + int len = (int)source.size(); + int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); + MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); +} + +std::wstring ConvertUTF8ToWString(const std::string &source) { + int len = (int)source.size(); + int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); + std::wstring str; + str.resize(size); + if (size > 0) { + MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, &str[0], size); + } + return str; +} + +#endif \ No newline at end of file diff --git a/src/common/utf8.h b/src/common/utf8.h new file mode 100644 index 00000000..36cf7571 --- /dev/null +++ b/src/common/utf8.h @@ -0,0 +1,67 @@ +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ + +// Further modified, and C++ stuff added, by hrydgard@gmail.com. + +#pragma once + +#include "common_types.h" +#include + +u32 u8_nextchar(const char *s, int *i); +int u8_wc_toutf8(char *dest, u32 ch); +int u8_strlen(const char *s); + +class UTF8 { +public: + static const u32 INVALID = (u32)-1; + UTF8(const char *c) : c_(c), index_(0) {} + bool end() const { return c_[index_] == 0; } + u32 next() { + return u8_nextchar(c_, &index_); + } + u32 peek() { + int tempIndex = index_; + return u8_nextchar(c_, &tempIndex); + } + int length() const { + return u8_strlen(c_); + } + int byteIndex() const { + return index_; + } + static int encode(char *dest, u32 ch) { + return u8_wc_toutf8(dest, ch); + } + +private: + const char *c_; + int index_; +}; + +int UTF8StringNonASCIICount(const char *utf8string); + +bool UTF8StringHasNonASCII(const char *utf8string); + + +// UTF8 to Win32 UTF-16 +// Should be used when calling Win32 api calls +#ifdef _WIN32 + +std::string ConvertWStringToUTF8(const std::wstring &wstr); +std::string ConvertWStringToUTF8(const wchar_t *wstr); +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source); +std::wstring ConvertUTF8ToWString(const std::string &source); + +#endif \ No newline at end of file diff --git a/src/common/version.cpp b/src/common/version.cpp new file mode 100644 index 00000000..01890dbb --- /dev/null +++ b/src/common/version.cpp @@ -0,0 +1,45 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "scm_rev.h" + +#ifdef _DEBUG + #define BUILD_TYPE_STR "Debug " +#elif defined DEBUGFAST + #define BUILD_TYPE_STR "DebugFast " +#else + #define BUILD_TYPE_STR "" +#endif + +const char *scm_rev_str = "emu " +#if !SCM_IS_MASTER + "[" SCM_BRANCH_STR "] " +#endif + +#ifdef __INTEL_COMPILER + BUILD_TYPE_STR SCM_DESC_STR "-ICC"; +#else + BUILD_TYPE_STR SCM_DESC_STR; +#endif + +#ifdef _M_X64 +#define NP_ARCH "x64" +#else +#ifdef _M_ARM +#define NP_ARCH "ARM" +#else +#define NP_ARCH "x86" +#endif +#endif + +#ifdef _WIN32 +const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH; +#elif __APPLE__ +const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH; +#else +const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH; +#endif + +const char *scm_rev_git_str = SCM_REV_STR; diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h new file mode 100644 index 00000000..eee2f624 --- /dev/null +++ b/src/core/arm/arm_interface.h @@ -0,0 +1,68 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" +#include "common_types.h" + +/// Generic ARM11 CPU interface +class ARM_Interface { +public: + ARM_Interface() { + num_instructions_ = 0; + } + + ~ARM_Interface() { + } + + /// Step CPU by one instruction + void Step() { + ExecuteInstruction(); + num_instructions_++; + } + + /** + * Set the Program Counter to an address + * @param addr Address to set PC to + */ + virtual void SetPC(u32 addr) = 0; + + /* + * Get the current Program Counter + * @return Returns current PC + */ + virtual u32 PC() = 0; + + /** + * Get an ARM register + * @param index Register index (0-15) + * @return Returns the value in the register + */ + virtual u32 Reg(int index) = 0; + + /** + * Get the current CPSR register + * @return Returns the value of the CPSR register + */ + virtual u32 CPSR() = 0; + + /** + * Returns the number of clock ticks since the last rese + * @return Returns number of clock ticks + */ + virtual u64 GetTicks() = 0; + + /// Getter for num_instructions_ + u64 num_instructions() { return num_instructions_; } + +private: + + /// Execture next instruction + virtual void ExecuteInstruction() = 0; + + u64 num_instructions_; ///< Number of instructions executed + + DISALLOW_COPY_AND_ASSIGN(ARM_Interface); +}; diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp new file mode 100644 index 00000000..82ca5ee8 --- /dev/null +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -0,0 +1,1003 @@ +// Copyright 2006 The Android Open Source Project + +#include +#include +#include "arm_disasm.h" + +static const char *cond_names[] = { + "eq", + "ne", + "cs", + "cc", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + "", + "RESERVED" +}; + +const char *opcode_names[] = { + "invalid", + "undefined", + "adc", + "add", + "and", + "b", + "bl", + "bic", + "bkpt", + "blx", + "bx", + "cdp", + "clz", + "cmn", + "cmp", + "eor", + "ldc", + "ldm", + "ldr", + "ldrb", + "ldrbt", + "ldrh", + "ldrsb", + "ldrsh", + "ldrt", + "mcr", + "mla", + "mov", + "mrc", + "mrs", + "msr", + "mul", + "mvn", + "orr", + "pld", + "rsb", + "rsc", + "sbc", + "smlal", + "smull", + "stc", + "stm", + "str", + "strb", + "strbt", + "strh", + "strt", + "sub", + "swi", + "swp", + "swpb", + "teq", + "tst", + "umlal", + "umull", + + "undefined", + "adc", + "add", + "and", + "asr", + "b", + "bic", + "bkpt", + "bl", + "blx", + "bx", + "cmn", + "cmp", + "eor", + "ldmia", + "ldr", + "ldrb", + "ldrh", + "ldrsb", + "ldrsh", + "lsl", + "lsr", + "mov", + "mul", + "mvn", + "neg", + "orr", + "pop", + "push", + "ror", + "sbc", + "stmia", + "str", + "strb", + "strh", + "sub", + "swi", + "tst", + + NULL +}; + +// Indexed by the shift type (bits 6-5) +static const char *shift_names[] = { + "LSL", + "LSR", + "ASR", + "ROR" +}; + +static const char* cond_to_str(int cond) { + return cond_names[cond]; +} + +char *ARM_Disasm::disasm(uint32_t addr, uint32_t insn, char *result) +{ + static char buf[80]; + char *ptr; + + ptr = result ? result : buf; + Opcode opcode = decode(insn); + switch (opcode) { + case OP_INVALID: + sprintf(ptr, "Invalid"); + return ptr; + case OP_UNDEFINED: + sprintf(ptr, "Undefined"); + return ptr; + case OP_ADC: + case OP_ADD: + case OP_AND: + case OP_BIC: + case OP_CMN: + case OP_CMP: + case OP_EOR: + case OP_MOV: + case OP_MVN: + case OP_ORR: + case OP_RSB: + case OP_RSC: + case OP_SBC: + case OP_SUB: + case OP_TEQ: + case OP_TST: + return disasm_alu(opcode, insn, ptr); + case OP_B: + case OP_BL: + return disasm_branch(addr, opcode, insn, ptr); + case OP_BKPT: + return disasm_bkpt(insn, ptr); + case OP_BLX: + // not supported yet + break; + case OP_BX: + return disasm_bx(insn, ptr); + case OP_CDP: + sprintf(ptr, "cdp"); + return ptr; + case OP_CLZ: + return disasm_clz(insn, ptr); + case OP_LDC: + sprintf(ptr, "ldc"); + return ptr; + case OP_LDM: + case OP_STM: + return disasm_memblock(opcode, insn, ptr); + case OP_LDR: + case OP_LDRB: + case OP_LDRBT: + case OP_LDRT: + case OP_STR: + case OP_STRB: + case OP_STRBT: + case OP_STRT: + return disasm_mem(insn, ptr); + case OP_LDRH: + case OP_LDRSB: + case OP_LDRSH: + case OP_STRH: + return disasm_memhalf(insn, ptr); + case OP_MCR: + case OP_MRC: + return disasm_mcr(opcode, insn, ptr); + case OP_MLA: + return disasm_mla(opcode, insn, ptr); + case OP_MRS: + return disasm_mrs(insn, ptr); + case OP_MSR: + return disasm_msr(insn, ptr); + case OP_MUL: + return disasm_mul(opcode, insn, ptr); + case OP_PLD: + return disasm_pld(insn, ptr); + case OP_STC: + sprintf(ptr, "stc"); + return ptr; + case OP_SWI: + return disasm_swi(insn, ptr); + case OP_SWP: + case OP_SWPB: + return disasm_swp(opcode, insn, ptr); + case OP_UMLAL: + case OP_UMULL: + case OP_SMLAL: + case OP_SMULL: + return disasm_umlal(opcode, insn, ptr); + default: + sprintf(ptr, "Error"); + return ptr; + } + return NULL; +} + +char *ARM_Disasm::disasm_alu(Opcode opcode, uint32_t insn, char *ptr) +{ + static const uint8_t kNoOperand1 = 1; + static const uint8_t kNoDest = 2; + static const uint8_t kNoSbit = 4; + + char rn_str[20]; + char rd_str[20]; + uint8_t flags = 0; + uint8_t cond = (insn >> 28) & 0xf; + uint8_t is_immed = (insn >> 25) & 0x1; + uint8_t bit_s = (insn >> 20) & 1; + uint8_t rn = (insn >> 16) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint8_t immed = insn & 0xff; + + const char *opname = opcode_names[opcode]; + switch (opcode) { + case OP_CMN: + case OP_CMP: + case OP_TEQ: + case OP_TST: + flags = kNoDest | kNoSbit; + break; + case OP_MOV: + case OP_MVN: + flags = kNoOperand1; + break; + default: + break; + } + + // The "mov" instruction ignores the first operand (rn). + rn_str[0] = 0; + if ((flags & kNoOperand1) == 0) { + sprintf(rn_str, "r%d, ", rn); + } + + // The following instructions do not write the result register (rd): + // tst, teq, cmp, cmn. + rd_str[0] = 0; + if ((flags & kNoDest) == 0) { + sprintf(rd_str, "r%d, ", rd); + } + + const char *sbit_str = ""; + if (bit_s && !(flags & kNoSbit)) + sbit_str = "s"; + + if (is_immed) { + sprintf(ptr, "%s%s%s\t%s%s#%u ; 0x%x", + opname, cond_to_str(cond), sbit_str, rd_str, rn_str, immed, immed); + return ptr; + } + + uint8_t shift_is_reg = (insn >> 4) & 1; + uint8_t rotate = (insn >> 8) & 0xf; + uint8_t rm = insn & 0xf; + uint8_t shift_type = (insn >> 5) & 0x3; + uint8_t rs = (insn >> 8) & 0xf; + uint8_t shift_amount = (insn >> 7) & 0x1f; + uint32_t rotated_val = immed; + uint8_t rotate2 = rotate << 1; + rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); + + if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { + sprintf(ptr, "%s%s%s\t%s%sr%d", + opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); + return ptr; + } + + const char *shift_name = shift_names[shift_type]; + if (shift_is_reg) { + sprintf(ptr, "%s%s%s\t%s%sr%d, %s r%d", + opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, + shift_name, rs); + return ptr; + } + if (shift_amount == 0) { + if (shift_type == 3) { + sprintf(ptr, "%s%s%s\t%s%sr%d, RRX", + opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); + return ptr; + } + shift_amount = 32; + } + sprintf(ptr, "%s%s%s\t%s%sr%d, %s #%u", + opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, + shift_name, shift_amount); + return ptr; +} + +char *ARM_Disasm::disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint32_t offset = insn & 0xffffff; + // Sign-extend the 24-bit offset + if ((offset >> 23) & 1) + offset |= 0xff000000; + + // Pre-compute the left-shift and the prefetch offset + offset <<= 2; + offset += 8; + addr += offset; + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s\t0x%x", opname, cond_to_str(cond), addr); + return ptr; +} + +char *ARM_Disasm::disasm_bx(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rn = insn & 0xf; + sprintf(ptr, "bx%s\tr%d", cond_to_str(cond), rn); + return ptr; +} + +char *ARM_Disasm::disasm_bkpt(uint32_t insn, char *ptr) +{ + uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); + sprintf(ptr, "bkpt\t#%d", immed); + return ptr; +} + +char *ARM_Disasm::disasm_clz(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint8_t rm = insn & 0xf; + sprintf(ptr, "clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); + return ptr; +} + +char *ARM_Disasm::disasm_memblock(Opcode opcode, uint32_t insn, char *ptr) +{ + char tmp_reg[10], tmp_list[80]; + + uint8_t cond = (insn >> 28) & 0xf; + uint8_t write_back = (insn >> 21) & 0x1; + uint8_t bit_s = (insn >> 22) & 0x1; + uint8_t is_up = (insn >> 23) & 0x1; + uint8_t is_pre = (insn >> 24) & 0x1; + uint8_t rn = (insn >> 16) & 0xf; + uint16_t reg_list = insn & 0xffff; + + const char *opname = opcode_names[opcode]; + + const char *bang = ""; + if (write_back) + bang = "!"; + + const char *carret = ""; + if (bit_s) + carret = "^"; + + const char *comma = ""; + tmp_list[0] = 0; + for (int ii = 0; ii < 16; ++ii) { + if (reg_list & (1 << ii)) { + sprintf(tmp_reg, "%sr%d", comma, ii); + strcat(tmp_list, tmp_reg); + comma = ","; + } + } + + const char *addr_mode = ""; + if (is_pre) { + if (is_up) { + addr_mode = "ib"; + } else { + addr_mode = "db"; + } + } else { + if (is_up) { + addr_mode = "ia"; + } else { + addr_mode = "da"; + } + } + + sprintf(ptr, "%s%s%s\tr%d%s, {%s}%s", + opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list, carret); + return ptr; +} + +char *ARM_Disasm::disasm_mem(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t is_reg = (insn >> 25) & 0x1; + uint8_t is_load = (insn >> 20) & 0x1; + uint8_t write_back = (insn >> 21) & 0x1; + uint8_t is_byte = (insn >> 22) & 0x1; + uint8_t is_up = (insn >> 23) & 0x1; + uint8_t is_pre = (insn >> 24) & 0x1; + uint8_t rn = (insn >> 16) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint16_t offset = insn & 0xfff; + + const char *opname = "ldr"; + if (!is_load) + opname = "str"; + + const char *bang = ""; + if (write_back) + bang = "!"; + + const char *minus = ""; + if (is_up == 0) + minus = "-"; + + const char *byte = ""; + if (is_byte) + byte = "b"; + + if (is_reg == 0) { + if (is_pre) { + if (offset == 0) { + sprintf(ptr, "%s%s%s\tr%d, [r%d]", + opname, cond_to_str(cond), byte, rd, rn); + } else { + sprintf(ptr, "%s%s%s\tr%d, [r%d, #%s%u]%s", + opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); + } + } else { + const char *transfer = ""; + if (write_back) + transfer = "t"; + sprintf(ptr, "%s%s%s%s\tr%d, [r%d], #%s%u", + opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); + } + return ptr; + } + + uint8_t rm = insn & 0xf; + uint8_t shift_type = (insn >> 5) & 0x3; + uint8_t shift_amount = (insn >> 7) & 0x1f; + + const char *shift_name = shift_names[shift_type]; + + if (is_pre) { + if (shift_amount == 0) { + if (shift_type == 0) { + sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d]%s", + opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); + return ptr; + } + if (shift_type == 3) { + sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", + opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); + return ptr; + } + shift_amount = 32; + } + sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", + opname, cond_to_str(cond), byte, rd, rn, minus, rm, + shift_name, shift_amount, bang); + return ptr; + } + + const char *transfer = ""; + if (write_back) + transfer = "t"; + + if (shift_amount == 0) { + if (shift_type == 0) { + sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d", + opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); + return ptr; + } + if (shift_type == 3) { + sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, RRX", + opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); + return ptr; + } + shift_amount = 32; + } + + sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", + opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, + shift_name, shift_amount); + return ptr; +} + +char *ARM_Disasm::disasm_memhalf(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t is_load = (insn >> 20) & 0x1; + uint8_t write_back = (insn >> 21) & 0x1; + uint8_t is_immed = (insn >> 22) & 0x1; + uint8_t is_up = (insn >> 23) & 0x1; + uint8_t is_pre = (insn >> 24) & 0x1; + uint8_t rn = (insn >> 16) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint8_t bits_65 = (insn >> 5) & 0x3; + uint8_t rm = insn & 0xf; + uint8_t offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); + + const char *opname = "ldr"; + if (is_load == 0) + opname = "str"; + + const char *width = ""; + if (bits_65 == 1) + width = "h"; + else if (bits_65 == 2) + width = "sb"; + else + width = "sh"; + + const char *bang = ""; + if (write_back) + bang = "!"; + const char *minus = ""; + if (is_up == 0) + minus = "-"; + + if (is_immed) { + if (is_pre) { + if (offset == 0) { + sprintf(ptr, "%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); + } else { + sprintf(ptr, "%s%sh\tr%d, [r%d, #%s%u]%s", + opname, cond_to_str(cond), rd, rn, minus, offset, bang); + } + } else { + sprintf(ptr, "%s%sh\tr%d, [r%d], #%s%u", + opname, cond_to_str(cond), rd, rn, minus, offset); + } + return ptr; + } + + if (is_pre) { + sprintf(ptr, "%s%sh\tr%d, [r%d, %sr%d]%s", + opname, cond_to_str(cond), rd, rn, minus, rm, bang); + } else { + sprintf(ptr, "%s%sh\tr%d, [r%d], %sr%d", + opname, cond_to_str(cond), rd, rn, minus, rm); + } + return ptr; +} + +char *ARM_Disasm::disasm_mcr(Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t crn = (insn >> 16) & 0xf; + uint8_t crd = (insn >> 12) & 0xf; + uint8_t cpnum = (insn >> 8) & 0xf; + uint8_t opcode2 = (insn >> 5) & 0x7; + uint8_t crm = insn & 0xf; + + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", + opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); + return ptr; +} + +char *ARM_Disasm::disasm_mla(Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rd = (insn >> 16) & 0xf; + uint8_t rn = (insn >> 12) & 0xf; + uint8_t rs = (insn >> 8) & 0xf; + uint8_t rm = insn & 0xf; + uint8_t bit_s = (insn >> 20) & 1; + + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", + opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); + return ptr; +} + +char *ARM_Disasm::disasm_umlal(Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rdhi = (insn >> 16) & 0xf; + uint8_t rdlo = (insn >> 12) & 0xf; + uint8_t rs = (insn >> 8) & 0xf; + uint8_t rm = insn & 0xf; + uint8_t bit_s = (insn >> 20) & 1; + + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", + opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); + return ptr; +} + +char *ARM_Disasm::disasm_mul(Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rd = (insn >> 16) & 0xf; + uint8_t rs = (insn >> 8) & 0xf; + uint8_t rm = insn & 0xf; + uint8_t bit_s = (insn >> 20) & 1; + + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s%s\tr%d, r%d, r%d", + opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); + return ptr; +} + +char *ARM_Disasm::disasm_mrs(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint8_t ps = (insn >> 22) & 1; + + sprintf(ptr, "mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); + return ptr; +} + +char *ARM_Disasm::disasm_msr(uint32_t insn, char *ptr) +{ + char flags[8]; + int flag_index = 0; + uint8_t cond = (insn >> 28) & 0xf; + uint8_t is_immed = (insn >> 25) & 0x1; + uint8_t pd = (insn >> 22) & 1; + uint8_t mask = (insn >> 16) & 0xf; + + if (mask & 1) + flags[flag_index++] = 'c'; + if (mask & 2) + flags[flag_index++] = 'x'; + if (mask & 4) + flags[flag_index++] = 's'; + if (mask & 8) + flags[flag_index++] = 'f'; + flags[flag_index] = 0; + + if (is_immed) { + uint32_t immed = insn & 0xff; + uint8_t rotate = (insn >> 8) & 0xf; + uint8_t rotate2 = rotate << 1; + uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); + sprintf(ptr, "msr%s\t%s_%s, #0x%x", + cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); + return ptr; + } + + uint8_t rm = insn & 0xf; + + sprintf(ptr, "msr%s\t%s_%s, r%d", + cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); + return ptr; +} + +char *ARM_Disasm::disasm_pld(uint32_t insn, char *ptr) +{ + uint8_t is_reg = (insn >> 25) & 0x1; + uint8_t is_up = (insn >> 23) & 0x1; + uint8_t rn = (insn >> 16) & 0xf; + + const char *minus = ""; + if (is_up == 0) + minus = "-"; + + if (is_reg) { + uint8_t rm = insn & 0xf; + sprintf(ptr, "pld\t[r%d, %sr%d]", rn, minus, rm); + return ptr; + } + + uint16_t offset = insn & 0xfff; + if (offset == 0) { + sprintf(ptr, "pld\t[r%d]", rn); + } else { + sprintf(ptr, "pld\t[r%d, #%s%u]", rn, minus, offset); + } + return ptr; +} + +char *ARM_Disasm::disasm_swi(uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint32_t sysnum = insn & 0x00ffffff; + + sprintf(ptr, "swi%s 0x%x", cond_to_str(cond), sysnum); + return ptr; +} + +char *ARM_Disasm::disasm_swp(Opcode opcode, uint32_t insn, char *ptr) +{ + uint8_t cond = (insn >> 28) & 0xf; + uint8_t rn = (insn >> 16) & 0xf; + uint8_t rd = (insn >> 12) & 0xf; + uint8_t rm = insn & 0xf; + + const char *opname = opcode_names[opcode]; + sprintf(ptr, "%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); + return ptr; +} + +Opcode ARM_Disasm::decode(uint32_t insn) { + uint32_t bits27_26 = (insn >> 26) & 0x3; + switch (bits27_26) { + case 0x0: + return decode00(insn); + case 0x1: + return decode01(insn); + case 0x2: + return decode10(insn); + case 0x3: + return decode11(insn); + } + return OP_INVALID; +} + +Opcode ARM_Disasm::decode00(uint32_t insn) { + uint8_t bit25 = (insn >> 25) & 0x1; + uint8_t bit4 = (insn >> 4) & 0x1; + if (bit25 == 0 && bit4 == 1) { + if ((insn & 0x0ffffff0) == 0x012fff10) { + // Bx instruction + return OP_BX; + } + if ((insn & 0x0ff000f0) == 0x01600010) { + // Clz instruction + return OP_CLZ; + } + if ((insn & 0xfff000f0) == 0xe1200070) { + // Bkpt instruction + return OP_BKPT; + } + uint32_t bits7_4 = (insn >> 4) & 0xf; + if (bits7_4 == 0x9) { + if ((insn & 0x0ff00ff0) == 0x01000090) { + // Swp instruction + uint8_t bit22 = (insn >> 22) & 0x1; + if (bit22) + return OP_SWPB; + return OP_SWP; + } + // One of the multiply instructions + return decode_mul(insn); + } + + uint8_t bit7 = (insn >> 7) & 0x1; + if (bit7 == 1) { + // One of the load/store halfword/byte instructions + return decode_ldrh(insn); + } + } + + // One of the data processing instructions + return decode_alu(insn); +} + +Opcode ARM_Disasm::decode01(uint32_t insn) { + uint8_t is_reg = (insn >> 25) & 0x1; + uint8_t bit4 = (insn >> 4) & 0x1; + if (is_reg == 1 && bit4 == 1) + return OP_UNDEFINED; + uint8_t is_load = (insn >> 20) & 0x1; + uint8_t is_byte = (insn >> 22) & 0x1; + if ((insn & 0xfd70f000) == 0xf550f000) { + // Pre-load + return OP_PLD; + } + if (is_load) { + if (is_byte) { + // Load byte + return OP_LDRB; + } + // Load word + return OP_LDR; + } + if (is_byte) { + // Store byte + return OP_STRB; + } + // Store word + return OP_STR; +} + +Opcode ARM_Disasm::decode10(uint32_t insn) { + uint8_t bit25 = (insn >> 25) & 0x1; + if (bit25 == 0) { + // LDM/STM + uint8_t is_load = (insn >> 20) & 0x1; + if (is_load) + return OP_LDM; + return OP_STM; + } + // Branch or Branch with link + uint8_t is_link = (insn >> 24) & 1; + uint32_t offset = insn & 0xffffff; + + // Sign-extend the 24-bit offset + if ((offset >> 23) & 1) + offset |= 0xff000000; + + // Pre-compute the left-shift and the prefetch offset + offset <<= 2; + offset += 8; + if (is_link == 0) + return OP_B; + return OP_BL; +} + +Opcode ARM_Disasm::decode11(uint32_t insn) { + uint8_t bit25 = (insn >> 25) & 0x1; + if (bit25 == 0) { + // LDC, SDC + uint8_t is_load = (insn >> 20) & 0x1; + if (is_load) { + // LDC + return OP_LDC; + } + // STC + return OP_STC; + } + + uint8_t bit24 = (insn >> 24) & 0x1; + if (bit24 == 0x1) { + // SWI + return OP_SWI; + } + + uint8_t bit4 = (insn >> 4) & 0x1; + uint8_t cpnum = (insn >> 8) & 0xf; + + if (cpnum == 15) { + // Special case for coprocessor 15 + uint8_t opcode = (insn >> 21) & 0x7; + if (bit4 == 0 || opcode != 0) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + + // MRC, MCR + uint8_t is_mrc = (insn >> 20) & 0x1; + if (is_mrc) + return OP_MRC; + return OP_MCR; + } + + if (bit4 == 0) { + // CDP + return OP_CDP; + } + // MRC, MCR + uint8_t is_mrc = (insn >> 20) & 0x1; + if (is_mrc) + return OP_MRC; + return OP_MCR; +} + +Opcode ARM_Disasm::decode_mul(uint32_t insn) { + uint8_t bit24 = (insn >> 24) & 0x1; + if (bit24 != 0) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + uint8_t bit23 = (insn >> 23) & 0x1; + uint8_t bit22_U = (insn >> 22) & 0x1; + uint8_t bit21_A = (insn >> 21) & 0x1; + if (bit23 == 0) { + // 32-bit multiply + if (bit22_U != 0) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + if (bit21_A == 0) + return OP_MUL; + return OP_MLA; + } + // 64-bit multiply + if (bit22_U == 0) { + // Unsigned multiply long + if (bit21_A == 0) + return OP_UMULL; + return OP_UMLAL; + } + // Signed multiply long + if (bit21_A == 0) + return OP_SMULL; + return OP_SMLAL; +} + +Opcode ARM_Disasm::decode_ldrh(uint32_t insn) { + uint8_t is_load = (insn >> 20) & 0x1; + uint8_t bits_65 = (insn >> 5) & 0x3; + if (is_load) { + if (bits_65 == 0x1) { + // Load unsigned halfword + return OP_LDRH; + } else if (bits_65 == 0x2) { + // Load signed byte + return OP_LDRSB; + } + // Signed halfword + if (bits_65 != 0x3) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + // Load signed halfword + return OP_LDRSH; + } + // Store halfword + if (bits_65 != 0x1) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + // Store halfword + return OP_STRH; +} + +Opcode ARM_Disasm::decode_alu(uint32_t insn) { + uint8_t is_immed = (insn >> 25) & 0x1; + uint8_t opcode = (insn >> 21) & 0xf; + uint8_t bit_s = (insn >> 20) & 1; + uint8_t shift_is_reg = (insn >> 4) & 1; + uint8_t bit7 = (insn >> 7) & 1; + if (!is_immed && shift_is_reg && (bit7 != 0)) { + // This is an unexpected bit pattern. Create an undefined + // instruction in case this is ever executed. + return OP_UNDEFINED; + } + switch (opcode) { + case 0x0: + return OP_AND; + case 0x1: + return OP_EOR; + case 0x2: + return OP_SUB; + case 0x3: + return OP_RSB; + case 0x4: + return OP_ADD; + case 0x5: + return OP_ADC; + case 0x6: + return OP_SBC; + case 0x7: + return OP_RSC; + case 0x8: + if (bit_s) + return OP_TST; + return OP_MRS; + case 0x9: + if (bit_s) + return OP_TEQ; + return OP_MSR; + case 0xa: + if (bit_s) + return OP_CMP; + return OP_MRS; + case 0xb: + if (bit_s) + return OP_CMN; + return OP_MSR; + case 0xc: + return OP_ORR; + case 0xd: + return OP_MOV; + case 0xe: + return OP_BIC; + case 0xf: + return OP_MVN; + } + // Unreachable + return OP_INVALID; +} \ No newline at end of file diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h new file mode 100644 index 00000000..9600e2ad --- /dev/null +++ b/src/core/arm/disassembler/arm_disasm.h @@ -0,0 +1,146 @@ +// Copyright 2006 The Android Open Source Project + +#ifndef ARMDIS_H +#define ARMDIS_H + +#include + +// Note: this list of opcodes must match the list used to initialize +// the opflags[] array in opcode.cpp. +enum Opcode { + OP_INVALID, + OP_UNDEFINED, + OP_ADC, + OP_ADD, + OP_AND, + OP_B, + OP_BL, + OP_BIC, + OP_BKPT, + OP_BLX, + OP_BX, + OP_CDP, + OP_CLZ, + OP_CMN, + OP_CMP, + OP_EOR, + OP_LDC, + OP_LDM, + OP_LDR, + OP_LDRB, + OP_LDRBT, + OP_LDRH, + OP_LDRSB, + OP_LDRSH, + OP_LDRT, + OP_MCR, + OP_MLA, + OP_MOV, + OP_MRC, + OP_MRS, + OP_MSR, + OP_MUL, + OP_MVN, + OP_ORR, + OP_PLD, + OP_RSB, + OP_RSC, + OP_SBC, + OP_SMLAL, + OP_SMULL, + OP_STC, + OP_STM, + OP_STR, + OP_STRB, + OP_STRBT, + OP_STRH, + OP_STRT, + OP_SUB, + OP_SWI, + OP_SWP, + OP_SWPB, + OP_TEQ, + OP_TST, + OP_UMLAL, + OP_UMULL, + + // Define thumb opcodes + OP_THUMB_UNDEFINED, + OP_THUMB_ADC, + OP_THUMB_ADD, + OP_THUMB_AND, + OP_THUMB_ASR, + OP_THUMB_B, + OP_THUMB_BIC, + OP_THUMB_BKPT, + OP_THUMB_BL, + OP_THUMB_BLX, + OP_THUMB_BX, + OP_THUMB_CMN, + OP_THUMB_CMP, + OP_THUMB_EOR, + OP_THUMB_LDMIA, + OP_THUMB_LDR, + OP_THUMB_LDRB, + OP_THUMB_LDRH, + OP_THUMB_LDRSB, + OP_THUMB_LDRSH, + OP_THUMB_LSL, + OP_THUMB_LSR, + OP_THUMB_MOV, + OP_THUMB_MUL, + OP_THUMB_MVN, + OP_THUMB_NEG, + OP_THUMB_ORR, + OP_THUMB_POP, + OP_THUMB_PUSH, + OP_THUMB_ROR, + OP_THUMB_SBC, + OP_THUMB_STMIA, + OP_THUMB_STR, + OP_THUMB_STRB, + OP_THUMB_STRH, + OP_THUMB_SUB, + OP_THUMB_SWI, + OP_THUMB_TST, + + OP_END // must be last +}; + +class ARM_Disasm { + public: + static char *disasm(uint32_t addr, uint32_t insn, char *buffer); + static Opcode decode(uint32_t insn); + + private: + static Opcode decode00(uint32_t insn); + static Opcode decode01(uint32_t insn); + static Opcode decode10(uint32_t insn); + static Opcode decode11(uint32_t insn); + static Opcode decode_mul(uint32_t insn); + static Opcode decode_ldrh(uint32_t insn); + static Opcode decode_alu(uint32_t insn); + + static char *disasm_alu(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_bx(uint32_t insn, char *ptr); + static char *disasm_bkpt(uint32_t insn, char *ptr); + static char *disasm_clz(uint32_t insn, char *ptr); + static char *disasm_memblock(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_mem(uint32_t insn, char *ptr); + static char *disasm_memhalf(uint32_t insn, char *ptr); + static char *disasm_mcr(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_mla(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_umlal(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_mul(Opcode opcode, uint32_t insn, char *ptr); + static char *disasm_mrs(uint32_t insn, char *ptr); + static char *disasm_msr(uint32_t insn, char *ptr); + static char *disasm_pld(uint32_t insn, char *ptr); + static char *disasm_swi(uint32_t insn, char *ptr); + static char *disasm_swp(Opcode opcode, uint32_t insn, char *ptr); +}; + +extern char *disasm_insn_thumb(uint32_t pc, uint32_t insn1, uint32_t insn2, char *result); +extern Opcode decode_insn_thumb(uint32_t given); + +#endif /* ARMDIS_H */ diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp new file mode 100644 index 00000000..a74aa26c --- /dev/null +++ b/src/core/arm/interpreter/arm_interpreter.cpp @@ -0,0 +1,86 @@ +/** + * Copyright (C) 2013 Citrus Emulator + * + * @file arm_interpreter.h + * @author bunnei + * @date 2014-04-04 + * @brief ARM interface instance for SkyEye interprerer + * + * @section LICENSE + * 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 at + * http://www.gnu.org/copyleft/gpl.html + * + * Official project repository can be found at: + * http://code.google.com/p/gekko-gc-emu/ + */ + +#include "arm_interpreter.h" + +const static cpu_config_t s_arm11_cpu_info = { + "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE +}; + +ARM_Interpreter::ARM_Interpreter() { + + state = new ARMul_State; + + ARMul_EmulateInit(); + ARMul_NewState(state); + + state->abort_model = 0; + state->cpu = (cpu_config_t*)&s_arm11_cpu_info; + state->bigendSig = LOW; + + ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); + state->lateabtSig = LOW; + mmu_init(state); + + // Reset the core to initial state + ARMul_Reset(state); + state->NextInstr = 0; + state->Emulate = 3; + + state->pc = state->Reg[15] = 0x00000000; + state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack +} + +void ARM_Interpreter::SetPC(u32 pc) { + state->pc = state->Reg[15] = pc; +} + +u32 ARM_Interpreter::PC() { + return state->pc; +} + +u32 ARM_Interpreter::Reg(int index){ + return state->Reg[index]; +} + +u32 ARM_Interpreter::CPSR() { + return state->Cpsr; +} + +ARM_Interpreter::~ARM_Interpreter() { + delete state; +} + +void ARM_Interpreter::ExecuteInstruction() { + state->step++; + state->cycle++; + state->EndCondition = 0; + state->stop_simulator = 0; + state->NextInstr = RESUME; + state->last_pc = state->Reg[15]; + state->Reg[15] = ARMul_DoInstr(state); + state->Cpsr = ((state->Cpsr & 0x0fffffdf) | (state->NFlag << 31) | (state->ZFlag << 30) | + (state->CFlag << 29) | (state->VFlag << 28) | (state->TFlag << 5)); + FLUSHPIPE; +} diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h new file mode 100644 index 00000000..074149f1 --- /dev/null +++ b/src/core/arm/interpreter/arm_interpreter.h @@ -0,0 +1,57 @@ +/** +* Copyright (C) 2013 Citrus Emulator +* +* @file arm_interpreter.h +* @author bunnei +* @date 2014-04-04 +* @brief ARM interface instance for SkyEye interprerer +* +* @section LICENSE +* 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 at +* http://www.gnu.org/copyleft/gpl.html +* +* Official project repository can be found at: +* http://code.google.com/p/gekko-gc-emu/ +*/ + +#pragma once + +#include "common.h" +#include "common_types.h" +#include "arm/arm_interface.h" + +#include "arm/interpreter/armdefs.h" +#include "arm/interpreter/armemu.h" + +class ARM_Interpreter : virtual public ARM_Interface { +public: + ARM_Interpreter(); + ~ARM_Interpreter(); + + void ExecuteInstruction(); + + void SetPC(u32 pc); + + u32 PC(); + + u32 Reg(int index); + + u32 CPSR(); + + u64 GetTicks() { + return ARMul_Time(state); + } + +private: + ARMul_State* state; + + DISALLOW_COPY_AND_ASSIGN(ARM_Interpreter); +}; diff --git a/src/core/arm/interpreter/arm_regformat.h b/src/core/arm/interpreter/arm_regformat.h new file mode 100644 index 00000000..0ca62780 --- /dev/null +++ b/src/core/arm/interpreter/arm_regformat.h @@ -0,0 +1,103 @@ +#ifndef __ARM_REGFORMAT_H__ +#define __ARM_REGFORMAT_H__ + +enum arm_regno{ + R0 = 0, + R1, + R2, + R3, + R4, + R5, + R6, + R7, + R8, + R9, + R10, + R11, + R12, + R13, + LR, + R15, //PC, + CPSR_REG, + SPSR_REG, +#if 1 + PHYS_PC, + R13_USR, + R14_USR, + R13_SVC, + R14_SVC, + R13_ABORT, + R14_ABORT, + R13_UNDEF, + R14_UNDEF, + R13_IRQ, + R14_IRQ, + R8_FIRQ, + R9_FIRQ, + R10_FIRQ, + R11_FIRQ, + R12_FIRQ, + R13_FIRQ, + R14_FIRQ, + SPSR_INVALID1, + SPSR_INVALID2, + SPSR_SVC, + SPSR_ABORT, + SPSR_UNDEF, + SPSR_IRQ, + SPSR_FIRQ, + MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */ + BANK_REG, + EXCLUSIVE_TAG, + EXCLUSIVE_STATE, + EXCLUSIVE_RESULT, + CP15_BASE, + CP15_C0 = CP15_BASE, + CP15_C0_C0 = CP15_C0, + CP15_MAIN_ID = CP15_C0_C0, + CP15_CACHE_TYPE, + CP15_TCM_STATUS, + CP15_TLB_TYPE, + CP15_C0_C1, + CP15_PROCESSOR_FEATURE_0 = CP15_C0_C1, + CP15_PROCESSOR_FEATURE_1, + CP15_DEBUG_FEATURE_0, + CP15_AUXILIARY_FEATURE_0, + CP15_C1_C0, + CP15_CONTROL = CP15_C1_C0, + 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, + CP15_TRANSLATION_BASE_TABLE_1, + CP15_TRANSLATION_BASE_CONTROL, + CP15_DOMAIN_ACCESS_CONTROL, + CP15_RESERVED, + /* Fault status */ + CP15_FAULT_STATUS, + CP15_INSTR_FAULT_STATUS, + CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, + CP15_INST_FSR, + /* Fault Address register */ + CP15_FAULT_ADDRESS, + CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, + CP15_WFAR, + CP15_IFAR, + CP15_PID, + CP15_CONTEXT_ID, + CP15_THREAD_URO, + 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, +#endif + MAX_REG_NUM, +}; + +#define VFP_OFFSET(x) (x - VFP_BASE) +#endif diff --git a/src/core/arm/interpreter/armcpu.h b/src/core/arm/interpreter/armcpu.h new file mode 100644 index 00000000..d7e336b9 --- /dev/null +++ b/src/core/arm/interpreter/armcpu.h @@ -0,0 +1,83 @@ +/* + * arm + * armcpu.h + * + * Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ARM_CPU_H__ +#define __ARM_CPU_H__ +//#include +//#include +//#include +//#include + +#include +#include + +#include "thread.h" + + +typedef struct ARM_CPU_State_s { + ARMul_State * core; + uint32_t core_num; + /* The core id that boot from + */ + uint32_t boot_core_id; +}ARM_CPU_State; + +//static ARM_CPU_State* get_current_cpu(){ +// machine_config_t* mach = get_current_mach(); +// /* Casting a conf_obj_t to ARM_CPU_State type */ +// ARM_CPU_State* cpu = (ARM_CPU_State*)mach->cpu_data->obj; +// +// return cpu; +//} + +/** +* @brief Get the core instance boot from +* +* @return +*/ +//static ARMul_State* get_boot_core(){ +// ARM_CPU_State* cpu = get_current_cpu(); +// return &cpu->core[cpu->boot_core_id]; +//} +/** +* @brief Get the instance of running core +* +* @return the core instance +*/ +//static ARMul_State* get_current_core(){ +// /* Casting a conf_obj_t to ARM_CPU_State type */ +// int id = Common::CurrentThreadId(); +// /* If thread is not in running mode, we should give the boot core */ +// if(get_thread_state(id) != Running_state){ +// return get_boot_core(); +// } +// /* Judge if we are running in paralell or sequenial */ +// if(thread_exist(id)){ +// conf_object_t* conf_obj = get_current_exec_priv(id); +// return (ARMul_State*)get_cast_conf_obj(conf_obj, "arm_core_t"); +// } +// +// return NULL; +//} + +#define CURRENT_CORE get_current_core() + +#endif + diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/interpreter/armdefs.h new file mode 100644 index 00000000..0136a52d --- /dev/null +++ b/src/core/arm/interpreter/armdefs.h @@ -0,0 +1,934 @@ +/* armdefs.h -- ARMulator common 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. */ + +#ifndef _ARMDEFS_H_ +#define _ARMDEFS_H_ + +#include +#include +#include + +#if EMU_PLATFORM == PLATFORM_WINDOWS +#include +#endif + +//teawater add for arm2x86 2005.02.14------------------------------------------- +// koodailar remove it for mingw 2005.12.18---------------- +//anthonylee modify it for portable 2007.01.30 +//#include "portable/mman.h" + +#include "arm_regformat.h" +#include "platform.h" +#include "skyeye_defs.h" + +//AJ2D-------------------------------------------------------------------------- + +//teawater add for arm2x86 2005.07.03------------------------------------------- + +#include +#include +#include +#include +#if EMU_PLATFORM == PLATFORM_LINUX +#include +#endif +#include +#include +#include + +//#include +//AJ2D-------------------------------------------------------------------------- +#if 0 +#if 0 +#define DIFF_STATE 1 +#define __FOLLOW_MODE__ 0 +#else +#define DIFF_STATE 0 +#define __FOLLOW_MODE__ 1 +#endif +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define LOW 0 +#define HIGH 1 +#define LOWHIGH 1 +#define HIGHLOW 2 + +#ifndef u8 +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define u64 unsigned long long +#endif /*u8 */ + +//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- +#include + +#include "platform.h" + +#if EMU_PLATFORM == PLATFORM_LINUX +#include +#endif + +//#define DBCT_TEST_SPEED +#define DBCT_TEST_SPEED_SEC 10 +//AJ2D-------------------------------------------------------------------------- + +//teawater add compile switch for DBCT GDB RSP function 2005.10.21-------------- +//#define DBCT_GDBRSP +//AJ2D-------------------------------------------------------------------------- + +//#include +//#include + +#define ARM_BYTE_TYPE 0 +#define ARM_HALFWORD_TYPE 1 +#define ARM_WORD_TYPE 2 + +//the define of cachetype +#define NONCACHE 0 +#define DATACACHE 1 +#define INSTCACHE 2 + +#ifndef __STDC__ +typedef char *VoidStar; +#endif + +typedef unsigned long long ARMdword; /* must be 64 bits wide */ +typedef unsigned int ARMword; /* must be 32 bits wide */ +typedef unsigned char ARMbyte; /* must be 8 bits wide */ +typedef unsigned short ARMhword; /* must be 16 bits wide */ +typedef struct ARMul_State ARMul_State; +typedef struct ARMul_io ARMul_io; +typedef struct ARMul_Energy ARMul_Energy; + +//teawater add for arm2x86 2005.06.24------------------------------------------- +#include +//AJ2D-------------------------------------------------------------------------- +/* +//chy 2005-05-11 +#ifndef __CYGWIN__ +//teawater add for arm2x86 2005.02.14------------------------------------------- +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int u32; +#if defined (__x86_64__) +typedef unsigned long uint64_t; +#else +typedef unsigned long long uint64_t; +#endif +////AJ2D-------------------------------------------------------------------------- +#endif +*/ + +#include "armmmu.h" +//#include "lcd/skyeye_lcd.h" + + +//#include "skyeye.h" +//#include "skyeye_device.h" +//#include "net/skyeye_net.h" +//#include "skyeye_config.h" + + +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); + + +//added by ksh,2004-3-5 +struct ARMul_io +{ + ARMword *instr; //to display the current interrupt state + ARMword *net_flag; //to judge if network is enabled + ARMword *net_int; //netcard interrupt + + //ywc,2004-04-01 + ARMword *ts_int; + ARMword *ts_is_enable; + ARMword *ts_addr_begin; + ARMword *ts_addr_end; + ARMword *ts_buffer; +}; + +/* added by ksh,2004-11-26,some energy profiling */ +struct ARMul_Energy +{ + int energy_prof; /* BUG200103282109 : for energy profiling */ + int enable_func_energy; /* BUG200105181702 */ + char *func_energy; + int func_display; /* BUG200103311509 : for function call display */ + int func_disp_start; /* BUG200104191428 : to start func profiling */ + char *start_func; /* BUG200104191428 */ + + FILE *outfile; /* BUG200105201531 : direct console to file */ + long long tcycle, pcycle; + float t_energy; + void *cur_task; /* BUG200103291737 */ + long long t_mem_cycle, t_idle_cycle, t_uart_cycle; + long long p_mem_cycle, p_idle_cycle, p_uart_cycle; + long long p_io_update_tcycle; + /*record CCCR,to get current core frequency */ + ARMword cccr; +}; +#if 0 +#define MAX_BANK 8 +#define MAX_STR 1024 + +typedef struct mem_bank +{ + ARMword (*read_byte) (ARMul_State * state, ARMword addr); + void (*write_byte) (ARMul_State * state, ARMword addr, ARMword data); + ARMword (*read_halfword) (ARMul_State * state, ARMword addr); + void (*write_halfword) (ARMul_State * state, ARMword addr, + ARMword data); + ARMword (*read_word) (ARMul_State * state, ARMword addr); + void (*write_word) (ARMul_State * state, ARMword addr, ARMword data); + unsigned int addr, len; + char filename[MAX_STR]; + unsigned type; //chy 2003-09-21: maybe io,ram,rom +} mem_bank_t; +typedef struct +{ + int bank_num; + int current_num; /*current num of bank */ + mem_bank_t mem_banks[MAX_BANK]; +} mem_config_t; +#endif +#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 */ + ARMword Cpsr; /* the current psr */ + ARMword Spsr_copy; + ARMword phys_pc; + ARMword Reg_usr[2]; + ARMword Reg_svc[2]; /* R13_SVC R14_SVC */ + ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */ + ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */ + ARMword Reg_irq[2]; /* R13_IRQ R14_IRQ */ + ARMword Reg_firq[7]; /* R8---R14 FIRQ */ + ARMword Spsr[7]; /* the exception psr's */ + ARMword Mode; /* the current mode */ + ARMword Bank; /* the current register bank */ + ARMword exclusive_tag; + ARMword exclusive_state; + ARMword exclusive_result; + ARMword CP15[VFP_BASE - CP15_BASE]; + ARMword VFP[3]; /* FPSID, FPSCR, and FPEXC */ + /* 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 */ + //chy:2003-08-19, used in arm xscale + /* 40 bit accumulator. We always keep this 64 bits wide, + and move only 40 bits out of it in an MRA insn. */ + ARMdword Accumulator; + + ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; /* dummy flags for speed */ + unsigned long long int icounter, debug_icounter, kernel_icounter; + unsigned int shifter_carry_out; + //ARMword translate_pc; + + /* add armv6 flags dyf:2010-08-09 */ + ARMword GEFlag, EFlag, AFlag, QFlags; + //chy:2003-08-19, used in arm v5e|xscale + ARMword SFlag; +#ifdef MODET + ARMword TFlag; /* Thumb state */ +#endif + ARMword instr, pc, temp; /* saved register state */ + ARMword loaded, decoded; /* saved pipeline state */ + //chy 2006-04-12 for ICE breakpoint + ARMword loaded_addr, decoded_addr; /* saved pipeline state addr*/ + unsigned int NumScycles, NumNcycles, NumIcycles, NumCcycles, NumFcycles; /* emulated cycles used */ + unsigned long long NumInstrs; /* the number of instructions executed */ + unsigned NextInstr; + unsigned VectorCatch; /* caught exception mask */ + unsigned CallDebug; /* set to call the debugger */ + unsigned CanWatch; /* set by memory interface if its willing to suffer the + overhead of checking for watchpoints on each memory + access */ + unsigned int StopHandle; + + char *CommandLine; /* Command Line from ARMsd */ + + 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 EventSet; /* the number of events in the queue */ + unsigned int Now; /* time to the nearest cycle */ + struct EventNode **EventPtr; /* the event list */ + + unsigned Debug; /* show instructions as they are executed */ + unsigned NresetSig; /* reset the processor */ + unsigned NfiqSig; + unsigned NirqSig; + + unsigned abortSig; + unsigned NtransSig; + unsigned bigendSig; + unsigned prog32Sig; + unsigned data32Sig; + unsigned syscallSig; + +/* 2004-05-09 chy +---------------------------------------------------------- +read ARM Architecture Reference Manual +2.6.5 Data Abort +There are three Abort Model in ARM arch. + +Early Abort Model: used in some ARMv3 and earlier implementations. In this +model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and +the base register was unchanged for all other instructions. (oldest) + +Base Restored Abort Model: If a Data Abort occurs in an instruction which +specifies base register writeback, the value in the base register is +unchanged. (strongarm, xscale) + +Base Updated Abort Model: If a Data Abort occurs in an instruction which +specifies base register writeback, the base register writeback still occurs. +(arm720T) + +read PART B +chap2 The System Control Coprocessor CP15 +2.4 Register1:control register +L(bit 6): in some ARMv3 and earlier implementations, the abort model of the +processor could be configured: +0=early Abort Model Selected(now obsolete) +1=Late Abort Model selceted(same as Base Updated Abort Model) + +on later processors, this bit reads as 1 and ignores writes. +------------------------------------------------------------- +So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) + if lateabtSig=0, then it means Base Restored Abort Model +*/ + unsigned lateabtSig; + + ARMword Vector; /* synthesize aborts in cycle modes */ + ARMword Aborted; /* sticky flag for aborts */ + ARMword 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 */ + + const struct Dbg_HostosInterface *hostif; + + int verbose; /* non-zero means print various messages like the banner */ + + mmu_state_t mmu; + int mmu_inited; + //mem_state_t mem; + /*remove io_state to skyeye_mach_*.c files */ + //io_state_t io; + /* point to a interrupt pending register. now for skyeye-ne2k.c + * later should move somewhere. e.g machine_config_t*/ + + + //chy: 2003-08-11, for different arm core type + unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */ + unsigned is_v5; /* Are we emulating a v5 architecture ? */ + unsigned is_v5e; /* Are we emulating a v5e architecture ? */ + unsigned is_v6; /* Are we emulating a v6 architecture ? */ + unsigned is_v7; /* Are we emulating a v7 architecture ? */ + unsigned is_XScale; /* Are we emulating an XScale architecture ? */ + unsigned is_iWMMXt; /* Are we emulating an iWMMXt co-processor ? */ + unsigned is_ep9312; /* Are we emulating a Cirrus Maverick co-processor ? */ + //chy 2005-09-19 + unsigned is_pxa27x; /* Are we emulating a Intel PXA27x co-processor ? */ + //chy: seems only used in xscale's CP14 + unsigned int LastTime; /* Value of last call to ARMul_Time() */ + ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit 3 set */ + + +//added by ksh:for handle different machs io 2004-3-5 + ARMul_io mach_io; + +/*added by ksh,2004-11-26,some energy profiling*/ + ARMul_Energy energy; + +//teawater add for next_dis 2004.10.27----------------------- + int disassemble; +//AJ2D------------------------------------------ + +//teawater add for arm2x86 2005.02.15------------------------------------------- + u32 trap; + u32 tea_break_addr; + u32 tea_break_ok; + int tea_pc; +//AJ2D-------------------------------------------------------------------------- +//teawater add for arm2x86 2005.07.03------------------------------------------- + + /* + * 2007-01-24 removed the term-io functions by Anthony Lee, + * moved to "device/uart/skyeye_uart_stdio.c". + */ + +//AJ2D-------------------------------------------------------------------------- +//teawater add for arm2x86 2005.07.05------------------------------------------- + //arm_arm A2-18 + int abort_model; //0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model +//AJ2D-------------------------------------------------------------------------- +//teawater change for return if running tb dirty 2005.07.09--------------------- + void *tb_now; +//AJ2D-------------------------------------------------------------------------- + +//teawater add for record reg value to ./reg.txt 2005.07.10--------------------- + FILE *tea_reg_fd; +//AJ2D-------------------------------------------------------------------------- + +/*added by ksh in 2005-10-1*/ + cpu_config_t *cpu; + //mem_config_t *mem_bank; + +/* added LPC remap function */ + int vector_remap_flag; + u32 vector_remap_addr; + u32 vector_remap_size; + + u32 step; + u32 cycle; + int stop_simulator; + conf_object_t *dyncom_cpu; +//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- +#ifdef DBCT_TEST_SPEED + uint64_t instr_count; +#endif //DBCT_TEST_SPEED +// FILE * state_log; +//diff log +//#if DIFF_STATE + FILE * state_log; +//#endif + /* monitored memory for exclusice access */ + ARMword exclusive_tag_array[128]; + /* 1 means exclusive access and 0 means open access */ + ARMword exclusive_access_state; + + memory_space_intf space; + u32 CurrInstr; + u32 last_pc; /* the last pc executed */ + u32 last_instr; /* the last inst executed */ + u32 WriteAddr[17]; + u32 WriteData[17]; + u32 WritePc[17]; + u32 CurrWrite; +}; +#define DIFF_WRITE 0 + +typedef ARMul_State arm_core_t; +#define ResetPin NresetSig +#define FIQPin NfiqSig +#define IRQPin NirqSig +#define AbortPin abortSig +#define TransPin NtransSig +#define BigEndPin bigendSig +#define Prog32Pin prog32Sig +#define Data32Pin data32Sig +#define LateAbortPin lateabtSig + +/***************************************************************************\ +* Types of ARM we know about * +\***************************************************************************/ + +/* The bitflags */ +#define ARM_Fix26_Prop 0x01 +#define ARM_Nexec_Prop 0x02 +#define ARM_Debug_Prop 0x10 +#define ARM_Isync_Prop ARM_Debug_Prop +#define ARM_Lock_Prop 0x20 +//chy 2003-08-11 +#define ARM_v4_Prop 0x40 +#define ARM_v5_Prop 0x80 +/*jeff.du 2010-08-05 */ +#define ARM_v6_Prop 0xc0 + +#define ARM_v5e_Prop 0x100 +#define ARM_XScale_Prop 0x200 +#define ARM_ep9312_Prop 0x400 +#define ARM_iWMMXt_Prop 0x800 +//chy 2005-09-19 +#define ARM_PXA27X_Prop 0x1000 +#define ARM_v7_Prop 0x2000 + +/* ARM2 family */ +#define ARM2 (ARM_Fix26_Prop) +#define ARM2as ARM2 +#define ARM61 ARM2 +#define ARM3 ARM2 + +#ifdef ARM60 /* previous definition in armopts.h */ +#undef ARM60 +#endif + +/* ARM6 family */ +#define ARM6 (ARM_Lock_Prop) +#define ARM60 ARM6 +#define ARM600 ARM6 +#define ARM610 ARM6 +#define ARM620 ARM6 + + +/***************************************************************************\ +* Macros to extract instruction fields * +\***************************************************************************/ + +#define BIT(n) ( (ARMword)(instr>>(n))&1) /* bit n of instruction */ +#define BITS(m,n) ( (ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) ) /* bits m to n of instr */ +#define TOPBITS(n) (instr >> (n)) /* bits 31 to n of instr */ + +/***************************************************************************\ +* The hardware vector addresses * +\***************************************************************************/ + +#define ARMResetV 0L +#define ARMUndefinedInstrV 4L +#define ARMSWIV 8L +#define ARMPrefetchAbortV 12L +#define ARMDataAbortV 16L +#define ARMAddrExceptnV 20L +#define ARMIRQV 24L +#define ARMFIQV 28L +#define ARMErrorV 32L /* This is an offset, not an address ! */ + +#define ARMul_ResetV ARMResetV +#define ARMul_UndefinedInstrV ARMUndefinedInstrV +#define ARMul_SWIV ARMSWIV +#define ARMul_PrefetchAbortV ARMPrefetchAbortV +#define ARMul_DataAbortV ARMDataAbortV +#define ARMul_AddrExceptnV ARMAddrExceptnV +#define ARMul_IRQV ARMIRQV +#define ARMul_FIQV ARMFIQV + +/***************************************************************************\ +* Mode and Bank Constants * +\***************************************************************************/ + +#define USER26MODE 0L +#define FIQ26MODE 1L +#define IRQ26MODE 2L +#define SVC26MODE 3L +#define USER32MODE 16L +#define FIQ32MODE 17L +#define IRQ32MODE 18L +#define SVC32MODE 19L +#define ABORT32MODE 23L +#define UNDEF32MODE 27L +//chy 2006-02-15 add system32 mode +#define SYSTEM32MODE 31L + +#define ARM32BITMODE (state->Mode > 3) +#define ARM26BITMODE (state->Mode <= 3) +#define ARMMODE (state->Mode) +#define ARMul_MODEBITS 0x1fL +#define ARMul_MODE32BIT ARM32BITMODE +#define ARMul_MODE26BIT ARM26BITMODE + +#define USERBANK 0 +#define FIQBANK 1 +#define IRQBANK 2 +#define SVCBANK 3 +#define ABORTBANK 4 +#define UNDEFBANK 5 +#define DUMMYBANK 6 +#define SYSTEMBANK USERBANK +#define BANK_CAN_ACCESS_SPSR(bank) \ + ((bank) != USERBANK && (bank) != SYSTEMBANK && (bank) != DUMMYBANK) + + +/***************************************************************************\ +* Definitons of things in the emulator * +\***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +extern void ARMul_EmulateInit (void); +extern void ARMul_Reset (ARMul_State * state); +#ifdef __cplusplus + } +#endif +extern ARMul_State *ARMul_NewState (ARMul_State * state); +extern ARMword ARMul_DoProg (ARMul_State * state); +extern ARMword ARMul_DoInstr (ARMul_State * state); +/***************************************************************************\ +* Definitons of things for event handling * +\***************************************************************************/ + +extern void ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, + unsigned (*func) ()); +extern void ARMul_EnvokeEvent (ARMul_State * state); +extern unsigned int ARMul_Time (ARMul_State * state); + +/***************************************************************************\ +* Useful support routines * +\***************************************************************************/ + +extern ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, + unsigned reg); +extern void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, + ARMword value); +extern ARMword ARMul_GetPC (ARMul_State * state); +extern ARMword ARMul_GetNextPC (ARMul_State * state); +extern void ARMul_SetPC (ARMul_State * state, ARMword value); +extern ARMword ARMul_GetR15 (ARMul_State * state); +extern void ARMul_SetR15 (ARMul_State * state, ARMword value); + +extern ARMword ARMul_GetCPSR (ARMul_State * state); +extern void ARMul_SetCPSR (ARMul_State * state, ARMword value); +extern ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode); +extern void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value); + +/***************************************************************************\ +* Definitons of things to handle aborts * +\***************************************************************************/ + +extern void ARMul_Abort (ARMul_State * state, ARMword address); +#ifdef MODET +#define ARMul_ABORTWORD (state->TFlag ? 0xefffdfff : 0xefffffff) /* SWI -1 */ +#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ + state->AbortAddr = (address & (state->TFlag ? ~1L : ~3L)) +#else +#define ARMul_ABORTWORD 0xefffffff /* SWI -1 */ +#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ + state->AbortAddr = (address & ~3L) +#endif +#define ARMul_DATAABORT(address) state->abortSig = HIGH ; \ + state->Aborted = ARMul_DataAbortV ; +#define ARMul_CLEARABORT state->abortSig = LOW + +/***************************************************************************\ +* Definitons of things in the memory interface * +\***************************************************************************/ + +extern unsigned ARMul_MemoryInit (ARMul_State * state, + unsigned int initmemsize); +extern void ARMul_MemoryExit (ARMul_State * state); + +extern ARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, + ARMword isize); +extern ARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, + ARMword isize); +#ifdef __cplusplus +extern "C" { +#endif +extern ARMword ARMul_ReLoadInstr (ARMul_State * state, ARMword address, + ARMword isize); +#ifdef __cplusplus + } +#endif +extern ARMword ARMul_LoadWordS (ARMul_State * state, ARMword address); +extern ARMword ARMul_LoadWordN (ARMul_State * state, ARMword address); +extern ARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address); +extern ARMword ARMul_LoadByte (ARMul_State * state, ARMword address); + +extern void ARMul_StoreWordS (ARMul_State * state, ARMword address, + ARMword data); +extern void ARMul_StoreWordN (ARMul_State * state, ARMword address, + ARMword data); +extern void ARMul_StoreHalfWord (ARMul_State * state, ARMword address, + ARMword data); +extern void ARMul_StoreByte (ARMul_State * state, ARMword address, + ARMword data); + +extern ARMword ARMul_SwapWord (ARMul_State * state, ARMword address, + ARMword data); +extern ARMword ARMul_SwapByte (ARMul_State * state, ARMword address, + ARMword data); + +extern void ARMul_Icycles (ARMul_State * state, unsigned number, + ARMword address); +extern void ARMul_Ccycles (ARMul_State * state, unsigned number, + ARMword address); + +extern ARMword ARMul_ReadWord (ARMul_State * state, ARMword address); +extern ARMword ARMul_ReadByte (ARMul_State * state, ARMword address); +extern void ARMul_WriteWord (ARMul_State * state, ARMword address, + ARMword data); +extern void ARMul_WriteByte (ARMul_State * state, ARMword address, + ARMword data); + +extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword, + ARMword, ARMword, ARMword, ARMword, ARMword, + ARMword, ARMword, ARMword); + +/***************************************************************************\ +* Definitons of things in the co-processor interface * +\***************************************************************************/ + +#define ARMul_FIRST 0 +#define ARMul_TRANSFER 1 +#define ARMul_BUSY 2 +#define ARMul_DATA 3 +#define ARMul_INTERRUPT 4 +#define ARMul_DONE 0 +#define ARMul_CANT 1 +#define ARMul_INC 3 + +#define ARMul_CP13_R0_FIQ 0x1 +#define ARMul_CP13_R0_IRQ 0x2 +#define ARMul_CP13_R8_PMUS 0x1 + +#define ARMul_CP14_R0_ENABLE 0x0001 +#define ARMul_CP14_R0_CLKRST 0x0004 +#define ARMul_CP14_R0_CCD 0x0008 +#define ARMul_CP14_R0_INTEN0 0x0010 +#define ARMul_CP14_R0_INTEN1 0x0020 +#define ARMul_CP14_R0_INTEN2 0x0040 +#define ARMul_CP14_R0_FLAG0 0x0100 +#define ARMul_CP14_R0_FLAG1 0x0200 +#define ARMul_CP14_R0_FLAG2 0x0400 +#define ARMul_CP14_R10_MOE_IB 0x0004 +#define ARMul_CP14_R10_MOE_DB 0x0008 +#define ARMul_CP14_R10_MOE_BT 0x000c +#define ARMul_CP15_R1_ENDIAN 0x0080 +#define ARMul_CP15_R1_ALIGN 0x0002 +#define ARMul_CP15_R5_X 0x0400 +#define ARMul_CP15_R5_ST_ALIGN 0x0001 +#define ARMul_CP15_R5_IMPRE 0x0406 +#define ARMul_CP15_R5_MMU_EXCPT 0x0400 +#define ARMul_CP15_DBCON_M 0x0100 +#define ARMul_CP15_DBCON_E1 0x000c +#define ARMul_CP15_DBCON_E0 0x0003 + +extern unsigned ARMul_CoProInit (ARMul_State * state); +extern void ARMul_CoProExit (ARMul_State * state); +extern 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); +extern void ARMul_CoProDetach (ARMul_State * state, unsigned number); + +/***************************************************************************\ +* Definitons of things in the host environment * +\***************************************************************************/ + +extern unsigned ARMul_OSInit (ARMul_State * state); +extern void ARMul_OSExit (ARMul_State * state); + +#ifdef __cplusplus + extern "C" { +#endif + +extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); +#ifdef __cplusplus +} +#endif + + +extern ARMword ARMul_OSLastErrorP (ARMul_State * state); + +extern ARMword ARMul_Debug (ARMul_State * state, ARMword pc, ARMword instr); +extern unsigned ARMul_OSException (ARMul_State * state, ARMword vector, + ARMword pc); +extern int rdi_log; + +/***************************************************************************\ +* Host-dependent stuff * +\***************************************************************************/ + +#ifdef macintosh +pascal void SpinCursor (short increment); /* copied from CursorCtl.h */ +# define HOURGLASS SpinCursor( 1 ) +# define HOURGLASS_RATE 1023 /* 2^n - 1 */ +#endif + +//teawater add for arm2x86 2005.02.14------------------------------------------- +/*ywc 2005-03-31*/ +/* +#include "arm2x86.h" +#include "arm2x86_dp.h" +#include "arm2x86_movl.h" +#include "arm2x86_psr.h" +#include "arm2x86_shift.h" +#include "arm2x86_mem.h" +#include "arm2x86_mul.h" +#include "arm2x86_test.h" +#include "arm2x86_other.h" +#include "list.h" +#include "tb.h" +*/ +#define EQ 0 +#define NE 1 +#define CS 2 +#define CC 3 +#define MI 4 +#define PL 5 +#define VS 6 +#define VC 7 +#define HI 8 +#define LS 9 +#define GE 10 +#define LT 11 +#define GT 12 +#define LE 13 +#define AL 14 +#define NV 15 + +#ifndef NFLAG +#define NFLAG state->NFlag +#endif //NFLAG + +#ifndef ZFLAG +#define ZFLAG state->ZFlag +#endif //ZFLAG + +#ifndef CFLAG +#define CFLAG state->CFlag +#endif //CFLAG + +#ifndef VFLAG +#define VFLAG state->VFlag +#endif //VFLAG + +#ifndef IFLAG +#define IFLAG (state->IFFlags >> 1) +#endif //IFLAG + +#ifndef FFLAG +#define FFLAG (state->IFFlags & 1) +#endif //FFLAG + +#ifndef IFFLAGS +#define IFFLAGS state->IFFlags +#endif //VFLAG + +#define FLAG_MASK 0xf0000000 +#define NBIT_SHIFT 31 +#define ZBIT_SHIFT 30 +#define CBIT_SHIFT 29 +#define VBIT_SHIFT 28 +#ifdef DBCT +//teawater change for local tb branch directly jump 2005.10.18------------------ +#include "dbct/list.h" +#include "dbct/arm2x86.h" +#include "dbct/arm2x86_dp.h" +#include "dbct/arm2x86_movl.h" +#include "dbct/arm2x86_psr.h" +#include "dbct/arm2x86_shift.h" +#include "dbct/arm2x86_mem.h" +#include "dbct/arm2x86_mul.h" +#include "dbct/arm2x86_test.h" +#include "dbct/arm2x86_other.h" +#include "dbct/arm2x86_coproc.h" +#include "dbct/tb.h" +#endif +//AJ2D-------------------------------------------------------------------------- +//AJ2D-------------------------------------------------------------------------- +#define SKYEYE_OUTREGS(fd) { fprintf ((fd), "R %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,C %x,S %x,%x,%x,%x,%x,%x,%x,M %x,B %x,E %x,I %x,P %x,T %x,L %x,D %x,",\ + state->Reg[0],state->Reg[1],state->Reg[2],state->Reg[3], \ + state->Reg[4],state->Reg[5],state->Reg[6],state->Reg[7], \ + state->Reg[8],state->Reg[9],state->Reg[10],state->Reg[11], \ + state->Reg[12],state->Reg[13],state->Reg[14],state->Reg[15], \ + state->Cpsr, state->Spsr[0], state->Spsr[1], state->Spsr[2],\ + state->Spsr[3],state->Spsr[4], state->Spsr[5], state->Spsr[6],\ + state->Mode,state->Bank,state->ErrorCode,state->instr,state->pc,\ + state->temp,state->loaded,state->decoded);} + +#define SKYEYE_OUTMOREREGS(fd) { fprintf ((fd),"\ +RUs %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ +RF %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ +RI %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ +RS %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ +RA %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ +RUn %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",\ + state->RegBank[0][0],state->RegBank[0][1],state->RegBank[0][2],state->RegBank[0][3], \ + state->RegBank[0][4],state->RegBank[0][5],state->RegBank[0][6],state->RegBank[0][7], \ + state->RegBank[0][8],state->RegBank[0][9],state->RegBank[0][10],state->RegBank[0][11], \ + state->RegBank[0][12],state->RegBank[0][13],state->RegBank[0][14],state->RegBank[0][15], \ + state->RegBank[1][0],state->RegBank[1][1],state->RegBank[1][2],state->RegBank[1][3], \ + state->RegBank[1][4],state->RegBank[1][5],state->RegBank[1][6],state->RegBank[1][7], \ + state->RegBank[1][8],state->RegBank[1][9],state->RegBank[1][10],state->RegBank[1][11], \ + state->RegBank[1][12],state->RegBank[1][13],state->RegBank[1][14],state->RegBank[1][15], \ + state->RegBank[2][0],state->RegBank[2][1],state->RegBank[2][2],state->RegBank[2][3], \ + state->RegBank[2][4],state->RegBank[2][5],state->RegBank[2][6],state->RegBank[2][7], \ + state->RegBank[2][8],state->RegBank[2][9],state->RegBank[2][10],state->RegBank[2][11], \ + state->RegBank[2][12],state->RegBank[2][13],state->RegBank[2][14],state->RegBank[2][15], \ + state->RegBank[3][0],state->RegBank[3][1],state->RegBank[3][2],state->RegBank[3][3], \ + state->RegBank[3][4],state->RegBank[3][5],state->RegBank[3][6],state->RegBank[3][7], \ + state->RegBank[3][8],state->RegBank[3][9],state->RegBank[3][10],state->RegBank[3][11], \ + state->RegBank[3][12],state->RegBank[3][13],state->RegBank[3][14],state->RegBank[3][15], \ + state->RegBank[4][0],state->RegBank[4][1],state->RegBank[4][2],state->RegBank[4][3], \ + state->RegBank[4][4],state->RegBank[4][5],state->RegBank[4][6],state->RegBank[4][7], \ + state->RegBank[4][8],state->RegBank[4][9],state->RegBank[4][10],state->RegBank[4][11], \ + state->RegBank[4][12],state->RegBank[4][13],state->RegBank[4][14],state->RegBank[4][15], \ + state->RegBank[5][0],state->RegBank[5][1],state->RegBank[5][2],state->RegBank[5][3], \ + state->RegBank[5][4],state->RegBank[5][5],state->RegBank[5][6],state->RegBank[5][7], \ + state->RegBank[5][8],state->RegBank[5][9],state->RegBank[5][10],state->RegBank[5][11], \ + state->RegBank[5][12],state->RegBank[5][13],state->RegBank[5][14],state->RegBank[5][15] \ + );} + + +#define SA1110 0x6901b110 +#define SA1100 0x4401a100 +#define PXA250 0x69052100 +#define PXA270 0x69054110 +//#define PXA250 0x69052903 +// 0x69052903; //PXA250 B1 from intel 278522-001.pdf + + +extern void ARMul_UndefInstr (ARMul_State *, ARMword); +extern void ARMul_FixCPSR (ARMul_State *, ARMword, ARMword); +extern void ARMul_FixSPSR (ARMul_State *, ARMword, ARMword); +extern void ARMul_ConsolePrint (ARMul_State *, const char *, ...); +extern void ARMul_SelectProcessor (ARMul_State *, unsigned); + +#define DIFF_LOG 0 +#define SAVE_LOG 0 + +#endif /* _ARMDEFS_H_ */ diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp new file mode 100644 index 00000000..46c51fbe --- /dev/null +++ b/src/core/arm/interpreter/armemu.cpp @@ -0,0 +1,6631 @@ +/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator. + Copyright (C) 1994 Advanced RISC Machines Ltd. + Modifications to add arch. v4 support by . + + 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 "arm_regformat.h" +#include "armdefs.h" +#include "armemu.h" +#include "armos.h" + +void +XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword _far) +{ + _dbg_assert_msg_(ARM11, false, "ImplementMe: XScale_set_fsr_far!"); + //if (!state->is_XScale || (read_cp14_reg(10) & (1UL << 31)) == 0) + // return; + // + //write_cp15_reg(state, 5, 0, 0, fsr); + //write_cp15_reg(state, 6, 0, 0, _far); +} + +#define ARMul_Debug(x,y,z) 0 // Disabling this /bunnei + +//#include "skyeye_callback.h" +//#include "skyeye_bus.h" +//#include "sim_control.h" +//#include "skyeye_pref.h" +//#include "skyeye.h" +//#include "skyeye2gdb.h" +//#include "code_cov.h" + +//#include "iwmmxt.h" +//chy 2003-07-11: for debug instrs +//extern int skyeye_instr_debug; +extern FILE *skyeye_logfd; + +static ARMword GetDPRegRHS (ARMul_State *, ARMword); +static ARMword GetDPSRegRHS (ARMul_State *, ARMword); +static void WriteR15 (ARMul_State *, ARMword); +static void WriteSR15 (ARMul_State *, ARMword); +static void WriteR15Branch (ARMul_State *, ARMword); +static ARMword GetLSRegRHS (ARMul_State *, ARMword); +static ARMword GetLS7RHS (ARMul_State *, ARMword); +static unsigned LoadWord (ARMul_State *, ARMword, ARMword); +static unsigned LoadHalfWord (ARMul_State *, ARMword, ARMword, int); +static unsigned LoadByte (ARMul_State *, ARMword, ARMword, int); +static unsigned StoreWord (ARMul_State *, ARMword, ARMword); +static unsigned StoreHalfWord (ARMul_State *, ARMword, ARMword); +static unsigned StoreByte (ARMul_State *, ARMword, ARMword); +static void LoadMult (ARMul_State *, ARMword, ARMword, ARMword); +static void StoreMult (ARMul_State *, ARMword, ARMword, ARMword); +static void LoadSMult (ARMul_State *, ARMword, ARMword, ARMword); +static void StoreSMult (ARMul_State *, ARMword, ARMword, ARMword); +static unsigned Multiply64 (ARMul_State *, ARMword, int, int); +static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); +static void Handle_Load_Double (ARMul_State *, ARMword); +static void Handle_Store_Double (ARMul_State *, ARMword); +void +XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far); +int +XScale_debug_moe (ARMul_State * state, int moe); +unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum); + +static int +handle_v6_insn (ARMul_State * state, ARMword instr); + +#define LUNSIGNED (0) /* unsigned operation */ +#define LSIGNED (1) /* signed operation */ +#define LDEFAULT (0) /* default : do nothing */ +#define LSCC (1) /* set condition codes on result */ + +#ifdef NEED_UI_LOOP_HOOK +/* How often to run the ui_loop update, when in use. */ +#define UI_LOOP_POLL_INTERVAL 0x32000 + +/* Counter for the ui_loop_hook update. */ +static int ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; + +/* Actual hook to call to run through gdb's gui event loop. */ +extern int (*ui_loop_hook) (int); +#endif /* NEED_UI_LOOP_HOOK */ + +/* Short-hand macros for LDR/STR. */ + +/* Store post decrement writeback. */ +#define SHDOWNWB() \ + lhs = LHS ; \ + if (StoreHalfWord (state, instr, lhs)) \ + LSBase = lhs - GetLS7RHS (state, instr); + +/* Store post increment writeback. */ +#define SHUPWB() \ + lhs = LHS ; \ + if (StoreHalfWord (state, instr, lhs)) \ + LSBase = lhs + GetLS7RHS (state, instr); + +/* Store pre decrement. */ +#define SHPREDOWN() \ + (void)StoreHalfWord (state, instr, LHS - GetLS7RHS (state, instr)); + +/* Store pre decrement writeback. */ +#define SHPREDOWNWB() \ + temp = LHS - GetLS7RHS (state, instr); \ + if (StoreHalfWord (state, instr, temp)) \ + LSBase = temp; + +/* Store pre increment. */ +#define SHPREUP() \ + (void)StoreHalfWord (state, instr, LHS + GetLS7RHS (state, instr)); + +/* Store pre increment writeback. */ +#define SHPREUPWB() \ + temp = LHS + GetLS7RHS (state, instr); \ + if (StoreHalfWord (state, instr, temp)) \ + LSBase = temp; + +/* Load post decrement writeback. */ +#define LHPOSTDOWN() \ +{ \ + int done = 1; \ + lhs = LHS; \ + temp = lhs - GetLS7RHS (state, instr); \ + \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ + LSBase = temp; \ + break; \ + case 2: /* SB */ \ + if (LoadByte (state, instr, lhs, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 3: /* SH */ \ + if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 0: /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/* Load post increment writeback. */ +#define LHPOSTUP() \ +{ \ + int done = 1; \ + lhs = LHS; \ + temp = lhs + GetLS7RHS (state, instr); \ + \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ + LSBase = temp; \ + break; \ + case 2: /* SB */ \ + if (LoadByte (state, instr, lhs, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 3: /* SH */ \ + if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 0: /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/* Load pre decrement. */ +#define LHPREDOWN() \ +{ \ + int done = 1; \ + \ + temp = LHS - GetLS7RHS (state, instr); \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ + break; \ + case 2: /* SB */ \ + (void) LoadByte (state, instr, temp, LSIGNED); \ + break; \ + case 3: /* SH */ \ + (void) LoadHalfWord (state, instr, temp, LSIGNED); \ + break; \ + case 0: \ + /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/* Load pre decrement writeback. */ +#define LHPREDOWNWB() \ +{ \ + int done = 1; \ + \ + temp = LHS - GetLS7RHS (state, instr); \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ + LSBase = temp; \ + break; \ + case 2: /* SB */ \ + if (LoadByte (state, instr, temp, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 3: /* SH */ \ + if (LoadHalfWord (state, instr, temp, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 0: \ + /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/* Load pre increment. */ +#define LHPREUP() \ +{ \ + int done = 1; \ + \ + temp = LHS + GetLS7RHS (state, instr); \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ + break; \ + case 2: /* SB */ \ + (void) LoadByte (state, instr, temp, LSIGNED); \ + break; \ + case 3: /* SH */ \ + (void) LoadHalfWord (state, instr, temp, LSIGNED); \ + break; \ + case 0: \ + /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/* Load pre increment writeback. */ +#define LHPREUPWB() \ +{ \ + int done = 1; \ + \ + temp = LHS + GetLS7RHS (state, instr); \ + switch (BITS (5, 6)) \ + { \ + case 1: /* H */ \ + if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ + LSBase = temp; \ + break; \ + case 2: /* SB */ \ + if (LoadByte (state, instr, temp, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 3: /* SH */ \ + if (LoadHalfWord (state, instr, temp, LSIGNED)) \ + LSBase = temp; \ + break; \ + case 0: \ + /* SWP handled elsewhere. */ \ + default: \ + done = 0; \ + break; \ + } \ + if (done) \ + break; \ +} + +/*ywc 2005-03-31*/ +//teawater add for arm2x86 2005.02.17------------------------------------------- +#ifdef DBCT +#include "dbct/tb.h" +#include "dbct/arm2x86_self.h" +#endif +//AJ2D-------------------------------------------------------------------------- + +//Diff register +unsigned int mirror_register_file[39]; + +/* EMULATION of ARM6. */ + +/* The PC pipeline value depends on whether ARM + or Thumb instructions are being executed. */ +ARMword isize; + +extern int debugmode; +int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr); +#ifdef MODE32 +//chy 2006-04-12, for ICE debug +int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr) +{ + int i; +#if 0 + if (debugmode) { + if (instr == ARMul_ABORTWORD) return 0; + for (i = 0; i < skyeye_ice.num_bps; i++) { + if (skyeye_ice.bps[i] == addr) { + //for test + //printf("SKYEYE: ICE_debug bps [%d]== 0x%x\n", i,addr); + state->EndCondition = 0; + state->Emulate = STOP; + return 1; + } + } + if (skyeye_ice.tps_status==TRACE_STARTED) + { + for (i = 0; i < skyeye_ice.num_tps; i++) + { + if (((skyeye_ice.tps[i].tp_address==addr)&&(skyeye_ice.tps[i].status==TRACEPOINT_ENABLED))||(skyeye_ice.tps[i].status==TRACEPOINT_STEPPING)) + { + handle_tracepoint(i); + } + } + } + } + /* do profiling for code coverage */ + if (skyeye_config.code_cov.prof_on) + cov_prof(EXEC_FLAG, addr); +#endif + /* chech if we need to run some callback functions at this time */ + //generic_arch_t* arch_instance = get_arch_instance(""); + //exec_callback(Step_callback, arch_instance); + //if (!SIM_is_running()) { + // if (instr == ARMul_ABORTWORD) return 0; + // state->EndCondition = 0; + // state->Emulate = STOP; + // return 1; + //} + return 0; +} + +/* +void chy_debug() +{ + printf("SkyEye chy_deubeg begin\n"); +} +*/ +ARMword +ARMul_Emulate32 (ARMul_State * state) +#else +ARMword +ARMul_Emulate26 (ARMul_State * state) +#endif +{ + ARMword instr; /* The current instruction. */ + ARMword dest = 0; /* Almost the DestBus. */ + ARMword temp; /* Ubiquitous third hand. */ + ARMword pc = 0; /* The address of the current instruction. */ + ARMword lhs; /* Almost the ABus and BBus. */ + ARMword rhs; + ARMword decoded = 0; /* Instruction pipeline. */ + ARMword loaded = 0; + ARMword decoded_addr=0; + ARMword loaded_addr=0; + ARMword have_bp=0; + + /* shenoubang */ + static int instr_sum = 0; + int reg_index = 0; +#if DIFF_STATE +//initialize all mirror register for follow mode + for (reg_index = 0; reg_index < 16; reg_index ++) { + mirror_register_file[reg_index] = state->Reg[reg_index]; + } + mirror_register_file[CPSR_REG] = state->Cpsr; + mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; + mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; + mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; + mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; + mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; + mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; + mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; + mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; + mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; + mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; + mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; + mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; + mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; + mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; + mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; + mirror_register_file[SPSR_SVC] = state->Spsr[SVCBANK]; + mirror_register_file[SPSR_ABORT] = state->Spsr[ABORTBANK]; + mirror_register_file[SPSR_UNDEF] = state->Spsr[UNDEFBANK]; + mirror_register_file[SPSR_IRQ] = state->Spsr[IRQBANK]; + mirror_register_file[SPSR_FIRQ] = state->Spsr[FIQBANK]; +#endif + /* Execute the next instruction. */ + if (state->NextInstr < PRIMEPIPE) { + decoded = state->decoded; + loaded = state->loaded; + pc = state->pc; + //chy 2006-04-12, for ICE debug + decoded_addr=state->decoded_addr; + loaded_addr=state->loaded_addr; + } + + do { + //print_func_name(state->pc); + /* Just keep going. */ + isize = INSN_SIZE; + + switch (state->NextInstr) { + case SEQ: + /* Advance the pipeline, and an S cycle. */ + state->Reg[15] += isize; + pc += isize; + instr = decoded; + //chy 2006-04-12, for ICE debug + have_bp = ARMul_ICE_debug(state,instr,decoded_addr); + decoded = loaded; + decoded_addr=loaded_addr; + //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), + // isize); + loaded_addr=pc + (isize * 2); + if (have_bp) goto TEST_EMULATE; + break; + + case NONSEQ: + /* Advance the pipeline, and an N cycle. */ + state->Reg[15] += isize; + pc += isize; + instr = decoded; + //chy 2006-04-12, for ICE debug + have_bp=ARMul_ICE_debug(state,instr,decoded_addr); + decoded = loaded; + decoded_addr=loaded_addr; + //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), + // isize); + loaded_addr=pc + (isize * 2); + NORMALCYCLE; + if (have_bp) goto TEST_EMULATE; + break; + + case PCINCEDSEQ: + /* Program counter advanced, and an S cycle. */ + pc += isize; + instr = decoded; + //chy 2006-04-12, for ICE debug + have_bp=ARMul_ICE_debug(state,instr,decoded_addr); + decoded = loaded; + decoded_addr=loaded_addr; + //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), + // isize); + loaded_addr=pc + (isize * 2); + NORMALCYCLE; + if (have_bp) goto TEST_EMULATE; + break; + + case PCINCEDNONSEQ: + /* Program counter advanced, and an N cycle. */ + pc += isize; + instr = decoded; + //chy 2006-04-12, for ICE debug + have_bp=ARMul_ICE_debug(state,instr,decoded_addr); + decoded = loaded; + decoded_addr=loaded_addr; + //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), + // isize); + loaded_addr=pc + (isize * 2); + NORMALCYCLE; + if (have_bp) goto TEST_EMULATE; + break; + + case RESUME: + /* The program counter has been changed. */ + pc = state->Reg[15]; +#ifndef MODE32 + pc = pc & R15PCBITS; +#endif + state->Reg[15] = pc + (isize * 2); + state->Aborted = 0; + //chy 2004-05-25, fix bug provided by Carl van Schaik + state->AbortAddr = 1; + + instr = ARMul_LoadInstrN (state, pc, isize); + //instr = ARMul_ReLoadInstr (state, pc, isize); + //chy 2006-04-12, for ICE debug + have_bp=ARMul_ICE_debug(state,instr,pc); + //decoded = + // ARMul_ReLoadInstr (state, pc + isize, isize); + decoded_addr=pc+isize; + //loaded = ARMul_ReLoadInstr (state, pc + isize * 2, + // isize); + loaded_addr=pc + isize * 2; + NORMALCYCLE; + if (have_bp) goto TEST_EMULATE; + break; + + default: + /* The program counter has been changed. */ + pc = state->Reg[15]; +#ifndef MODE32 + pc = pc & R15PCBITS; +#endif + state->Reg[15] = pc + (isize * 2); + state->Aborted = 0; + //chy 2004-05-25, fix bug provided by Carl van Schaik + state->AbortAddr = 1; + + instr = ARMul_LoadInstrN (state, pc, isize); + //chy 2006-04-12, for ICE debug + have_bp=ARMul_ICE_debug(state,instr,pc); + #if 0 + decoded = + ARMul_LoadInstrS (state, pc + (isize), isize); + #endif + decoded_addr=pc+isize; + #if 0 + loaded = ARMul_LoadInstrS (state, pc + (isize * 2), + isize); + #endif + loaded_addr=pc + isize * 2; + NORMALCYCLE; + if (have_bp) goto TEST_EMULATE; + break; + } +#if 0 + int idx = 0; + printf("pc:%x\n", pc); + for (;idx < 17; idx ++) { + printf("R%d:%x\t", idx, state->Reg[idx]); + } + printf("\n"); +#endif + instr = ARMul_LoadInstrN (state, pc, isize); + state->last_instr = state->CurrInstr; + state->CurrInstr = instr; +#if 0 + if((state->NumInstrs % 10000000) == 0) + printf("---|%p|--- %lld\n", pc, state->NumInstrs); + if(state->NumInstrs > (3000000000)){ + static int flag = 0; + if(pc == 0x8032ccc4){ + flag = 300; + } + if(flag){ + int idx = 0; + printf("------------------------------------\n"); + printf("pc:%x\n", pc); + for (;idx < 17; idx ++) { + printf("R%d:%x\t", idx, state->Reg[idx]); + } + printf("\nN:%d\t Z:%d\t C:%d\t V:%d\n", state->NFlag, state->ZFlag, state->CFlag, state->VFlag); + printf("\n"); + printf("------------------------------------\n"); + flag--; + } + } +#endif +#if DIFF_STATE + fprintf(state->state_log, "PC:0x%x\n", pc); + if (pc && (pc + 8) != state->Reg[15]) { + printf("lucky dog\n"); + printf("pc is %x, R15 is %x\n", pc, state->Reg[15]); + //exit(-1); + } + for (reg_index = 0; reg_index < 16; reg_index ++) { + if (state->Reg[reg_index] != mirror_register_file[reg_index]) { + fprintf(state->state_log, "R%d:0x%x\n", reg_index, state->Reg[reg_index]); + mirror_register_file[reg_index] = state->Reg[reg_index]; + } + } + if (state->Cpsr != mirror_register_file[CPSR_REG]) { + fprintf(state->state_log, "Cpsr:0x%x\n", state->Cpsr); + mirror_register_file[CPSR_REG] = state->Cpsr; + } + if (state->RegBank[SVCBANK][13] != mirror_register_file[R13_SVC]) { + fprintf(state->state_log, "R13_SVC:0x%x\n", state->RegBank[SVCBANK][13]); + mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; + } + if (state->RegBank[SVCBANK][14] != mirror_register_file[R14_SVC]) { + fprintf(state->state_log, "R14_SVC:0x%x\n", state->RegBank[SVCBANK][14]); + mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; + } + if (state->RegBank[ABORTBANK][13] != mirror_register_file[R13_ABORT]) { + fprintf(state->state_log, "R13_ABORT:0x%x\n", state->RegBank[ABORTBANK][13]); + mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; + } + if (state->RegBank[ABORTBANK][14] != mirror_register_file[R14_ABORT]) { + fprintf(state->state_log, "R14_ABORT:0x%x\n", state->RegBank[ABORTBANK][14]); + mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; + } + if (state->RegBank[UNDEFBANK][13] != mirror_register_file[R13_UNDEF]) { + fprintf(state->state_log, "R13_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][13]); + mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; + } + if (state->RegBank[UNDEFBANK][14] != mirror_register_file[R14_UNDEF]) { + fprintf(state->state_log, "R14_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][14]); + mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; + } + if (state->RegBank[IRQBANK][13] != mirror_register_file[R13_IRQ]) { + fprintf(state->state_log, "R13_IRQ:0x%x\n", state->RegBank[IRQBANK][13]); + mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; + } + if (state->RegBank[IRQBANK][14] != mirror_register_file[R14_IRQ]) { + fprintf(state->state_log, "R14_IRQ:0x%x\n", state->RegBank[IRQBANK][14]); + mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; + } + if (state->RegBank[FIQBANK][8] != mirror_register_file[R8_FIRQ]) { + fprintf(state->state_log, "R8_FIRQ:0x%x\n", state->RegBank[FIQBANK][8]); + mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; + } + if (state->RegBank[FIQBANK][9] != mirror_register_file[R9_FIRQ]) { + fprintf(state->state_log, "R9_FIRQ:0x%x\n", state->RegBank[FIQBANK][9]); + mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; + } + if (state->RegBank[FIQBANK][10] != mirror_register_file[R10_FIRQ]) { + fprintf(state->state_log, "R10_FIRQ:0x%x\n", state->RegBank[FIQBANK][10]); + mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; + } + if (state->RegBank[FIQBANK][11] != mirror_register_file[R11_FIRQ]) { + fprintf(state->state_log, "R11_FIRQ:0x%x\n", state->RegBank[FIQBANK][11]); + mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; + } + if (state->RegBank[FIQBANK][12] != mirror_register_file[R12_FIRQ]) { + fprintf(state->state_log, "R12_FIRQ:0x%x\n", state->RegBank[FIQBANK][12]); + mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; + } + if (state->RegBank[FIQBANK][13] != mirror_register_file[R13_FIRQ]) { + fprintf(state->state_log, "R13_FIRQ:0x%x\n", state->RegBank[FIQBANK][13]); + mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; + } + if (state->RegBank[FIQBANK][14] != mirror_register_file[R14_FIRQ]) { + fprintf(state->state_log, "R14_FIRQ:0x%x\n", state->RegBank[FIQBANK][14]); + mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; + } + if (state->Spsr[SVCBANK] != mirror_register_file[SPSR_SVC]) { + fprintf(state->state_log, "SPSR_SVC:0x%x\n", state->Spsr[SVCBANK]); + mirror_register_file[SPSR_SVC] = state->RegBank[SVCBANK]; + } + if (state->Spsr[ABORTBANK] != mirror_register_file[SPSR_ABORT]) { + fprintf(state->state_log, "SPSR_ABORT:0x%x\n", state->Spsr[ABORTBANK]); + mirror_register_file[SPSR_ABORT] = state->RegBank[ABORTBANK]; + } + if (state->Spsr[UNDEFBANK] != mirror_register_file[SPSR_UNDEF]) { + fprintf(state->state_log, "SPSR_UNDEF:0x%x\n", state->Spsr[UNDEFBANK]); + mirror_register_file[SPSR_UNDEF] = state->RegBank[UNDEFBANK]; + } + if (state->Spsr[IRQBANK] != mirror_register_file[SPSR_IRQ]) { + fprintf(state->state_log, "SPSR_IRQ:0x%x\n", state->Spsr[IRQBANK]); + mirror_register_file[SPSR_IRQ] = state->RegBank[IRQBANK]; + } + if (state->Spsr[FIQBANK] != mirror_register_file[SPSR_FIRQ]) { + fprintf(state->state_log, "SPSR_FIRQ:0x%x\n", state->Spsr[FIQBANK]); + mirror_register_file[SPSR_FIRQ] = state->RegBank[FIQBANK]; + } +#endif + +#if 0 + uint32_t alex = 0; + static int flagged = 0; + if ((flagged == 0) && (pc == 0xb224)) + { + flagged++; + } + if ((flagged == 1) && (pc == 0x1a800)) + { + flagged++; + } + if (flagged == 3) { + printf("---|%p|--- %x\n", pc, state->NumInstrs); + for (alex = 0; alex < 15; alex++) + { + printf("R%02d % 8x\n", alex, state->Reg[alex]); + } + printf("R%02d % 8x\n", alex, state->Reg[alex] - 8); + printf("CPS %x%07x\n", (state->NFlag<<3 | state->ZFlag<<2 | state->CFlag<<1 | state->VFlag), state->Cpsr & 0xfffffff); + } else { + if (state->NumInstrs < 0x400000) + { + //exit(-1); + } + } +#endif + + if (state->EventSet) + ARMul_EnvokeEvent (state); + +#if 0 + /* do profiling for code coverage */ + if (skyeye_config.code_cov.prof_on) + cov_prof(EXEC_FLAG, pc); +#endif +//2003-07-11 chy: for test +#if 0 + if (skyeye_config.log.logon >= 1) { + if (state->NumInstrs >= skyeye_config.log.start && + state->NumInstrs <= skyeye_config.log.end) { + static int mybegin = 0; + static int myinstrnum = 0; + if (mybegin == 0) + mybegin = 1; +#if 0 + if (state->NumInstrs == 3695) { + printf ("***********SKYEYE: numinstr = 3695\n"); + } + static int mybeg2 = 0; + static int mybeg3 = 0; + static int mybeg4 = 0; + static int mybeg5 = 0; + + if (pc == 0xa0008000) { + //mybegin=1; + printf ("************SKYEYE: real vmlinux begin now numinstr is %llu ****************\n", state->NumInstrs); + } + + //chy 2003-09-02 test fiq + if (state->NumInstrs == 67347000) { + printf ("***********SKYEYE: numinstr = 67347000, begin log\n"); + mybegin = 1; + } + if (pc == 0xc00087b4) { //numinstr=67348714 + mybegin = 1; + printf ("************SKYEYE: test irq now numinstr is %llu ****************\n", state->NumInstrs); + } + if (pc == 0xc00087b8) { //in start_kernel::sti() + mybeg4 = 1; + printf ("************SKYEYE: startkerenl: sti now numinstr is %llu ********\n", state->NumInstrs); + } + /*if (pc==0xc001e4f4||pc==0xc001e4f8||pc==0xc001e4fc||pc==0xc001e500||pc==0xffff0004) { //MRA instr */ + if (pc == 0xc001e500) { //MRA instr + mybeg5 = 1; + printf ("************SKYEYE: MRA instr now numinstr is %llu ********\n", state->NumInstrs); + } + if (pc >= 0xc0000000 && mybeg2 == 0) { + mybeg2 = 1; + printf ("************SKYEYE: enable mmu&cache, now numinstr is %llu **************\n", state->NumInstrs); + SKYEYE_OUTREGS (stderr); + printf ("************************************************************************\n"); + } + //chy 2003-09-01 test after tlb-flush + if (pc == 0xc00261ac) { + //sleep(2); + mybeg3 = 1; + printf ("************SKYEYE: after tlb-flush numinstr is %llu ****************\n", state->NumInstrs); + } + if (mybeg3 == 1) { + SKYEYE_OUTREGS (skyeye_logfd); + SKYEYE_OUTMOREREGS (skyeye_logfd); + fprintf (skyeye_logfd, "\n"); + } +#endif + if (mybegin == 1) { + //fprintf(skyeye_logfd,"p %x,i %x,d %x,l %x,",pc,instr,decoded,loaded); + //chy for test 20050729 + /*if (state->NumInstrs>=3302294) { + if (pc==0x100c9d4 && instr==0xe1b0f00e){ + chy_debug(); + printf("*********************************************\n"); + printf("******SKYEYE N %llx :p %x,i %x\n SKYEYE******\n",state->NumInstrs,pc,instr); + printf("*********************************************\n"); + } + */ + if (skyeye_config.log.logon >= 1) + /* + fprintf (skyeye_logfd, + "N %llx :p %x,i %x,", + state->NumInstrs, pc, +#ifdef MODET + TFLAG ? instr & 0xffff : instr +#else + instr +#endif + ); + */ + fprintf(skyeye_logfd, "pc=0x%x,r3=0x%x\n", pc, state->Reg[3]); + if (skyeye_config.log.logon >= 2) + SKYEYE_OUTREGS (skyeye_logfd); + if (skyeye_config.log.logon >= 3) + SKYEYE_OUTMOREREGS + (skyeye_logfd); + //fprintf (skyeye_logfd, "\n"); + if (skyeye_config.log.length > 0) { + myinstrnum++; + if (myinstrnum >= + skyeye_config.log. + length) { + myinstrnum = 0; + fflush (skyeye_logfd); + fseek (skyeye_logfd, + 0L, SEEK_SET); + } + } + } + //SKYEYE_OUTREGS(skyeye_logfd); + //SKYEYE_OUTMOREREGS(skyeye_logfd); + } + } +#endif +#if 0 /* Enable this for a helpful bit of debugging when tracing is needed. */ + fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr); + if (instr == 0) + abort (); +#endif +#if 0 /* Enable this code to help track down stack alignment bugs. */ + { + static ARMword old_sp = -1; + + if (old_sp != state->Reg[13]) { + old_sp = state->Reg[13]; + fprintf (stderr, + "pc: %08x: SP set to %08x%s\n", + pc & ~1, old_sp, + (old_sp % 8) ? " [UNALIGNED!]" : ""); + } + } +#endif + /* Any exceptions ? */ + if (state->NresetSig == LOW) { + ARMul_Abort (state, ARMul_ResetV); + + /*added energy_prof statement by ksh in 2004-11-26 */ + //chy 2005-07-28 for standalone + //ARMul_do_energy(state,instr,pc); + break; + } + else if (!state->NfiqSig && !FFLAG) { + ARMul_Abort (state, ARMul_FIQV); + /*added energy_prof statement by ksh in 2004-11-26 */ + //chy 2005-07-28 for standalone + //ARMul_do_energy(state,instr,pc); + break; + } + else if (!state->NirqSig && !IFLAG) { + ARMul_Abort (state, ARMul_IRQV); + /*added energy_prof statement by ksh in 2004-11-26 */ + //chy 2005-07-28 for standalone + //ARMul_do_energy(state,instr,pc); + break; + } + +//teawater add for arm2x86 2005.04.26------------------------------------------- +#if 0 +// if (state->pc == 0xc011a868 || state->pc == 0xc011a86c) { + if (state->NumInstrs == 1671574 || state->NumInstrs == 1671573 || state->NumInstrs == 1671572 + || state->NumInstrs == 1671575) { + for (reg_index = 0; reg_index < 16; reg_index ++) { + printf("R%d:%x\t", reg_index, state->Reg[reg_index]); + } + printf("\n"); + } +#endif + if (state->tea_pc) { + int i; + + if (state->tea_reg_fd) { + fprintf (state->tea_reg_fd, "\n"); + for (i = 0; i < 15; i++) { + fprintf (state->tea_reg_fd, "%x,", + state->Reg[i]); + } + fprintf (state->tea_reg_fd, "%x,", pc); + state->Cpsr = ARMul_GetCPSR (state); + fprintf (state->tea_reg_fd, "%x\n", + state->Cpsr); + } + else { + printf ("\n"); + for (i = 0; i < 15; i++) { + printf ("%x,", state->Reg[i]); + } + printf ("%x,", pc); + state->Cpsr = ARMul_GetCPSR (state); + printf ("%x\n", state->Cpsr); + } + } +//AJ2D-------------------------------------------------------------------------- + + if (state->CallDebug > 0) { + instr = ARMul_Debug (state, pc, instr); + if (state->Emulate < ONCE) { + state->NextInstr = RESUME; + break; + } + if (state->Debug) { + fprintf (stderr, + "sim: At %08lx Instr %08lx Mode %02lx\n", + pc, instr, state->Mode); + (void) fgetc (stdin); + } + } + else if (state->Emulate < ONCE) { + state->NextInstr = RESUME; + break; + } + //io_do_cycle (state); + state->NumInstrs++; + #if 0 + if (state->NumInstrs % 10000000 == 0) { + printf("10 MIPS instr have been executed\n"); + } + #endif + +#ifdef MODET + /* Provide Thumb instruction decoding. If the processor is in Thumb + mode, then we can simply decode the Thumb instruction, and map it + to the corresponding ARM instruction (by directly loading the + instr variable, and letting the normal ARM simulator + execute). There are some caveats to ensure that the correct + pipelined PC value is used when executing Thumb code, and also for + dealing with the BL instruction. */ + if (TFLAG) { + ARMword new_instr; + + /* Check if in Thumb mode. */ + switch (ARMul_ThumbDecode(state, pc, instr, &new_instr)) { + case t_undefined: + /* This is a Thumb instruction. */ + ARMul_UndefInstr (state, instr); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + + case t_branch: + /* Already processed. */ + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + + case t_decoded: + /* ARM instruction available. */ + //printf("t decode %04lx -> %08lx\n", instr & 0xffff, new); + instr = new_instr; + /* So continue instruction decoding. */ + break; + default: + break; + } + } +#endif + + /* Check the condition codes. */ + if ((temp = TOPBITS (28)) == AL) { + /* Vile deed in the need for speed. */ + goto mainswitch; + } + + /* Check the condition code. */ + switch ((int) TOPBITS (28)) { + case AL: + temp = TRUE; + break; + case NV: + + /* shenoubang add for armv7 instr dmb 2012-3-11 */ + if (state->is_v7) { + if ((instr & 0x0fffff00) == 0x057ff000) { + switch((instr >> 4) & 0xf) { + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + // TODO: do no implemented thes instr + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + } + } + /* dyf add for armv6 instruct CPS 2010.9.17 */ + if (state->is_v6) { + /* clrex do nothing here temporary */ + if (instr == 0xf57ff01f) { + //printf("clrex \n"); + ERROR_LOG(ARM11, "Instr = 0x%x, pc = 0x%x, clrex instr!!\n", instr, pc); +#if 0 + int i; + for(i = 0; i < 128; i++){ + state->exclusive_tag_array[i] = 0xffffffff; + } +#endif + /* shenoubang 2012-3-14 refer the dyncom_interpreter */ + state->exclusive_tag_array[0] = 0xFFFFFFFF; + state->exclusive_access_state = 0; + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + + if (BITS(20, 27) == 0x10) { + if (BIT(19)) { + if (BIT(8)) { + if (BIT(18)) + state->Cpsr |= 1<<8; + else + state->Cpsr &= ~(1<<8); + } + if (BIT(7)) { + if (BIT(18)) + state->Cpsr |= 1<<7; + else + state->Cpsr &= ~(1<<7); + ASSIGNINT (state->Cpsr & INTBITS); + } + if (BIT(6)) { + if (BIT(18)) + state->Cpsr |= 1<<6; + else + state->Cpsr &= ~(1<<6); + ASSIGNINT (state->Cpsr & INTBITS); + } + } + if (BIT(17)) { + state->Cpsr |= BITS(0, 4); + printf("skyeye test state->Mode\n"); + if (state->Mode != (state->Cpsr & MODEBITS)) { + state->Mode = + ARMul_SwitchMode (state, state->Mode, + state->Cpsr & MODEBITS); + + state->NtransSig = (state->Mode & 3) ? HIGH : LOW; + } + } + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + } + if (state->is_v5) { + if (BITS (25, 27) == 5) { /* BLX(1) */ + ARMword dest; + + state->Reg[14] = pc + 4; + + /* Force entry into Thumb mode. */ + dest = pc + 8 + 1; + if (BIT (23)) + dest += (NEGBRANCH + + (BIT (24) << 1)); + else + dest += POSBRANCH + + (BIT (24) << 1); + + WriteR15Branch (state, dest); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + else if ((instr & 0xFC70F000) == 0xF450F000) { + /* The PLD instruction. Ignored. */ + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + else if (((instr & 0xfe500f00) == 0xfc100100) + || ((instr & 0xfe500f00) == + 0xfc000100)) { + /* wldrw and wstrw are unconditional. */ + goto mainswitch; + } + else { + /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2. */ + ARMul_UndefInstr (state, instr); + } + } + temp = FALSE; + break; + case EQ: + temp = ZFLAG; + break; + case NE: + temp = !ZFLAG; + break; + case VS: + temp = VFLAG; + break; + case VC: + temp = !VFLAG; + break; + case MI: + temp = NFLAG; + break; + case PL: + temp = !NFLAG; + break; + case CS: + temp = CFLAG; + break; + case CC: + temp = !CFLAG; + break; + case HI: + temp = (CFLAG && !ZFLAG); + break; + case LS: + temp = (!CFLAG || ZFLAG); + break; + case GE: + temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); + break; + case LT: + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); + break; + case GT: + temp = ((!NFLAG && !VFLAG && !ZFLAG) + || (NFLAG && VFLAG && !ZFLAG)); + break; + case LE: + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) + || ZFLAG; + break; + } /* cc check */ + +//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... +#if 0 + /* Handle the Clock counter here. */ + if (state->is_XScale) { + ARMword cp14r0; + int ok; + + ok = state->CPRead[14] (state, 0, &cp14r0); + + if (ok && (cp14r0 & ARMul_CP14_R0_ENABLE)) { + unsigned int newcycles, nowtime = + ARMul_Time (state); + + newcycles = nowtime - state->LastTime; + state->LastTime = nowtime; + + if (cp14r0 & ARMul_CP14_R0_CCD) { + if (state->CP14R0_CCD == -1) + state->CP14R0_CCD = newcycles; + else + state->CP14R0_CCD += + newcycles; + + if (state->CP14R0_CCD >= 64) { + newcycles = 0; + + while (state->CP14R0_CCD >= + 64) + state->CP14R0_CCD -= + 64, + newcycles++; + + goto check_PMUintr; + } + } + else { + ARMword cp14r1; + int do_int = 0; + + state->CP14R0_CCD = -1; + check_PMUintr: + cp14r0 |= ARMul_CP14_R0_FLAG2; + (void) state->CPWrite[14] (state, 0, + cp14r0); + + ok = state->CPRead[14] (state, 1, + &cp14r1); + + /* Coded like this for portability. */ + while (ok && newcycles) { + if (cp14r1 == 0xffffffff) { + cp14r1 = 0; + do_int = 1; + } + else + cp14r1++; + + newcycles--; + } + + (void) state->CPWrite[14] (state, 1, + cp14r1); + + if (do_int + && (cp14r0 & + ARMul_CP14_R0_INTEN2)) { + ARMword temp; + + if (state-> + CPRead[13] (state, 8, + &temp) + && (temp & + ARMul_CP13_R8_PMUS)) + ARMul_Abort (state, + ARMul_FIQV); + else + ARMul_Abort (state, + ARMul_IRQV); + } + } + } + } + + /* Handle hardware instructions breakpoints here. */ + if (state->is_XScale) { + if ((pc | 3) == (read_cp15_reg (14, 0, 8) | 2) + || (pc | 3) == (read_cp15_reg (14, 0, 9) | 2)) { + if (XScale_debug_moe + (state, ARMul_CP14_R10_MOE_IB)) + ARMul_OSHandleSWI (state, + SWI_Breakpoint); + } + } +#endif + + /* Actual execution of instructions begins here. */ + /* If the condition codes don't match, stop here. */ + if (temp) { + mainswitch: + + if (state->is_XScale) { + if (BIT (20) == 0 && BITS (25, 27) == 0) { + if (BITS (4, 7) == 0xD) { + /* XScale Load Consecutive insn. */ + ARMword temp = + GetLS7RHS (state, + instr); + ARMword temp2 = + BIT (23) ? LHS + + temp : LHS - temp; + ARMword addr = + BIT (24) ? temp2 : + LHS; + + if (BIT (12)) + ARMul_UndefInstr + (state, + instr); + else if (addr & 7) + /* Alignment violation. */ + ARMul_Abort (state, + ARMul_DataAbortV); + else { + int wb = BIT (21) + || + (!BIT (24)); + + state->Reg[BITS + (12, 15)] = + ARMul_LoadWordN + (state, addr); + state->Reg[BITS + (12, + 15) + 1] = + ARMul_LoadWordN + (state, + addr + 4); + if (wb) + LSBase = temp2; + } + + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + else if (BITS (4, 7) == 0xF) { + /* XScale Store Consecutive insn. */ + ARMword temp = + GetLS7RHS (state, + instr); + ARMword temp2 = + BIT (23) ? LHS + + temp : LHS - temp; + ARMword addr = + BIT (24) ? temp2 : + LHS; + + if (BIT (12)) + ARMul_UndefInstr + (state, + instr); + else if (addr & 7) + /* Alignment violation. */ + ARMul_Abort (state, + ARMul_DataAbortV); + else { + ARMul_StoreWordN + (state, addr, + state-> + Reg[BITS + (12, + 15)]); + ARMul_StoreWordN + (state, + addr + 4, + state-> + Reg[BITS + (12, + 15) + + 1]); + + if (BIT (21) + || !BIT (24)) + LSBase = temp2; + } + + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + } + //chy 2003-09-03 TMRRC(iwmmxt.c) and MRA has the same decoded instr???? + //Now, I commit iwmmxt process, may be future, I will change it!!!! + //if (ARMul_HandleIwmmxt (state, instr)) + // _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + + /* shenoubang sbfx and ubfx instr 2012-3-16 */ + if (state->is_v6) { + unsigned int m, lsb, width, Rd, Rn, data; + Rd = Rn = lsb = width = data = m = 0; + + //printf("helloworld\n"); + if ((((int) BITS (21, 27)) == 0x3f) && (((int) BITS (4, 6)) == 0x5)) { + m = (unsigned)BITS(7, 11); + width = (unsigned)BITS(16, 20); + Rd = (unsigned)BITS(12, 15); + Rn = (unsigned)BITS(0, 3); + if ((Rd == 15) || (Rn == 15)) { + ARMul_UndefInstr (state, instr); + } + else if ((m + width) < 32) { + data = state->Reg[Rn]; + state->Reg[Rd] ^= state->Reg[Rd]; + state->Reg[Rd] = + ((ARMword)(data << (31 -(m + width))) >> ((31 - (m + width)) + (m))); + //SKYEYE_LOG_IN_CLR(RED, "UBFX: In %s, line = %d, Reg_src[%d] = 0x%x, Reg_d[%d] = 0x%x, m = %d, width = %d, Rd = %d, Rn = %d\n", + // __FUNCTION__, __LINE__, Rn, data, Rd, state->Reg[Rd], m, width + 1, Rd, Rn); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + } // ubfx instr + else if ((((int) BITS (21, 27)) == 0x3d) && (((int) BITS (4, 6)) == 0x5)) { + int tmp = 0; + Rd = BITS(12, 15); Rn = BITS(0, 3); + lsb = BITS(7, 11); width = BITS(16, 20); + if ((Rd == 15) || (Rn == 15)) { + ARMul_UndefInstr (state, instr); + } + else if ((lsb + width) < 32) { + state->Reg[Rd] ^= state->Reg[Rd]; + data = state->Reg[Rn]; + tmp = (data << (32 - (lsb + width + 1))); + state->Reg[Rd] = (tmp >> (32 - (lsb + width + 1))); + //SKYEYE_LOG_IN_CLR(RED, "sbfx: In %s, line = %d, pc = 0x%x, instr = 0x%x,Rd = 0x%x, \ + Rn = 0x%x, lsb = %d, width = %d, Rs[%d] = 0x%x, Rd[%d] = 0x%x\n", + // __func__, __LINE__, pc, instr, Rd, Rn, lsb, width + 1, Rn, state->Reg[Rn], Rd, state->Reg[Rd]); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + } // sbfx instr + else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) { + //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) + unsigned msb ,tmp_rn, tmp_rd, dst; + msb = tmp_rd = tmp_rn = dst = 0; + Rd = BITS(12, 15); Rn = BITS(0, 3); + lsb = BITS(7, 11); msb = BITS(16, 20); + if ((Rd == 15)) { + ARMul_UndefInstr (state, instr); + } + else if ((Rn == 15)) { + data = state->Reg[Rd]; + tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); + dst = ((data >> msb) << (msb - lsb)); + dst = (dst << lsb) | tmp_rd; + DEBUG_LOG(ARM11, "BFC instr: msb = %d, lsb = %d, Rd[%d] : 0x%x, dst = 0x%x\n", + msb, lsb, Rd, state->Reg[Rd], dst); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } // bfc instr + else if (((msb >= lsb) && (msb < 32))) { + data = state->Reg[Rn]; + tmp_rn = ((ARMword)(data << (31 - (msb - lsb))) >> (31 - (msb - lsb))); + data = state->Reg[Rd]; + tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); + dst = ((data >> msb) << (msb - lsb)) | tmp_rn; + dst = (dst << lsb) | tmp_rd; + DEBUG_LOG(ARM11, "BFI instr:msb = %d, lsb = %d, Rd[%d] : 0x%x, Rn[%d]: 0x%x, dst = 0x%x\n", + msb, lsb, Rd, state->Reg[Rd], Rn, state->Reg[Rn], dst); + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } // bfi instr + } + } + + switch ((int) BITS (20, 27)) { + /* Data Processing Register RHS Instructions. */ + + case 0x00: /* AND reg and MUL */ +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, no write-back, down, post indexed. */ + SHDOWNWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + if (BITS (4, 7) == 9) { + /* MUL */ + rhs = state->Reg[MULRHSReg]; + //if (MULLHSReg == MULDESTReg) { + if(0){ /* For armv6, the restriction is removed */ + UNDEF_MULDestEQOp1; + state->Reg[MULDESTReg] = 0; + } + else if (MULDESTReg != 15) + state->Reg[MULDESTReg] = + state-> + Reg[MULLHSReg] * rhs; + else + UNDEF_MULPCDest; + + for (dest = 0, temp = 0; dest < 32; + dest++) + if (rhs & (1L << dest)) + temp = dest; + + /* Mult takes this many/2 I cycles. */ + ARMul_Icycles (state, + ARMul_MultTable[temp], + 0L); + } + else { + /* AND reg. */ + rhs = DPRegRHS; + dest = LHS & rhs; + WRITEDEST (dest); + } + break; + + case 0x01: /* ANDS reg and MULS */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, no write-back, down, post indexed. */ + LHPOSTDOWN (); + /* Fall through to rest of decoding. */ +#endif + if (BITS (4, 7) == 9) { + /* MULS */ + rhs = state->Reg[MULRHSReg]; + + //if (MULLHSReg == MULDESTReg) { + if(0){ + printf("Something in %d line\n", __LINE__); + UNDEF_WARNING; + UNDEF_MULDestEQOp1; + state->Reg[MULDESTReg] = 0; + CLEARN; + SETZ; + } + else if (MULDESTReg != 15) { + dest = state->Reg[MULLHSReg] * + rhs; + ARMul_NegZero (state, dest); + state->Reg[MULDESTReg] = dest; + } + else + UNDEF_MULPCDest; + + for (dest = 0, temp = 0; dest < 32; + dest++) + if (rhs & (1L << dest)) + temp = dest; + + /* Mult takes this many/2 I cycles. */ + ARMul_Icycles (state, + ARMul_MultTable[temp], + 0L); + } + else { + /* ANDS reg. */ + rhs = DPSRegRHS; + dest = LHS & rhs; + WRITESDEST (dest); + } + break; + + case 0x02: /* EOR reg and MLA */ +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, write-back, down, post indexed. */ + SHDOWNWB (); + break; + } +#endif + if (BITS (4, 7) == 9) { /* MLA */ + rhs = state->Reg[MULRHSReg]; + #if 0 + if (MULLHSReg == MULDESTReg) { + UNDEF_MULDestEQOp1; + state->Reg[MULDESTReg] = + state->Reg[MULACCReg]; + } + else if (MULDESTReg != 15){ + #endif + if (MULDESTReg != 15){ + state->Reg[MULDESTReg] = + state-> + Reg[MULLHSReg] * rhs + + state->Reg[MULACCReg]; + } + else + UNDEF_MULPCDest; + + for (dest = 0, temp = 0; dest < 32; + dest++) + if (rhs & (1L << dest)) + temp = dest; + + /* Mult takes this many/2 I cycles. */ + ARMul_Icycles (state, + ARMul_MultTable[temp], + 0L); + } + else { + rhs = DPRegRHS; + dest = LHS ^ rhs; + WRITEDEST (dest); + } + break; + + case 0x03: /* EORS reg and MLAS */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, write-back, down, post-indexed. */ + LHPOSTDOWN (); + /* Fall through to rest of the decoding. */ +#endif + if (BITS (4, 7) == 9) { + /* MLAS */ + rhs = state->Reg[MULRHSReg]; + //if (MULLHSReg == MULDESTReg) { + if (0) { + UNDEF_MULDestEQOp1; + dest = state->Reg[MULACCReg]; + ARMul_NegZero (state, dest); + state->Reg[MULDESTReg] = dest; + } + else if (MULDESTReg != 15) { + dest = state->Reg[MULLHSReg] * + rhs + + state->Reg[MULACCReg]; + ARMul_NegZero (state, dest); + state->Reg[MULDESTReg] = dest; + } + else + UNDEF_MULPCDest; + + for (dest = 0, temp = 0; dest < 32; + dest++) + if (rhs & (1L << dest)) + temp = dest; + + /* Mult takes this many/2 I cycles. */ + ARMul_Icycles (state, + ARMul_MultTable[temp], + 0L); + } + else { + /* EORS Reg. */ + rhs = DPSRegRHS; + dest = LHS ^ rhs; + WRITESDEST (dest); + } + break; + + case 0x04: /* SUB reg */ +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, no write-back, down, post indexed. */ + SHDOWNWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS - rhs; + WRITEDEST (dest); + break; + + case 0x05: /* SUBS reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, no write-back, down, post indexed. */ + LHPOSTDOWN (); + /* Fall through to the rest of the instruction decoding. */ +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = lhs - rhs; + + if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, rhs, + dest); + ARMul_SubOverflow (state, lhs, rhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x06: /* RSB reg */ +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, write-back, down, post indexed. */ + SHDOWNWB (); + break; + } +#endif + rhs = DPRegRHS; + dest = rhs - LHS; + WRITEDEST (dest); + break; + + case 0x07: /* RSBS reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, write-back, down, post indexed. */ + LHPOSTDOWN (); + /* Fall through to remainder of instruction decoding. */ +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = rhs - lhs; + + if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, rhs, lhs, + dest); + ARMul_SubOverflow (state, rhs, lhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x08: /* ADD reg */ +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, no write-back, up, post indexed. */ + SHUPWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif +#ifdef MODET + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32 = 64 */ + ARMul_Icycles (state, + Multiply64 (state, + instr, + LUNSIGNED, + LDEFAULT), + 0L); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS + rhs; + WRITEDEST (dest); + break; + + case 0x09: /* ADDS reg */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, no write-back, up, post indexed. */ + LHPOSTUP (); + /* Fall through to remaining instruction decoding. */ +#endif +#ifdef MODET + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + Multiply64 (state, + instr, + LUNSIGNED, + LSCC), 0L); + break; + } +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = lhs + rhs; + ASSIGNZ (dest == 0); + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, rhs, + dest); + ARMul_AddOverflow (state, lhs, rhs, + dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x0a: /* ADC reg */ +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, write-back, up, post-indexed. */ + SHUPWB (); + break; + } + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + MultiplyAdd64 (state, + instr, + LUNSIGNED, + LDEFAULT), + 0L); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS + rhs + CFLAG; + WRITEDEST (dest); + break; + + case 0x0b: /* ADCS reg */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, write-back, up, post indexed. */ + LHPOSTUP (); + /* Fall through to remaining instruction decoding. */ + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + MultiplyAdd64 (state, + instr, + LUNSIGNED, + LSCC), + 0L); + break; + } +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = lhs + rhs + CFLAG; + ASSIGNZ (dest == 0); + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, rhs, + dest); + ARMul_AddOverflow (state, lhs, rhs, + dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x0c: /* SBC reg */ +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, no write-back, up post indexed. */ + SHUPWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + Multiply64 (state, + instr, + LSIGNED, + LDEFAULT), + 0L); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS - rhs - !CFLAG; + WRITEDEST (dest); + break; + + case 0x0d: /* SBCS reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, no write-back, up, post indexed. */ + LHPOSTUP (); + + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + Multiply64 (state, + instr, + LSIGNED, + LSCC), 0L); + break; + } +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = lhs - rhs - !CFLAG; + if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, rhs, + dest); + ARMul_SubOverflow (state, lhs, rhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x0e: /* RSC reg */ +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, write-back, up, post indexed. */ + SHUPWB (); + break; + } + + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + MultiplyAdd64 (state, + instr, + LSIGNED, + LDEFAULT), + 0L); + break; + } +#endif + rhs = DPRegRHS; + dest = rhs - LHS - !CFLAG; + WRITEDEST (dest); + break; + + case 0x0f: /* RSCS reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, write-back, up, post indexed. */ + LHPOSTUP (); + /* Fall through to remaining instruction decoding. */ + + if (BITS (4, 7) == 0x9) { + /* MULL */ + /* 32x32=64 */ + ARMul_Icycles (state, + MultiplyAdd64 (state, + instr, + LSIGNED, + LSCC), + 0L); + break; + } +#endif + lhs = LHS; + rhs = DPRegRHS; + dest = rhs - lhs - !CFLAG; + + if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, rhs, lhs, + dest); + ARMul_SubOverflow (state, rhs, lhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x10: /* TST reg and MRS CPSR and SWP word. */ + if (state->is_v5e) { + if (BIT (4) == 0 && BIT (7) == 1) { + /* ElSegundo SMLAxy insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (8, 11)]; + ARMword Rn = + state-> + Reg[BITS (12, 15)]; + + if (BIT (5)) + op1 >>= 16; + if (BIT (6)) + op2 >>= 16; + op1 &= 0xFFFF; + op2 &= 0xFFFF; + if (op1 & 0x8000) + op1 -= 65536; + if (op2 & 0x8000) + op2 -= 65536; + op1 *= op2; + //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn); + if (AddOverflow + (op1, Rn, op1 + Rn)) + SETS; + state->Reg[BITS (16, 19)] = + op1 + Rn; + break; + } + + if (BITS (4, 11) == 5) { + /* ElSegundo QADD insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (16, 19)]; + ARMword result = op1 + op2; + if (AddOverflow + (op1, op2, result)) { + result = POS (result) + ? 0x80000000 : + 0x7fffffff; + SETS; + } + state->Reg[BITS (12, 15)] = + result; + break; + } + } +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, no write-back, down, pre indexed. */ + SHPREDOWN (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + if (BITS (4, 11) == 9) { + /* SWP */ + UNDEF_SWPPC; + temp = LHS; + BUSUSEDINCPCS; +#ifndef MODE32 + if (VECTORACCESS (temp) + || ADDREXCEPT (temp)) { + INTERNALABORT (temp); + (void) ARMul_LoadWordN (state, + temp); + (void) ARMul_LoadWordN (state, + temp); + } + else +#endif + dest = ARMul_SwapWord (state, + temp, + state-> + Reg + [RHSReg]); + if (temp & 3) + DEST = ARMul_Align (state, + temp, + dest); + else + DEST = dest; + if (state->abortSig || state->Aborted) + TAKEABORT; + } + else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */ + UNDEF_MRSPC; + DEST = ECC | EINT | EMODE; + } + else { + UNDEF_Test; + } + break; + + case 0x11: /* TSTP reg */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, no write-back, down, pre indexed. */ + LHPREDOWN (); + /* Continue with remaining instruction decode. */ +#endif + if (DESTReg == 15) { + /* TSTP reg */ +#ifdef MODE32 + //chy 2006-02-15 if in user mode, can not set cpsr 0:23 + //from p165 of ARMARM book + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + rhs = DPRegRHS; + temp = LHS & rhs; + SETR15PSR (temp); +#endif + } + else { + /* TST reg */ + rhs = DPSRegRHS; + dest = LHS & rhs; + ARMul_NegZero (state, dest); + } + break; + + case 0x12: /* TEQ reg and MSR reg to CPSR (ARM6). */ + + if (state->is_v5) { + if (BITS (4, 7) == 3) { + /* BLX(2) */ + ARMword temp; + + if (TFLAG) + temp = (pc + 2) | 1; + else + temp = pc + 4; + + WriteR15Branch (state, + state-> + Reg[RHSReg]); + state->Reg[14] = temp; + break; + } + } + + if (state->is_v5e) { + if (BIT (4) == 0 && BIT (7) == 1 + && (BIT (5) == 0 + || BITS (12, 15) == 0)) { + /* ElSegundo SMLAWy/SMULWy insn. */ + unsigned long long op1 = + state-> + Reg[BITS (0, 3)]; + unsigned long long op2 = + state-> + Reg[BITS (8, 11)]; + unsigned long long result; + + if (BIT (6)) + op2 >>= 16; + if (op1 & 0x80000000) + op1 -= 1ULL << 32; + op2 &= 0xFFFF; + if (op2 & 0x8000) + op2 -= 65536; + result = (op1 * op2) >> 16; + + if (BIT (5) == 0) { + ARMword Rn = + state-> + Reg[BITS + (12, 15)]; + + if (AddOverflow + (result, Rn, + result + Rn)) + SETS; + result += Rn; + } + state->Reg[BITS (16, 19)] = + result; + break; + } + + if (BITS (4, 11) == 5) { + /* ElSegundo QSUB insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (16, 19)]; + ARMword result = op1 - op2; + + if (SubOverflow + (op1, op2, result)) { + result = POS (result) + ? 0x80000000 : + 0x7fffffff; + SETS; + } + + state->Reg[BITS (12, 15)] = + result; + break; + } + } +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, write-back, down, pre indexed. */ + SHPREDOWNWB (); + break; + } + if (BITS (4, 27) == 0x12FFF1) { + /* BX */ + WriteR15Branch (state, + state->Reg[RHSReg]); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + if (state->is_v5) { + if (BITS (4, 7) == 0x7) { + ARMword value; + extern int + SWI_vector_installed; + + /* Hardware is allowed to optionally override this + instruction and treat it as a breakpoint. Since + this is a simulator not hardware, we take the position + that if a SWI vector was not installed, then an Abort + vector was probably not installed either, and so + normally this instruction would be ignored, even if an + Abort is generated. This is a bad thing, since GDB + uses this instruction for its breakpoints (at least in + Thumb mode it does). So intercept the instruction here + and generate a breakpoint SWI instead. */ + if (!SWI_vector_installed) + ARMul_OSHandleSWI + (state, + SWI_Breakpoint); + else { + /* BKPT - normally this will cause an abort, but on the + XScale we must check the DCSR. */ + XScale_set_fsr_far + (state, + ARMul_CP15_R5_MMU_EXCPT, + pc); + //if (!XScale_debug_moe + // (state, + // ARMul_CP14_R10_MOE_BT)) + // break; // Disabled /bunnei + } + + /* Force the next instruction to be refetched. */ + state->NextInstr = RESUME; + break; + } + } + if (DESTReg == 15) { + /* MSR reg to CPSR. */ + UNDEF_MSRPC; + temp = DPRegRHS; +#ifdef MODET + /* Don't allow TBIT to be set by MSR. */ + temp &= ~TBIT; +#endif + ARMul_FixCPSR (state, instr, temp); + } + else + UNDEF_Test; + + break; + + case 0x13: /* TEQP reg */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, write-back, down, pre indexed. */ + LHPREDOWNWB (); + /* Continue with remaining instruction decode. */ +#endif + if (DESTReg == 15) { + /* TEQP reg */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + rhs = DPRegRHS; + temp = LHS ^ rhs; + SETR15PSR (temp); +#endif + } + else { + /* TEQ Reg. */ + rhs = DPSRegRHS; + dest = LHS ^ rhs; + ARMul_NegZero (state, dest); + } + break; + + case 0x14: /* CMP reg and MRS SPSR and SWP byte. */ + if (state->is_v5e) { + if (BIT (4) == 0 && BIT (7) == 1) { + /* ElSegundo SMLALxy insn. */ + unsigned long long op1 = + state-> + Reg[BITS (0, 3)]; + unsigned long long op2 = + state-> + Reg[BITS (8, 11)]; + unsigned long long dest; + unsigned long long result; + + if (BIT (5)) + op1 >>= 16; + if (BIT (6)) + op2 >>= 16; + op1 &= 0xFFFF; + if (op1 & 0x8000) + op1 -= 65536; + op2 &= 0xFFFF; + if (op2 & 0x8000) + op2 -= 65536; + + dest = (unsigned long long) + state-> + Reg[BITS (16, 19)] << + 32; + dest |= state-> + Reg[BITS (12, 15)]; + dest += op1 * op2; + state->Reg[BITS (12, 15)] = + dest; + state->Reg[BITS (16, 19)] = + dest >> 32; + break; + } + + if (BITS (4, 11) == 5) { + /* ElSegundo QDADD insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (16, 19)]; + ARMword op2d = op2 + op2; + ARMword result; + + if (AddOverflow + (op2, op2, op2d)) { + SETS; + op2d = POS (op2d) ? + 0x80000000 : + 0x7fffffff; + } + + result = op1 + op2d; + if (AddOverflow + (op1, op2d, result)) { + SETS; + result = POS (result) + ? 0x80000000 : + 0x7fffffff; + } + + state->Reg[BITS (12, 15)] = + result; + break; + } + } +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, no write-back, down, pre indexed. */ + SHPREDOWN (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + if (BITS (4, 11) == 9) { + /* SWP */ + UNDEF_SWPPC; + temp = LHS; + BUSUSEDINCPCS; +#ifndef MODE32 + if (VECTORACCESS (temp) + || ADDREXCEPT (temp)) { + INTERNALABORT (temp); + (void) ARMul_LoadByte (state, + temp); + (void) ARMul_LoadByte (state, + temp); + } + else +#endif + DEST = ARMul_SwapByte (state, + temp, + state-> + Reg + [RHSReg]); + if (state->abortSig || state->Aborted) + TAKEABORT; + } + else if ((BITS (0, 11) == 0) + && (LHSReg == 15)) { + /* MRS SPSR */ + UNDEF_MRSPC; + DEST = GETSPSR (state->Bank); + } + else + UNDEF_Test; + + break; + + case 0x15: /* CMPP reg. */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, no write-back, down, pre indexed. */ + LHPREDOWN (); + /* Continue with remaining instruction decode. */ +#endif + if (DESTReg == 15) { + /* CMPP reg. */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + rhs = DPRegRHS; + temp = LHS - rhs; + SETR15PSR (temp); +#endif + } + else { + /* CMP reg. */ + lhs = LHS; + rhs = DPRegRHS; + dest = lhs - rhs; + ARMul_NegZero (state, dest); + if ((lhs >= rhs) + || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, + rhs, dest); + ARMul_SubOverflow (state, lhs, + rhs, dest); + } + else { + CLEARC; + CLEARV; + } + } + break; + + case 0x16: /* CMN reg and MSR reg to SPSR */ + if (state->is_v5e) { + if (BIT (4) == 0 && BIT (7) == 1 + && BITS (12, 15) == 0) { + /* ElSegundo SMULxy insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (8, 11)]; + ARMword Rn = + state-> + Reg[BITS (12, 15)]; + + if (BIT (5)) + op1 >>= 16; + if (BIT (6)) + op2 >>= 16; + op1 &= 0xFFFF; + op2 &= 0xFFFF; + if (op1 & 0x8000) + op1 -= 65536; + if (op2 & 0x8000) + op2 -= 65536; + + state->Reg[BITS (16, 19)] = + op1 * op2; + break; + } + + if (BITS (4, 11) == 5) { + /* ElSegundo QDSUB insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + ARMword op2 = + state-> + Reg[BITS (16, 19)]; + ARMword op2d = op2 + op2; + ARMword result; + + if (AddOverflow + (op2, op2, op2d)) { + SETS; + op2d = POS (op2d) ? + 0x80000000 : + 0x7fffffff; + } + + result = op1 - op2d; + if (SubOverflow + (op1, op2d, result)) { + SETS; + result = POS (result) + ? 0x80000000 : + 0x7fffffff; + } + + state->Reg[BITS (12, 15)] = + result; + break; + } + } + + if (state->is_v5) { + if (BITS (4, 11) == 0xF1 + && BITS (16, 19) == 0xF) { + /* ARM5 CLZ insn. */ + ARMword op1 = + state-> + Reg[BITS (0, 3)]; + int result = 32; + + if (op1) + for (result = 0; + (op1 & + 0x80000000) == + 0; op1 <<= 1) + result++; + state->Reg[BITS (12, 15)] = + result; + break; + } + } + +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, write-back, down, pre indexed. */ + SHPREDOWNWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + if (DESTReg == 15) { + /* MSR */ + UNDEF_MSRPC; + ARMul_FixSPSR (state, instr, + DPRegRHS); + } + else { + UNDEF_Test; + } + break; + + case 0x17: /* CMNP reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, write-back, down, pre indexed. */ + LHPREDOWNWB (); + /* Continue with remaining instruction decoding. */ +#endif + if (DESTReg == 15) { +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + rhs = DPRegRHS; + temp = LHS + rhs; + SETR15PSR (temp); +#endif + break; + } + else { + /* CMN reg. */ + lhs = LHS; + rhs = DPRegRHS; + dest = lhs + rhs; + ASSIGNZ (dest == 0); + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, + rhs, dest); + ARMul_AddOverflow (state, lhs, + rhs, dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + } + break; + + case 0x18: /* ORR reg */ +#ifdef MODET + /* dyf add armv6 instr strex 2010.9.17 */ + if (state->is_v6) { + if (BITS (4, 7) == 0x9) + if (handle_v6_insn (state, instr)) + break; + } + + if (BITS (4, 11) == 0xB) { + /* STRH register offset, no write-back, up, pre indexed. */ + SHPREUP (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS | rhs; + WRITEDEST (dest); + break; + + case 0x19: /* ORRS reg */ +#ifdef MODET + /* dyf add armv6 instr ldrex */ + if (state->is_v6) { + if (BITS (4, 7) == 0x9) { + if (handle_v6_insn (state, instr)) + break; + } + } + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, no write-back, up, pre indexed. */ + LHPREUP (); + /* Continue with remaining instruction decoding. */ +#endif + rhs = DPSRegRHS; + dest = LHS | rhs; + WRITESDEST (dest); + break; + + case 0x1a: /* MOV reg */ +#ifdef MODET + if (BITS (4, 11) == 0xB) { + /* STRH register offset, write-back, up, pre indexed. */ + SHPREUPWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + dest = DPRegRHS; + WRITEDEST (dest); + break; + + case 0x1b: /* MOVS reg */ +#ifdef MODET + if ((BITS (4, 11) & 0xF9) == 0x9) + /* LDR register offset, write-back, up, pre indexed. */ + LHPREUPWB (); + /* Continue with remaining instruction decoding. */ +#endif + dest = DPSRegRHS; + WRITESDEST (dest); + break; + + case 0x1c: /* BIC reg */ +#ifdef MODET + /* dyf add for STREXB */ + if (state->is_v6) { + if (BITS (4, 7) == 0x9) { + if (handle_v6_insn (state, instr)) + break; + } + } + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, no write-back, up, pre indexed. */ + SHPREUP (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + else if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + rhs = DPRegRHS; + dest = LHS & ~rhs; + WRITEDEST (dest); + break; + + case 0x1d: /* BICS reg */ +#ifdef MODET + /* ladsh P=1 U=1 W=0 L=1 S=1 H=1 */ + if (BITS(4, 7) == 0xF) { + temp = LHS + GetLS7RHS (state, instr); + LoadHalfWord (state, instr, temp, LSIGNED); + break; + + } + if (BITS (4, 7) == 0xb) { + /* LDRH immediate offset, no write-back, up, pre indexed. */ + temp = LHS + GetLS7RHS (state, instr); + LoadHalfWord (state, instr, temp, LUNSIGNED); + break; + } + if (BITS (4, 7) == 0xd) { + // alex-ykl fix: 2011-07-20 missing ldrsb instruction + temp = LHS + GetLS7RHS (state, instr); + LoadByte (state, instr, temp, LSIGNED); + break; + } + + /* Continue with instruction decoding. */ + /*if ((BITS (4, 7) & 0x9) == 0x9) */ + if ((BITS (4, 7)) == 0x9) { + /* ldrexb */ + if (state->is_v6) { + if (handle_v6_insn (state, instr)) + break; + } + /* LDR immediate offset, no write-back, up, pre indexed. */ + LHPREUP (); + + } + +#endif + rhs = DPSRegRHS; + dest = LHS & ~rhs; + WRITESDEST (dest); + break; + + case 0x1e: /* MVN reg */ +#ifdef MODET + if (BITS (4, 7) == 0xB) { + /* STRH immediate offset, write-back, up, pre indexed. */ + SHPREUPWB (); + break; + } + if (BITS (4, 7) == 0xD) { + Handle_Load_Double (state, instr); + break; + } + if (BITS (4, 7) == 0xF) { + Handle_Store_Double (state, instr); + break; + } +#endif + dest = ~DPRegRHS; + WRITEDEST (dest); + break; + + case 0x1f: /* MVNS reg */ +#ifdef MODET + if ((BITS (4, 7) & 0x9) == 0x9) + /* LDR immediate offset, write-back, up, pre indexed. */ + LHPREUPWB (); + /* Continue instruction decoding. */ +#endif + dest = ~DPSRegRHS; + WRITESDEST (dest); + break; + + + /* Data Processing Immediate RHS Instructions. */ + + case 0x20: /* AND immed */ + dest = LHS & DPImmRHS; + WRITEDEST (dest); + break; + + case 0x21: /* ANDS immed */ + DPSImmRHS; + dest = LHS & rhs; + WRITESDEST (dest); + break; + + case 0x22: /* EOR immed */ + dest = LHS ^ DPImmRHS; + WRITEDEST (dest); + break; + + case 0x23: /* EORS immed */ + DPSImmRHS; + dest = LHS ^ rhs; + WRITESDEST (dest); + break; + + case 0x24: /* SUB immed */ + dest = LHS - DPImmRHS; + WRITEDEST (dest); + break; + + case 0x25: /* SUBS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs - rhs; + + if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, rhs, + dest); + ARMul_SubOverflow (state, lhs, rhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x26: /* RSB immed */ + dest = DPImmRHS - LHS; + WRITEDEST (dest); + break; + + case 0x27: /* RSBS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = rhs - lhs; + + if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, rhs, lhs, + dest); + ARMul_SubOverflow (state, rhs, lhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x28: /* ADD immed */ + dest = LHS + DPImmRHS; + WRITEDEST (dest); + break; + + case 0x29: /* ADDS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs + rhs; + ASSIGNZ (dest == 0); + + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, rhs, + dest); + ARMul_AddOverflow (state, lhs, rhs, + dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x2a: /* ADC immed */ + dest = LHS + DPImmRHS + CFLAG; + WRITEDEST (dest); + break; + + case 0x2b: /* ADCS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs + rhs + CFLAG; + ASSIGNZ (dest == 0); + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, rhs, + dest); + ARMul_AddOverflow (state, lhs, rhs, + dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x2c: /* SBC immed */ + dest = LHS - DPImmRHS - !CFLAG; + WRITEDEST (dest); + break; + + case 0x2d: /* SBCS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs - rhs - !CFLAG; + if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, rhs, + dest); + ARMul_SubOverflow (state, lhs, rhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x2e: /* RSC immed */ + dest = DPImmRHS - LHS - !CFLAG; + WRITEDEST (dest); + break; + + case 0x2f: /* RSCS immed */ + lhs = LHS; + rhs = DPImmRHS; + dest = rhs - lhs - !CFLAG; + if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, rhs, lhs, + dest); + ARMul_SubOverflow (state, rhs, lhs, + dest); + } + else { + CLEARC; + CLEARV; + } + WRITESDEST (dest); + break; + + case 0x30: /* TST immed */ + /* shenoubang 2012-3-14*/ + if (state->is_v6) { /* movw, ARMV6, ARMv7 */ + dest ^= dest; + dest = BITS(16, 19); + dest = ((dest<<12) | BITS(0, 11)); + WRITEDEST(dest); + //SKYEYE_DBG("In %s, line = %d, pc = 0x%x, instr = 0x%x, R[0:11]: 0x%x, R[16:19]: 0x%x, R[%d]:0x%x\n", + // __func__, __LINE__, pc, instr, BITS(0, 11), BITS(16, 19), DESTReg, state->Reg[DESTReg]); + break; + } + else { + UNDEF_Test; + break; + } + + case 0x31: /* TSTP immed */ + if (DESTReg == 15) { + /* TSTP immed. */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + temp = LHS & DPImmRHS; + SETR15PSR (temp); +#endif + } + else { + /* TST immed. */ + DPSImmRHS; + dest = LHS & rhs; + ARMul_NegZero (state, dest); + } + break; + + case 0x32: /* TEQ immed and MSR immed to CPSR */ + if (DESTReg == 15) + /* MSR immed to CPSR. */ + ARMul_FixCPSR (state, instr, + DPImmRHS); + else + UNDEF_Test; + break; + + case 0x33: /* TEQP immed */ + if (DESTReg == 15) { + /* TEQP immed. */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + temp = LHS ^ DPImmRHS; + SETR15PSR (temp); +#endif + } + else { + DPSImmRHS; /* TEQ immed */ + dest = LHS ^ rhs; + ARMul_NegZero (state, dest); + } + break; + + case 0x34: /* CMP immed */ + UNDEF_Test; + break; + + case 0x35: /* CMPP immed */ + if (DESTReg == 15) { + /* CMPP immed. */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + temp = LHS - DPImmRHS; + SETR15PSR (temp); +#endif + break; + } + else { + /* CMP immed. */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs - rhs; + ARMul_NegZero (state, dest); + + if ((lhs >= rhs) + || ((rhs | lhs) >> 31)) { + ARMul_SubCarry (state, lhs, + rhs, dest); + ARMul_SubOverflow (state, lhs, + rhs, dest); + } + else { + CLEARC; + CLEARV; + } + } + break; + + case 0x36: /* CMN immed and MSR immed to SPSR */ + if (DESTReg == 15) + ARMul_FixSPSR (state, instr, + DPImmRHS); + else + UNDEF_Test; + break; + + case 0x37: /* CMNP immed. */ + if (DESTReg == 15) { + /* CMNP immed. */ +#ifdef MODE32 + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); +#else + temp = LHS + DPImmRHS; + SETR15PSR (temp); +#endif + break; + } + else { + /* CMN immed. */ + lhs = LHS; + rhs = DPImmRHS; + dest = lhs + rhs; + ASSIGNZ (dest == 0); + if ((lhs | rhs) >> 30) { + /* Possible C,V,N to set. */ + ASSIGNN (NEG (dest)); + ARMul_AddCarry (state, lhs, + rhs, dest); + ARMul_AddOverflow (state, lhs, + rhs, dest); + } + else { + CLEARN; + CLEARC; + CLEARV; + } + } + break; + + case 0x38: /* ORR immed. */ + dest = LHS | DPImmRHS; + WRITEDEST (dest); + break; + + case 0x39: /* ORRS immed. */ + DPSImmRHS; + dest = LHS | rhs; + WRITESDEST (dest); + break; + + case 0x3a: /* MOV immed. */ + dest = DPImmRHS; + WRITEDEST (dest); + break; + + case 0x3b: /* MOVS immed. */ + DPSImmRHS; + WRITESDEST (rhs); + break; + + case 0x3c: /* BIC immed. */ + dest = LHS & ~DPImmRHS; + WRITEDEST (dest); + break; + + case 0x3d: /* BICS immed. */ + DPSImmRHS; + dest = LHS & ~rhs; + WRITESDEST (dest); + break; + + case 0x3e: /* MVN immed. */ + dest = ~DPImmRHS; + WRITEDEST (dest); + break; + + case 0x3f: /* MVNS immed. */ + DPSImmRHS; + WRITESDEST (~rhs); + break; + + + /* Single Data Transfer Immediate RHS Instructions. */ + + case 0x40: /* Store Word, No WriteBack, Post Dec, Immed. */ + lhs = LHS; + if (StoreWord (state, instr, lhs)) + LSBase = lhs - LSImmRHS; + break; + + case 0x41: /* Load Word, No WriteBack, Post Dec, Immed. */ + lhs = LHS; + if (LoadWord (state, instr, lhs)) + LSBase = lhs - LSImmRHS; + break; + + case 0x42: /* Store Word, WriteBack, Post Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + temp = lhs - LSImmRHS; + state->NtransSig = LOW; + if (StoreWord (state, instr, lhs)) + LSBase = temp; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x43: /* Load Word, WriteBack, Post Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (LoadWord (state, instr, lhs)) + LSBase = lhs - LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x44: /* Store Byte, No WriteBack, Post Dec, Immed. */ + lhs = LHS; + if (StoreByte (state, instr, lhs)) + LSBase = lhs - LSImmRHS; + break; + + case 0x45: /* Load Byte, No WriteBack, Post Dec, Immed. */ + lhs = LHS; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = lhs - LSImmRHS; + break; + + case 0x46: /* Store Byte, WriteBack, Post Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreByte (state, instr, lhs)) + LSBase = lhs - LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x47: /* Load Byte, WriteBack, Post Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = lhs - LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x48: /* Store Word, No WriteBack, Post Inc, Immed. */ + lhs = LHS; + if (StoreWord (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + break; + + case 0x49: /* Load Word, No WriteBack, Post Inc, Immed. */ + lhs = LHS; + if (LoadWord (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + break; + + case 0x4a: /* Store Word, WriteBack, Post Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreWord (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x4b: /* Load Word, WriteBack, Post Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (LoadWord (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x4c: /* Store Byte, No WriteBack, Post Inc, Immed. */ + lhs = LHS; + if (StoreByte (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + break; + + case 0x4d: /* Load Byte, No WriteBack, Post Inc, Immed. */ + lhs = LHS; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = lhs + LSImmRHS; + break; + + case 0x4e: /* Store Byte, WriteBack, Post Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreByte (state, instr, lhs)) + LSBase = lhs + LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x4f: /* Load Byte, WriteBack, Post Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + lhs = LHS; + state->NtransSig = LOW; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = lhs + LSImmRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + + case 0x50: /* Store Word, No WriteBack, Pre Dec, Immed. */ + (void) StoreWord (state, instr, + LHS - LSImmRHS); + break; + + case 0x51: /* Load Word, No WriteBack, Pre Dec, Immed. */ + (void) LoadWord (state, instr, + LHS - LSImmRHS); + break; + + case 0x52: /* Store Word, WriteBack, Pre Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS - LSImmRHS; + if (StoreWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x53: /* Load Word, WriteBack, Pre Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS - LSImmRHS; + if (LoadWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x54: /* Store Byte, No WriteBack, Pre Dec, Immed. */ + (void) StoreByte (state, instr, + LHS - LSImmRHS); + break; + + case 0x55: /* Load Byte, No WriteBack, Pre Dec, Immed. */ + (void) LoadByte (state, instr, LHS - LSImmRHS, + LUNSIGNED); + break; + + case 0x56: /* Store Byte, WriteBack, Pre Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS - LSImmRHS; + if (StoreByte (state, instr, temp)) + LSBase = temp; + break; + + case 0x57: /* Load Byte, WriteBack, Pre Dec, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS - LSImmRHS; + if (LoadByte (state, instr, temp, LUNSIGNED)) + LSBase = temp; + break; + + case 0x58: /* Store Word, No WriteBack, Pre Inc, Immed. */ + (void) StoreWord (state, instr, + LHS + LSImmRHS); + break; + + case 0x59: /* Load Word, No WriteBack, Pre Inc, Immed. */ + (void) LoadWord (state, instr, + LHS + LSImmRHS); + break; + + case 0x5a: /* Store Word, WriteBack, Pre Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS + LSImmRHS; + if (StoreWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x5b: /* Load Word, WriteBack, Pre Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS + LSImmRHS; + if (LoadWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x5c: /* Store Byte, No WriteBack, Pre Inc, Immed. */ + (void) StoreByte (state, instr, + LHS + LSImmRHS); + break; + + case 0x5d: /* Load Byte, No WriteBack, Pre Inc, Immed. */ + (void) LoadByte (state, instr, LHS + LSImmRHS, + LUNSIGNED); + break; + + case 0x5e: /* Store Byte, WriteBack, Pre Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS + LSImmRHS; + if (StoreByte (state, instr, temp)) + LSBase = temp; + break; + + case 0x5f: /* Load Byte, WriteBack, Pre Inc, Immed. */ + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + temp = LHS + LSImmRHS; + if (LoadByte (state, instr, temp, LUNSIGNED)) + LSBase = temp; + break; + + + /* Single Data Transfer Register RHS Instructions. */ + + case 0x60: /* Store Word, No WriteBack, Post Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + if (StoreWord (state, instr, lhs)) + LSBase = lhs - LSRegRHS; + break; + + case 0x61: /* Load Word, No WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs - LSRegRHS; + if (LoadWord (state, instr, lhs)) + LSBase = temp; + break; + + case 0x62: /* Store Word, WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreWord (state, instr, lhs)) + LSBase = lhs - LSRegRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x63: /* Load Word, WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs - LSRegRHS; + state->NtransSig = LOW; + if (LoadWord (state, instr, lhs)) + LSBase = temp; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x64: /* Store Byte, No WriteBack, Post Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + if (StoreByte (state, instr, lhs)) + LSBase = lhs - LSRegRHS; + break; + + case 0x65: /* Load Byte, No WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs - LSRegRHS; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = temp; + break; + + case 0x66: /* Store Byte, WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreByte (state, instr, lhs)) + LSBase = lhs - LSRegRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x67: /* Load Byte, WriteBack, Post Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs - LSRegRHS; + state->NtransSig = LOW; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = temp; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + if (StoreWord (state, instr, lhs)) + LSBase = lhs + LSRegRHS; + break; + + case 0x69: /* Load Word, No WriteBack, Post Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs + LSRegRHS; + if (LoadWord (state, instr, lhs)) + LSBase = temp; + break; + + case 0x6a: /* Store Word, WriteBack, Post Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreWord (state, instr, lhs)) + LSBase = lhs + LSRegRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x6b: /* Load Word, WriteBack, Post Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs + LSRegRHS; + state->NtransSig = LOW; + if (LoadWord (state, instr, lhs)) + LSBase = temp; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x6c: /* Store Byte, No WriteBack, Post Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + if (StoreByte (state, instr, lhs)) + LSBase = lhs + LSRegRHS; + break; + + case 0x6d: /* Load Byte, No WriteBack, Post Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs + LSRegRHS; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = temp; + break; + + case 0x6e: /* Store Byte, WriteBack, Post Inc, Reg. */ +#if 0 + if (state->is_v6) { + int Rm = 0; + /* utxb */ + if (BITS(15, 19) == 0xf && BITS(4, 7) == 0x7) { + + Rm = (RHS >> (8 * BITS(10, 11))) & 0xff; + DEST = Rm; + } + + } +#endif + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + state->NtransSig = LOW; + if (StoreByte (state, instr, lhs)) + LSBase = lhs + LSRegRHS; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + case 0x6f: /* Load Byte, WriteBack, Post Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + lhs = LHS; + temp = lhs + LSRegRHS; + state->NtransSig = LOW; + if (LoadByte (state, instr, lhs, LUNSIGNED)) + LSBase = temp; + state->NtransSig = + (state->Mode & 3) ? HIGH : LOW; + break; + + + case 0x70: /* Store Word, No WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + (void) StoreWord (state, instr, + LHS - LSRegRHS); + break; + + case 0x71: /* Load Word, No WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + (void) LoadWord (state, instr, + LHS - LSRegRHS); + break; + + case 0x72: /* Store Word, WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS - LSRegRHS; + if (StoreWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x73: /* Load Word, WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS - LSRegRHS; + if (LoadWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x74: /* Store Byte, No WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + (void) StoreByte (state, instr, + LHS - LSRegRHS); + break; + + case 0x75: /* Load Byte, No WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + (void) LoadByte (state, instr, LHS - LSRegRHS, + LUNSIGNED); + break; + + case 0x76: /* Store Byte, WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS - LSRegRHS; + if (StoreByte (state, instr, temp)) + LSBase = temp; + break; + + case 0x77: /* Load Byte, WriteBack, Pre Dec, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS - LSRegRHS; + if (LoadByte (state, instr, temp, LUNSIGNED)) + LSBase = temp; + break; + + case 0x78: /* Store Word, No WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + (void) StoreWord (state, instr, + LHS + LSRegRHS); + break; + + case 0x79: /* Load Word, No WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + (void) LoadWord (state, instr, + LHS + LSRegRHS); + break; + + case 0x7a: /* Store Word, WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS + LSRegRHS; + if (StoreWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x7b: /* Load Word, WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS + LSRegRHS; + if (LoadWord (state, instr, temp)) + LSBase = temp; + break; + + case 0x7c: /* Store Byte, No WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { +#ifdef MODE32 + if (state->is_v6 + && handle_v6_insn (state, instr)) + break; +#endif + + ARMul_UndefInstr (state, instr); + break; + } + (void) StoreByte (state, instr, + LHS + LSRegRHS); + break; + + case 0x7d: /* Load Byte, No WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + (void) LoadByte (state, instr, LHS + LSRegRHS, + LUNSIGNED); + break; + + case 0x7e: /* Store Byte, WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { + ARMul_UndefInstr (state, instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS + LSRegRHS; + if (StoreByte (state, instr, temp)) + LSBase = temp; + break; + + case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */ + if (BIT (4)) { + /* Check for the special breakpoint opcode. + This value should correspond to the value defined + as ARM_BE_BREAKPOINT in gdb/arm/tm-arm.h. */ + if (BITS (0, 19) == 0xfdefe) { + if (!ARMul_OSHandleSWI + (state, SWI_Breakpoint)) + ARMul_Abort (state, + ARMul_SWIV); + } + else + ARMul_UndefInstr (state, + instr); + break; + } + UNDEF_LSRBaseEQOffWb; + UNDEF_LSRBaseEQDestWb; + UNDEF_LSRPCBaseWb; + UNDEF_LSRPCOffWb; + temp = LHS + LSRegRHS; + if (LoadByte (state, instr, temp, LUNSIGNED)) + LSBase = temp; + break; + + + /* Multiple Data Transfer Instructions. */ + + case 0x80: /* Store, No WriteBack, Post Dec. */ + STOREMULT (instr, LSBase - LSMNumRegs + 4L, + 0L); + break; + + case 0x81: /* Load, No WriteBack, Post Dec. */ + LOADMULT (instr, LSBase - LSMNumRegs + 4L, + 0L); + break; + + case 0x82: /* Store, WriteBack, Post Dec. */ + temp = LSBase - LSMNumRegs; + STOREMULT (instr, temp + 4L, temp); + break; + + case 0x83: /* Load, WriteBack, Post Dec. */ + temp = LSBase - LSMNumRegs; + LOADMULT (instr, temp + 4L, temp); + break; + + case 0x84: /* Store, Flags, No WriteBack, Post Dec. */ + STORESMULT (instr, LSBase - LSMNumRegs + 4L, + 0L); + break; + + case 0x85: /* Load, Flags, No WriteBack, Post Dec. */ + LOADSMULT (instr, LSBase - LSMNumRegs + 4L, + 0L); + break; + + case 0x86: /* Store, Flags, WriteBack, Post Dec. */ + temp = LSBase - LSMNumRegs; + STORESMULT (instr, temp + 4L, temp); + break; + + case 0x87: /* Load, Flags, WriteBack, Post Dec. */ + temp = LSBase - LSMNumRegs; + LOADSMULT (instr, temp + 4L, temp); + break; + + case 0x88: /* Store, No WriteBack, Post Inc. */ + STOREMULT (instr, LSBase, 0L); + break; + + case 0x89: /* Load, No WriteBack, Post Inc. */ + LOADMULT (instr, LSBase, 0L); + break; + + case 0x8a: /* Store, WriteBack, Post Inc. */ + temp = LSBase; + STOREMULT (instr, temp, temp + LSMNumRegs); + break; + + case 0x8b: /* Load, WriteBack, Post Inc. */ + temp = LSBase; + LOADMULT (instr, temp, temp + LSMNumRegs); + break; + + case 0x8c: /* Store, Flags, No WriteBack, Post Inc. */ + STORESMULT (instr, LSBase, 0L); + break; + + case 0x8d: /* Load, Flags, No WriteBack, Post Inc. */ + LOADSMULT (instr, LSBase, 0L); + break; + + case 0x8e: /* Store, Flags, WriteBack, Post Inc. */ + temp = LSBase; + STORESMULT (instr, temp, temp + LSMNumRegs); + break; + + case 0x8f: /* Load, Flags, WriteBack, Post Inc. */ + temp = LSBase; + LOADSMULT (instr, temp, temp + LSMNumRegs); + break; + + case 0x90: /* Store, No WriteBack, Pre Dec. */ + STOREMULT (instr, LSBase - LSMNumRegs, 0L); + break; + + case 0x91: /* Load, No WriteBack, Pre Dec. */ + LOADMULT (instr, LSBase - LSMNumRegs, 0L); + break; + + case 0x92: /* Store, WriteBack, Pre Dec. */ + temp = LSBase - LSMNumRegs; + STOREMULT (instr, temp, temp); + break; + + case 0x93: /* Load, WriteBack, Pre Dec. */ + temp = LSBase - LSMNumRegs; + LOADMULT (instr, temp, temp); + break; + + case 0x94: /* Store, Flags, No WriteBack, Pre Dec. */ + STORESMULT (instr, LSBase - LSMNumRegs, 0L); + break; + + case 0x95: /* Load, Flags, No WriteBack, Pre Dec. */ + LOADSMULT (instr, LSBase - LSMNumRegs, 0L); + break; + + case 0x96: /* Store, Flags, WriteBack, Pre Dec. */ + temp = LSBase - LSMNumRegs; + STORESMULT (instr, temp, temp); + break; + + case 0x97: /* Load, Flags, WriteBack, Pre Dec. */ + temp = LSBase - LSMNumRegs; + LOADSMULT (instr, temp, temp); + break; + + case 0x98: /* Store, No WriteBack, Pre Inc. */ + STOREMULT (instr, LSBase + 4L, 0L); + break; + + case 0x99: /* Load, No WriteBack, Pre Inc. */ + LOADMULT (instr, LSBase + 4L, 0L); + break; + + case 0x9a: /* Store, WriteBack, Pre Inc. */ + temp = LSBase; + STOREMULT (instr, temp + 4L, + temp + LSMNumRegs); + break; + + case 0x9b: /* Load, WriteBack, Pre Inc. */ + temp = LSBase; + LOADMULT (instr, temp + 4L, + temp + LSMNumRegs); + break; + + case 0x9c: /* Store, Flags, No WriteBack, Pre Inc. */ + STORESMULT (instr, LSBase + 4L, 0L); + break; + + case 0x9d: /* Load, Flags, No WriteBack, Pre Inc. */ + LOADSMULT (instr, LSBase + 4L, 0L); + break; + + case 0x9e: /* Store, Flags, WriteBack, Pre Inc. */ + temp = LSBase; + STORESMULT (instr, temp + 4L, + temp + LSMNumRegs); + break; + + case 0x9f: /* Load, Flags, WriteBack, Pre Inc. */ + temp = LSBase; + LOADSMULT (instr, temp + 4L, + temp + LSMNumRegs); + break; + + + /* Branch forward. */ + case 0xa0: + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + state->Reg[15] = pc + 8 + POSBRANCH; + FLUSHPIPE; + break; + + + /* Branch backward. */ + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + state->Reg[15] = pc + 8 + NEGBRANCH; + FLUSHPIPE; + break; + + + /* Branch and Link forward. */ + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + /* Put PC into Link. */ +#ifdef MODE32 + state->Reg[14] = pc + 4; +#else + state->Reg[14] = + (pc + 4) | ECC | ER15INT | EMODE; +#endif + state->Reg[15] = pc + 8 + POSBRANCH; + FLUSHPIPE; + break; + + + /* Branch and Link backward. */ + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + /* Put PC into Link. */ +#ifdef MODE32 + state->Reg[14] = pc + 4; +#else + state->Reg[14] = + (pc + 4) | ECC | ER15INT | EMODE; +#endif + state->Reg[15] = pc + 8 + NEGBRANCH; + FLUSHPIPE; + break; + + + /* Co-Processor Data Transfers. */ + case 0xc4: + if (state->is_v5) { + /* Reading from R15 is UNPREDICTABLE. */ + if (BITS (12, 15) == 15 + || BITS (16, 19) == 15) + ARMul_UndefInstr (state, + instr); + /* Is access to coprocessor 0 allowed ? */ + else if (!CP_ACCESS_ALLOWED + (state, CPNum)) + ARMul_UndefInstr (state, + instr); + /* Special treatment for XScale coprocessors. */ + else if (state->is_XScale) { + /* Only opcode 0 is supported. */ + if (BITS (4, 7) != 0x00) + ARMul_UndefInstr + (state, + instr); + /* Only coporcessor 0 is supported. */ + else if (CPNum != 0x00) + ARMul_UndefInstr + (state, + instr); + /* Only accumulator 0 is supported. */ + else if (BITS (0, 3) != 0x00) + ARMul_UndefInstr + (state, + instr); + else { + /* XScale MAR insn. Move two registers into accumulator. */ + state->Accumulator = + state-> + Reg[BITS + (12, 15)]; + state->Accumulator += + (ARMdword) + state-> + Reg[BITS + (16, + 19)] << + 32; + } + } + else + { + /* MCRR, ARMv5TE and up */ + ARMul_MCRR (state, instr, DEST, state->Reg[LHSReg]); + break; + } + } + /* Drop through. */ + + case 0xc0: /* Store , No WriteBack , Post Dec. */ + ARMul_STC (state, instr, LHS); + break; + + case 0xc5: + if (state->is_v5) { + /* Writes to R15 are UNPREDICATABLE. */ + if (DESTReg == 15 || LHSReg == 15) + ARMul_UndefInstr (state, + instr); + /* Is access to the coprocessor allowed ? */ + else if (!CP_ACCESS_ALLOWED + (state, CPNum)) + ARMul_UndefInstr (state, + instr); + /* Special handling for XScale coprcoessors. */ + else if (state->is_XScale) { + /* Only opcode 0 is supported. */ + if (BITS (4, 7) != 0x00) + ARMul_UndefInstr + (state, + instr); + /* Only coprocessor 0 is supported. */ + else if (CPNum != 0x00) + ARMul_UndefInstr + (state, + instr); + /* Only accumulator 0 is supported. */ + else if (BITS (0, 3) != 0x00) + ARMul_UndefInstr + (state, + instr); + else { + /* XScale MRA insn. Move accumulator into two registers. */ + ARMword t1 = + (state-> + Accumulator + >> 32) & 255; + + if (t1 & 128) + t1 -= 256; + + state->Reg[BITS + (12, 15)] = + state-> + Accumulator; + state->Reg[BITS + (16, 19)] = + t1; + break; + } + } + else + { + /* MRRC, ARMv5TE and up */ + ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); + break; + } + } + /* Drop through. */ + + case 0xc1: /* Load , No WriteBack , Post Dec. */ + ARMul_LDC (state, instr, LHS); + break; + + case 0xc2: + case 0xc6: /* Store , WriteBack , Post Dec. */ + lhs = LHS; + state->Base = lhs - LSCOff; + ARMul_STC (state, instr, lhs); + break; + + case 0xc3: + case 0xc7: /* Load , WriteBack , Post Dec. */ + lhs = LHS; + state->Base = lhs - LSCOff; + ARMul_LDC (state, instr, lhs); + break; + + case 0xc8: + case 0xcc: /* Store , No WriteBack , Post Inc. */ + ARMul_STC (state, instr, LHS); + break; + + case 0xc9: + case 0xcd: /* Load , No WriteBack , Post Inc. */ + ARMul_LDC (state, instr, LHS); + break; + + case 0xca: + case 0xce: /* Store , WriteBack , Post Inc. */ + lhs = LHS; + state->Base = lhs + LSCOff; + ARMul_STC (state, instr, LHS); + break; + + case 0xcb: + case 0xcf: /* Load , WriteBack , Post Inc. */ + lhs = LHS; + state->Base = lhs + LSCOff; + ARMul_LDC (state, instr, LHS); + break; + + case 0xd0: + case 0xd4: /* Store , No WriteBack , Pre Dec. */ + ARMul_STC (state, instr, LHS - LSCOff); + break; + + case 0xd1: + case 0xd5: /* Load , No WriteBack , Pre Dec. */ + ARMul_LDC (state, instr, LHS - LSCOff); + break; + + case 0xd2: + case 0xd6: /* Store , WriteBack , Pre Dec. */ + lhs = LHS - LSCOff; + state->Base = lhs; + ARMul_STC (state, instr, lhs); + break; + + case 0xd3: + case 0xd7: /* Load , WriteBack , Pre Dec. */ + lhs = LHS - LSCOff; + state->Base = lhs; + ARMul_LDC (state, instr, lhs); + break; + + case 0xd8: + case 0xdc: /* Store , No WriteBack , Pre Inc. */ + ARMul_STC (state, instr, LHS + LSCOff); + break; + + case 0xd9: + case 0xdd: /* Load , No WriteBack , Pre Inc. */ + ARMul_LDC (state, instr, LHS + LSCOff); + break; + + case 0xda: + case 0xde: /* Store , WriteBack , Pre Inc. */ + lhs = LHS + LSCOff; + state->Base = lhs; + ARMul_STC (state, instr, lhs); + break; + + case 0xdb: + case 0xdf: /* Load , WriteBack , Pre Inc. */ + lhs = LHS + LSCOff; + state->Base = lhs; + ARMul_LDC (state, instr, lhs); + break; + + + /* Co-Processor Register Transfers (MCR) and Data Ops. */ + + case 0xe2: + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + break; + } + if (state->is_XScale) + switch (BITS (18, 19)) { + case 0x0: + if (BITS (4, 11) == 1 + && BITS (16, 17) == 0) { + /* XScale MIA instruction. Signed multiplication of + two 32 bit values and addition to 40 bit accumulator. */ + long long Rm = + state-> + Reg + [MULLHSReg]; + long long Rs = + state-> + Reg + [MULACCReg]; + + if (Rm & (1 << 31)) + Rm -= 1ULL << + 32; + if (Rs & (1 << 31)) + Rs -= 1ULL << + 32; + state->Accumulator += + Rm * Rs; + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + break; + + case 0x2: + if (BITS (4, 11) == 1 + && BITS (16, 17) == 0) { + /* XScale MIAPH instruction. */ + ARMword t1 = + state-> + Reg[MULLHSReg] + >> 16; + ARMword t2 = + state-> + Reg[MULACCReg] + >> 16; + ARMword t3 = + state-> + Reg[MULLHSReg] + & 0xffff; + ARMword t4 = + state-> + Reg[MULACCReg] + & 0xffff; + long long t5; + + if (t1 & (1 << 15)) + t1 -= 1 << 16; + if (t2 & (1 << 15)) + t2 -= 1 << 16; + if (t3 & (1 << 15)) + t3 -= 1 << 16; + if (t4 & (1 << 15)) + t4 -= 1 << 16; + t1 *= t2; + t5 = t1; + if (t5 & (1 << 31)) + t5 -= 1ULL << + 32; + state->Accumulator += + t5; + t3 *= t4; + t5 = t3; + if (t5 & (1 << 31)) + t5 -= 1ULL << + 32; + state->Accumulator += + t5; + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + break; + + case 0x3: + if (BITS (4, 11) == 1) { + /* XScale MIAxy instruction. */ + ARMword t1; + ARMword t2; + long long t5; + + if (BIT (17)) + t1 = state-> + Reg + [MULLHSReg] + >> 16; + else + t1 = state-> + Reg + [MULLHSReg] + & + 0xffff; + + if (BIT (16)) + t2 = state-> + Reg + [MULACCReg] + >> 16; + else + t2 = state-> + Reg + [MULACCReg] + & + 0xffff; + + if (t1 & (1 << 15)) + t1 -= 1 << 16; + if (t2 & (1 << 15)) + t2 -= 1 << 16; + t1 *= t2; + t5 = t1; + if (t5 & (1 << 31)) + t5 -= 1ULL << + 32; + state->Accumulator += + t5; + _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; + } + break; + + default: + break; + } + /* Drop through. */ + + case 0xe0: + case 0xe4: + case 0xe6: + case 0xe8: + case 0xea: + case 0xec: + case 0xee: + if (BIT (4)) { + /* MCR. */ + if (DESTReg == 15) { + UNDEF_MCRPC; +#ifdef MODE32 + ARMul_MCR (state, instr, + state->Reg[15] + + isize); +#else + ARMul_MCR (state, instr, + ECC | ER15INT | + EMODE | + ((state->Reg[15] + + isize) & + R15PCBITS)); +#endif + } + else + ARMul_MCR (state, instr, + DEST); + } + else + /* CDP Part 1. */ + ARMul_CDP (state, instr); + break; + + + /* Co-Processor Register Transfers (MRC) and Data Ops. */ + case 0xe1: + case 0xe3: + case 0xe5: + case 0xe7: + case 0xe9: + case 0xeb: + case 0xed: + case 0xef: + if (BIT (4)) { + /* MRC */ + temp = ARMul_MRC (state, instr); + if (DESTReg == 15) { + ASSIGNN ((temp & NBIT) != 0); + ASSIGNZ ((temp & ZBIT) != 0); + ASSIGNC ((temp & CBIT) != 0); + ASSIGNV ((temp & VBIT) != 0); + } + else + DEST = temp; + } + else + /* CDP Part 2. */ + ARMul_CDP (state, instr); + break; + + + /* SWI instruction. */ + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + case 0xfc: + case 0xfd: + case 0xfe: + case 0xff: + if (instr == ARMul_ABORTWORD + && state->AbortAddr == pc) { + /* A prefetch abort. */ + XScale_set_fsr_far (state, + ARMul_CP15_R5_MMU_EXCPT, + pc); + ARMul_Abort (state, + ARMul_PrefetchAbortV); + break; + } + //sky_pref_t* pref = get_skyeye_pref(); + //if(pref->user_mode_sim){ + // ARMul_OSHandleSWI (state, BITS (0, 23)); + // break; + //} + ARMul_Abort (state, ARMul_SWIV); + break; + } + } + +#ifdef MODET + donext: +#endif + state->pc = pc; +#if 0 + /* shenoubang */ + instr_sum++; + int i, j; + i = j = 0; + if (instr_sum >= 7388648) { + //if (pc == 0xc0008ab4) { + // printf("instr_sum: %d\n", instr_sum); + // start_kernel : 0xc000895c + printf("--------------------------------------------------\n"); + for (i = 0; i < 16; i++) { + printf("[R%02d]:[0x%08x]\t", i, state->Reg[i]); + if ((i % 3) == 2) { + printf("\n"); + } + } + printf("[cpr]:[0x%08x]\t[spr0]:[0x%08x]\n", state->Cpsr, state->Spsr[0]); + for (j = 1; j < 7; j++) { + printf("[spr%d]:[0x%08x]\t", j, state->Spsr[j]); + if ((j % 4) == 3) { + printf("\n"); + } + } + printf("\n[PC]:[0x%08x]\t[INST]:[0x%08x]\t[COUNT]:[%d]\n", pc, instr, instr_sum); + printf("--------------------------------------------------\n"); + } +#endif + +#if 0 + fprintf(state->state_log, "PC:0x%x\n", pc); + for (reg_index = 0; reg_index < 16; reg_index ++) { + if (state->Reg[reg_index] != mirror_register_file[reg_index]) { + fprintf(state->state_log, "R%d:0x%x\n", reg_index, state->Reg[reg_index]); + mirror_register_file[reg_index] = state->Reg[reg_index]; + } + } + if (state->Cpsr != mirror_register_file[CPSR_REG]) { + fprintf(state->state_log, "Cpsr:0x%x\n", state->Cpsr); + mirror_register_file[CPSR_REG] = state->Cpsr; + } + if (state->RegBank[SVCBANK][13] != mirror_register_file[R13_SVC]) { + fprintf(state->state_log, "R13_SVC:0x%x\n", state->RegBank[SVCBANK][13]); + mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; + } + if (state->RegBank[SVCBANK][14] != mirror_register_file[R14_SVC]) { + fprintf(state->state_log, "R14_SVC:0x%x\n", state->RegBank[SVCBANK][14]); + mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; + } + if (state->RegBank[ABORTBANK][13] != mirror_register_file[R13_ABORT]) { + fprintf(state->state_log, "R13_ABORT:0x%x\n", state->RegBank[ABORTBANK][13]); + mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; + } + if (state->RegBank[ABORTBANK][14] != mirror_register_file[R14_ABORT]) { + fprintf(state->state_log, "R14_ABORT:0x%x\n", state->RegBank[ABORTBANK][14]); + mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; + } + if (state->RegBank[UNDEFBANK][13] != mirror_register_file[R13_UNDEF]) { + fprintf(state->state_log, "R13_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][13]); + mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; + } + if (state->RegBank[UNDEFBANK][14] != mirror_register_file[R14_UNDEF]) { + fprintf(state->state_log, "R14_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][14]); + mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; + } + if (state->RegBank[IRQBANK][13] != mirror_register_file[R13_IRQ]) { + fprintf(state->state_log, "R13_IRQ:0x%x\n", state->RegBank[IRQBANK][13]); + mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; + } + if (state->RegBank[IRQBANK][14] != mirror_register_file[R14_IRQ]) { + fprintf(state->state_log, "R14_IRQ:0x%x\n", state->RegBank[IRQBANK][14]); + mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; + } + if (state->RegBank[FIQBANK][8] != mirror_register_file[R8_FIRQ]) { + fprintf(state->state_log, "R8_FIRQ:0x%x\n", state->RegBank[FIQBANK][8]); + mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; + } + if (state->RegBank[FIQBANK][9] != mirror_register_file[R9_FIRQ]) { + fprintf(state->state_log, "R9_FIRQ:0x%x\n", state->RegBank[FIQBANK][9]); + mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; + } + if (state->RegBank[FIQBANK][10] != mirror_register_file[R10_FIRQ]) { + fprintf(state->state_log, "R10_FIRQ:0x%x\n", state->RegBank[FIQBANK][10]); + mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; + } + if (state->RegBank[FIQBANK][11] != mirror_register_file[R11_FIRQ]) { + fprintf(state->state_log, "R11_FIRQ:0x%x\n", state->RegBank[FIQBANK][11]); + mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; + } + if (state->RegBank[FIQBANK][12] != mirror_register_file[R12_FIRQ]) { + fprintf(state->state_log, "R12_FIRQ:0x%x\n", state->RegBank[FIQBANK][12]); + mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; + } + if (state->RegBank[FIQBANK][13] != mirror_register_file[R13_FIRQ]) { + fprintf(state->state_log, "R13_FIRQ:0x%x\n", state->RegBank[FIQBANK][13]); + mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; + } + if (state->RegBank[FIQBANK][14] != mirror_register_file[R14_FIRQ]) { + fprintf(state->state_log, "R14_FIRQ:0x%x\n", state->RegBank[FIQBANK][14]); + mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; + } + if (state->Spsr[SVCBANK] != mirror_register_file[SPSR_SVC]) { + fprintf(state->state_log, "SPSR_SVC:0x%x\n", state->Spsr[SVCBANK]); + mirror_register_file[SPSR_SVC] = state->RegBank[SVCBANK]; + } + if (state->Spsr[ABORTBANK] != mirror_register_file[SPSR_ABORT]) { + fprintf(state->state_log, "SPSR_ABORT:0x%x\n", state->Spsr[ABORTBANK]); + mirror_register_file[SPSR_ABORT] = state->RegBank[ABORTBANK]; + } + if (state->Spsr[UNDEFBANK] != mirror_register_file[SPSR_UNDEF]) { + fprintf(state->state_log, "SPSR_UNDEF:0x%x\n", state->Spsr[UNDEFBANK]); + mirror_register_file[SPSR_UNDEF] = state->RegBank[UNDEFBANK]; + } + if (state->Spsr[IRQBANK] != mirror_register_file[SPSR_IRQ]) { + fprintf(state->state_log, "SPSR_IRQ:0x%x\n", state->Spsr[IRQBANK]); + mirror_register_file[SPSR_IRQ] = state->RegBank[IRQBANK]; + } + if (state->Spsr[FIQBANK] != mirror_register_file[SPSR_FIRQ]) { + fprintf(state->state_log, "SPSR_FIRQ:0x%x\n", state->Spsr[FIQBANK]); + mirror_register_file[SPSR_FIRQ] = state->RegBank[FIQBANK]; + } + +#endif + +#ifdef NEED_UI_LOOP_HOOK + if (ui_loop_hook != NULL && ui_loop_hook_counter-- < 0) { + ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; + ui_loop_hook (0); + } +#endif /* NEED_UI_LOOP_HOOK */ + + /*added energy_prof statement by ksh in 2004-11-26 */ + //chy 2005-07-28 for standalone + //ARMul_do_energy(state,instr,pc); +//teawater add for record reg value to ./reg.txt 2005.07.10--------------------- + if (state->tea_break_ok && pc == state->tea_break_addr) { + ARMul_Debug (state, 0, 0); + state->tea_break_ok = 0; + } + else { + state->tea_break_ok = 1; + } +//AJ2D-------------------------------------------------------------------------- +//chy 2006-04-14 for ctrl-c debug +#if 0 + if (debugmode) { + if (instr != ARMul_ABORTWORD) { + remote_interrupt_test_time++; + //chy 2006-04-14 2000 should be changed in skyeye_conf ???!!! + if (remote_interrupt_test_time >= 2000) { + remote_interrupt_test_time=0; + if (remote_interrupt()) { + //for test + //printf("SKYEYE: ICE_debug recv Ctrl_C\n"); + state->EndCondition = 0; + state->Emulate = STOP; + } + } + } + } +#endif + + /* jump out every time */ + //state->EndCondition = 0; + //state->Emulate = STOP; +//chy 2006-04-12 for ICE debug +TEST_EMULATE: + if (state->Emulate == ONCE) + state->Emulate = STOP; + //chy: 2003-08-23: should not use CHANGEMODE !!!! + /* If we have changed mode, allow the PC to advance before stopping. */ + // else if (state->Emulate == CHANGEMODE) + // continue; + else if (state->Emulate != RUN) + break; + } + while (!state->stop_simulator); + + state->decoded = decoded; + state->loaded = loaded; + state->pc = pc; + //chy 2006-04-12, for ICE debug + state->decoded_addr=decoded_addr; + state->loaded_addr=loaded_addr; + + return pc; +} + +//teawater add for arm2x86 2005.02.17------------------------------------------- +/*ywc 2005-04-01*/ +//#include "tb.h" +//#include "arm2x86_self.h" + +static volatile void (*gen_func) (void); +//static volatile ARMul_State *tmp_st; +//static volatile ARMul_State *save_st; +static volatile uint32_t tmp_st; +static volatile uint32_t save_st; +static volatile uint32_t save_T0; +static volatile uint32_t save_T1; +static volatile uint32_t save_T2; + +#ifdef MODE32 +#ifdef DBCT +//teawater change for debug function 2005.07.09--------------------------------- +ARMword +ARMul_Emulate32_dbct (ARMul_State * state) +{ + static int init = 0; + static FILE *fd; + + /*if (!init) { + + fd = fopen("./pc.txt", "w"); + if (!fd) { + exit(-1); + } + init = 1; + } */ + + state->Reg[15] += INSN_SIZE; + do { + /*if (skyeye_config.log.logon>=1) { + if (state->NumInstrs>=skyeye_config.log.start && state->NumInstrs<=skyeye_config.log.end) { + static int mybegin=0; + static int myinstrnum=0; + + if (mybegin==0) mybegin=1; + if (mybegin==1) { + state->Reg[15] -= INSN_SIZE; + if (skyeye_config.log.logon>=1) fprintf(skyeye_logfd,"N %llx :p %x,i %x,",state->NumInstrs, (state->Reg[15] - INSN_SIZE), instr); + if (skyeye_config.log.logon>=2) SKYEYE_OUTREGS(skyeye_logfd); + if (skyeye_config.log.logon>=3) SKYEYE_OUTMOREREGS(skyeye_logfd); + fprintf(skyeye_logfd,"\n"); + if (skyeye_config.log.length>0) { + myinstrnum++; + if (myinstrnum>=skyeye_config.log.length) { + myinstrnum=0; + fflush(skyeye_logfd); + fseek(skyeye_logfd,0L,SEEK_SET); + } + } + state->Reg[15] += INSN_SIZE; + } + } + } */ + state->trap = 0; + gen_func = + (void *) tb_find (state, state->Reg[15] - INSN_SIZE); + if (!gen_func) { + //fprintf(stderr, "SKYEYE: tb_find: Error in find the translate block.\n"); + //exit(-1); + //TRAP_INSN_ABORT + //TEA_OUT(printf("\n------------\npc:%x\n", state->Reg[15] - INSN_SIZE)); + //TEA_OUT(printf("TRAP_INSN_ABORT\n")); +//teawater add for xscale(arm v5) 2005.09.01------------------------------------ + /*XScale_set_fsr_far(state, ARMul_CP15_R5_MMU_EXCPT, state->Reg[15] - INSN_SIZE); + state->Reg[15] += INSN_SIZE; + ARMul_Abort(state, ARMul_PrefetchAbortV); + state->Reg[15] += INSN_SIZE; + goto next; */ + state->trap = TRAP_INSN_ABORT; + goto check; +//AJ2D-------------------------------------------------------------------------- + } + + save_st = (uint32_t) st; + save_T0 = T0; + save_T1 = T1; + save_T2 = T2; + tmp_st = (uint32_t) state; + wmb (); + st = (ARMul_State *) tmp_st; + gen_func (); + st = (ARMul_State *) save_st; + T0 = save_T0; + T1 = save_T1; + T2 = save_T2; + + /*if (state->trap != TRAP_OUT) { + state->tea_break_ok = 1; + } + if (state->trap <= TRAP_SET_R15) { + goto next; + } */ + //TEA_OUT(printf("\n------------\npc:%x\n", state->Reg[15] - INSN_SIZE)); +//teawater add check thumb 2005.07.21------------------------------------------- + /*if (TFLAG) { + state->Reg[15] -= 2; + return(state->Reg[15]); + } */ +//AJ2D-------------------------------------------------------------------------- + +//teawater add for xscale(arm v5) 2005.09.01------------------------------------ + check: +//AJ2D-------------------------------------------------------------------------- + switch (state->trap) { + case TRAP_RESET: + { + //TEA_OUT(printf("TRAP_RESET\n")); + ARMul_Abort (state, ARMul_ResetV); + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_UNPREDICTABLE: + { + ARMul_Debug (state, 0, 0); + } + break; + case TRAP_INSN_UNDEF: + { + //TEA_OUT(printf("TRAP_INSN_UNDEF\n")); + state->Reg[15] += INSN_SIZE; + ARMul_UndefInstr (state, 0); + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_SWI: + { + //TEA_OUT(printf("TRAP_SWI\n")); + state->Reg[15] += INSN_SIZE; + ARMul_Abort (state, ARMul_SWIV); + state->Reg[15] += INSN_SIZE; + } + break; +//teawater add for xscale(arm v5) 2005.09.01------------------------------------ + case TRAP_INSN_ABORT: + { + XScale_set_fsr_far (state, + ARMul_CP15_R5_MMU_EXCPT, + state->Reg[15] - + INSN_SIZE); + state->Reg[15] += INSN_SIZE; + ARMul_Abort (state, ARMul_PrefetchAbortV); + state->Reg[15] += INSN_SIZE; + } + break; +//AJ2D-------------------------------------------------------------------------- + case TRAP_DATA_ABORT: + { + //TEA_OUT(printf("TRAP_DATA_ABORT\n")); + state->Reg[15] += INSN_SIZE; + ARMul_Abort (state, ARMul_DataAbortV); + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_IRQ: + { + //TEA_OUT(printf("TRAP_IRQ\n")); + state->Reg[15] += INSN_SIZE; + ARMul_Abort (state, ARMul_IRQV); + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_FIQ: + { + //TEA_OUT(printf("TRAP_FIQ\n")); + state->Reg[15] += INSN_SIZE; + ARMul_Abort (state, ARMul_FIQV); + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_SETS_R15: + { + //TEA_OUT(printf("TRAP_SETS_R15\n")); + /*if (state->Bank > 0) { + state->Cpsr = state->Spsr[state->Bank]; + ARMul_CPSRAltered (state); + } */ + WriteSR15 (state, state->Reg[15]); + } + break; + case TRAP_SET_CPSR: + { + //TEA_OUT(printf("TRAP_SET_CPSR\n")); + //chy 2006-02-15 USERBANK=SYSTEMBANK=0 + //chy 2006-02-16 should use Mode to test + //if (state->Bank > 0) { + if (state->Mode != USER26MODE && state->Mode != USER32MODE){ + ARMul_CPSRAltered (state); + } + state->Reg[15] += INSN_SIZE; + } + break; + case TRAP_OUT: + { + //TEA_OUT(printf("TRAP_OUT\n")); + goto out; + } + break; + case TRAP_BREAKPOINT: + { + //TEA_OUT(printf("TRAP_BREAKPOINT\n")); + state->Reg[15] -= INSN_SIZE; + if (!ARMul_OSHandleSWI + (state, SWI_Breakpoint)) { + ARMul_Abort (state, ARMul_SWIV); + } + state->Reg[15] += INSN_SIZE; + } + break; + } + + next: + if (state->Emulate == ONCE) { + state->Emulate = STOP; + break; + } + else if (state->Emulate != RUN) { + break; + } + } + while (!state->stop_simulator); + + out: + state->Reg[15] -= INSN_SIZE; + return (state->Reg[15]); +} +#endif +//AJ2D-------------------------------------------------------------------------- +#endif +//AJ2D-------------------------------------------------------------------------- + +/* This routine evaluates most Data Processing register RHS's with the S + bit clear. It is intended to be called from the macro DPRegRHS, which + filters the common case of an unshifted register with in line code. */ + +static ARMword +GetDPRegRHS (ARMul_State * state, ARMword instr) +{ + ARMword shamt, base; + + base = RHSReg; + if (BIT (4)) { + /* Shift amount in a register. */ + UNDEF_Shift; + INCPC; +#ifndef MODE32 + if (base == 15) + base = ECC | ER15INT | R15PC | EMODE; + else +#endif + base = state->Reg[base]; + ARMul_Icycles (state, 1, 0L); + shamt = state->Reg[BITS (8, 11)] & 0xff; + switch ((int) BITS (5, 6)) { + case LSL: + if (shamt == 0) + return (base); + else if (shamt >= 32) + return (0); + else + return (base << shamt); + case LSR: + if (shamt == 0) + return (base); + else if (shamt >= 32) + return (0); + else + return (base >> shamt); + case ASR: + if (shamt == 0) + return (base); + else if (shamt >= 32) + return ((ARMword) ((int) base >> 31L)); + else + return ((ARMword) + (( int) base >> (int) shamt)); + case ROR: + shamt &= 0x1f; + if (shamt == 0) + return (base); + else + return ((base << (32 - shamt)) | + (base >> shamt)); + } + } + else { + /* Shift amount is a constant. */ +#ifndef MODE32 + if (base == 15) + base = ECC | ER15INT | R15PC | EMODE; + else +#endif + base = state->Reg[base]; + shamt = BITS (7, 11); + switch ((int) BITS (5, 6)) { + case LSL: + return (base << shamt); + case LSR: + if (shamt == 0) + return (0); + else + return (base >> shamt); + case ASR: + if (shamt == 0) + return ((ARMword) (( int) base >> 31L)); + else + return ((ARMword) + (( int) base >> (int) shamt)); + case ROR: + if (shamt == 0) + /* It's an RRX. */ + return ((base >> 1) | (CFLAG << 31)); + else + return ((base << (32 - shamt)) | + (base >> shamt)); + } + } + + return 0; +} + +/* This routine evaluates most Logical Data Processing register RHS's + with the S bit set. It is intended to be called from the macro + DPSRegRHS, which filters the common case of an unshifted register + with in line code. */ + +static ARMword +GetDPSRegRHS (ARMul_State * state, ARMword instr) +{ + ARMword shamt, base; + + base = RHSReg; + if (BIT (4)) { + /* Shift amount in a register. */ + UNDEF_Shift; + INCPC; +#ifndef MODE32 + if (base == 15) + base = ECC | ER15INT | R15PC | EMODE; + else +#endif + base = state->Reg[base]; + ARMul_Icycles (state, 1, 0L); + shamt = state->Reg[BITS (8, 11)] & 0xff; + switch ((int) BITS (5, 6)) { + case LSL: + if (shamt == 0) + return (base); + else if (shamt == 32) { + ASSIGNC (base & 1); + return (0); + } + else if (shamt > 32) { + CLEARC; + return (0); + } + else { + ASSIGNC ((base >> (32 - shamt)) & 1); + return (base << shamt); + } + case LSR: + if (shamt == 0) + return (base); + else if (shamt == 32) { + ASSIGNC (base >> 31); + return (0); + } + else if (shamt > 32) { + CLEARC; + return (0); + } + else { + ASSIGNC ((base >> (shamt - 1)) & 1); + return (base >> shamt); + } + case ASR: + if (shamt == 0) + return (base); + else if (shamt >= 32) { + ASSIGNC (base >> 31L); + return ((ARMword) (( int) base >> 31L)); + } + else { + ASSIGNC ((ARMword) + (( int) base >> + (int) (shamt - 1)) & 1); + return ((ARMword) + ((int) base >> (int) shamt)); + } + case ROR: + if (shamt == 0) + return (base); + shamt &= 0x1f; + if (shamt == 0) { + ASSIGNC (base >> 31); + return (base); + } + else { + ASSIGNC ((base >> (shamt - 1)) & 1); + return ((base << (32 - shamt)) | + (base >> shamt)); + } + } + } + else { + /* Shift amount is a constant. */ +#ifndef MODE32 + if (base == 15) + base = ECC | ER15INT | R15PC | EMODE; + else +#endif + base = state->Reg[base]; + shamt = BITS (7, 11); + + switch ((int) BITS (5, 6)) { + case LSL: + ASSIGNC ((base >> (32 - shamt)) & 1); + return (base << shamt); + case LSR: + if (shamt == 0) { + ASSIGNC (base >> 31); + return (0); + } + else { + ASSIGNC ((base >> (shamt - 1)) & 1); + return (base >> shamt); + } + case ASR: + if (shamt == 0) { + ASSIGNC (base >> 31L); + return ((ARMword) ((int) base >> 31L)); + } + else { + ASSIGNC ((ARMword) + ((int) base >> + (int) (shamt - 1)) & 1); + return ((ARMword) + (( int) base >> (int) shamt)); + } + case ROR: + if (shamt == 0) { + /* It's an RRX. */ + shamt = CFLAG; + ASSIGNC (base & 1); + return ((base >> 1) | (shamt << 31)); + } + else { + ASSIGNC ((base >> (shamt - 1)) & 1); + return ((base << (32 - shamt)) | + (base >> shamt)); + } + } + } + + return 0; +} + +/* This routine handles writes to register 15 when the S bit is not set. */ + +static void +WriteR15 (ARMul_State * state, ARMword src) +{ + /* The ARM documentation states that the two least significant bits + are discarded when setting PC, except in the cases handled by + WriteR15Branch() below. It's probably an oversight: in THUMB + mode, the second least significant bit should probably not be + discarded. */ +#ifdef MODET + if (TFLAG) + src &= 0xfffffffe; + else +#endif + src &= 0xfffffffc; + +#ifdef MODE32 + state->Reg[15] = src & PCBITS; +#else + state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE; + ARMul_R15Altered (state); +#endif + + FLUSHPIPE; +} + +/* This routine handles writes to register 15 when the S bit is set. */ + +static void +WriteSR15 (ARMul_State * state, ARMword src) +{ +#ifdef MODE32 + if (state->Bank > 0) { + state->Cpsr = state->Spsr[state->Bank]; + ARMul_CPSRAltered (state); + } +#ifdef MODET + if (TFLAG) + src &= 0xfffffffe; + else +#endif + src &= 0xfffffffc; + state->Reg[15] = src & PCBITS; +#else +#ifdef MODET + if (TFLAG) + /* ARMul_R15Altered would have to support it. */ + abort (); + else +#endif + src &= 0xfffffffc; + + if (state->Bank == USERBANK) + state->Reg[15] = + (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE; + else + state->Reg[15] = src; + + ARMul_R15Altered (state); +#endif + FLUSHPIPE; +} + +/* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM + will switch to Thumb mode if the least significant bit is set. */ + +static void +WriteR15Branch (ARMul_State * state, ARMword src) +{ +#ifdef MODET + if (src & 1) { + /* Thumb bit. */ + SETT; + state->Reg[15] = src & 0xfffffffe; + } + else { + CLEART; + state->Reg[15] = src & 0xfffffffc; + } + state->Cpsr = ARMul_GetCPSR (state); + FLUSHPIPE; +#else + WriteR15 (state, src); +#endif +} + +/* This routine evaluates most Load and Store register RHS's. It is + intended to be called from the macro LSRegRHS, which filters the + common case of an unshifted register with in line code. */ + +static ARMword +GetLSRegRHS (ARMul_State * state, ARMword instr) +{ + ARMword shamt, base; + + base = RHSReg; +#ifndef MODE32 + if (base == 15) + /* Now forbidden, but ... */ + base = ECC | ER15INT | R15PC | EMODE; + else +#endif + base = state->Reg[base]; + + shamt = BITS (7, 11); + switch ((int) BITS (5, 6)) { + case LSL: + return (base << shamt); + case LSR: + if (shamt == 0) + return (0); + else + return (base >> shamt); + case ASR: + if (shamt == 0) + return ((ARMword) (( int) base >> 31L)); + else + return ((ARMword) (( int) base >> (int) shamt)); + case ROR: + if (shamt == 0) + /* It's an RRX. */ + return ((base >> 1) | (CFLAG << 31)); + else + return ((base << (32 - shamt)) | (base >> shamt)); + default: + break; + } + return 0; +} + +/* This routine evaluates the ARM7T halfword and signed transfer RHS's. */ + +static ARMword +GetLS7RHS (ARMul_State * state, ARMword instr) +{ + if (BIT (22) == 0) { + /* Register. */ +#ifndef MODE32 + if (RHSReg == 15) + /* Now forbidden, but ... */ + return ECC | ER15INT | R15PC | EMODE; +#endif + return state->Reg[RHSReg]; + } + + /* Immediate. */ + return BITS (0, 3) | (BITS (8, 11) << 4); +} + +/* This function does the work of loading a word for a LDR instruction. */ +#define MEM_LOAD_LOG(description) if (skyeye_config.log.memlogon >= 1) { \ + fprintf(skyeye_logfd, \ + "m LOAD %s: N %llx :p %x :i %x :a %x :d %x\n", \ + description, state->NumInstrs, state->pc, instr, \ + address, dest); \ + } + +#define MEM_STORE_LOG(description) if (skyeye_config.log.memlogon >= 1) { \ + fprintf(skyeye_logfd, \ + "m STORE %s: N %llx :p %x :i %x :a %x :d %x\n", \ + description, state->NumInstrs, state->pc, instr, \ + address, DEST); \ + } + + + +static unsigned +LoadWord (ARMul_State * state, ARMword instr, ARMword address) +{ + ARMword dest; + + BUSUSEDINCPCS; +#ifndef MODE32 + if (ADDREXCEPT (address)) + INTERNALABORT (address); +#endif + + dest = ARMul_LoadWordN (state, address); + + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + if (address & 3) + dest = ARMul_Align (state, address, dest); + WRITEDESTB (dest); + ARMul_Icycles (state, 1, 0L); + + //MEM_LOAD_LOG("WORD"); + + return (DESTReg != LHSReg); +} + +#ifdef MODET +/* This function does the work of loading a halfword. */ + +static unsigned +LoadHalfWord (ARMul_State * state, ARMword instr, ARMword address, + int signextend) +{ + ARMword dest; + + BUSUSEDINCPCS; +#ifndef MODE32 + if (ADDREXCEPT (address)) + INTERNALABORT (address); +#endif + dest = ARMul_LoadHalfWord (state, address); + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + UNDEF_LSRBPC; + if (signextend) + if (dest & 1 << (16 - 1)) + dest = (dest & ((1 << 16) - 1)) - (1 << 16); + + WRITEDEST (dest); + ARMul_Icycles (state, 1, 0L); + + //MEM_LOAD_LOG("HALFWORD"); + + return (DESTReg != LHSReg); +} + +#endif /* MODET */ + +/* This function does the work of loading a byte for a LDRB instruction. */ + +static unsigned +LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend) +{ + ARMword dest; + + BUSUSEDINCPCS; +#ifndef MODE32 + if (ADDREXCEPT (address)) + INTERNALABORT (address); +#endif + dest = ARMul_LoadByte (state, address); + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + UNDEF_LSRBPC; + if (signextend) + if (dest & 1 << (8 - 1)) + dest = (dest & ((1 << 8) - 1)) - (1 << 8); + + WRITEDEST (dest); + ARMul_Icycles (state, 1, 0L); + + //MEM_LOAD_LOG("BYTE"); + + return (DESTReg != LHSReg); +} + +/* This function does the work of loading two words for a LDRD instruction. */ + +static void +Handle_Load_Double (ARMul_State * state, ARMword instr) +{ + ARMword dest_reg; + ARMword addr_reg; + ARMword write_back = BIT (21); + ARMword immediate = BIT (22); + ARMword add_to_base = BIT (23); + ARMword pre_indexed = BIT (24); + ARMword offset; + ARMword addr; + ARMword sum; + ARMword base; + ARMword value1; + ARMword value2; + + BUSUSEDINCPCS; + + /* If the writeback bit is set, the pre-index bit must be clear. */ + if (write_back && !pre_indexed) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Extract the base address register. */ + addr_reg = LHSReg; + + /* Extract the destination register and check it. */ + dest_reg = DESTReg; + + /* Destination register must be even. */ + if ((dest_reg & 1) + /* Destination register cannot be LR. */ + || (dest_reg == 14)) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Compute the base address. */ + base = state->Reg[addr_reg]; + + /* Compute the offset. */ + offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> + Reg[RHSReg]; + + /* Compute the sum of the two. */ + if (add_to_base) + sum = base + offset; + else + sum = base - offset; + + /* If this is a pre-indexed mode use the sum. */ + if (pre_indexed) + addr = sum; + else + addr = base; + + /* The address must be aligned on a 8 byte boundary. */ + if (addr & 0x7) { +#ifdef ABORTS + ARMul_DATAABORT (addr); +#else + ARMul_UndefInstr (state, instr); +#endif + return; + } + + /* For pre indexed or post indexed addressing modes, + check that the destination registers do not overlap + the address registers. */ + if ((!pre_indexed || write_back) + && (addr_reg == dest_reg || addr_reg == dest_reg + 1)) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Load the words. */ + value1 = ARMul_LoadWordN (state, addr); + value2 = ARMul_LoadWordN (state, addr + 4); + + /* Check for data aborts. */ + if (state->Aborted) { + TAKEABORT; + return; + } + + ARMul_Icycles (state, 2, 0L); + + /* Store the values. */ + state->Reg[dest_reg] = value1; + state->Reg[dest_reg + 1] = value2; + + /* Do the post addressing and writeback. */ + if (!pre_indexed) + addr = sum; + + if (!pre_indexed || write_back) + state->Reg[addr_reg] = addr; +} + +/* This function does the work of storing two words for a STRD instruction. */ + +static void +Handle_Store_Double (ARMul_State * state, ARMword instr) +{ + ARMword src_reg; + ARMword addr_reg; + ARMword write_back = BIT (21); + ARMword immediate = BIT (22); + ARMword add_to_base = BIT (23); + ARMword pre_indexed = BIT (24); + ARMword offset; + ARMword addr; + ARMword sum; + ARMword base; + + BUSUSEDINCPCS; + + /* If the writeback bit is set, the pre-index bit must be clear. */ + if (write_back && !pre_indexed) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Extract the base address register. */ + addr_reg = LHSReg; + + /* Base register cannot be PC. */ + if (addr_reg == 15) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Extract the source register. */ + src_reg = DESTReg; + + /* Source register must be even. */ + if (src_reg & 1) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Compute the base address. */ + base = state->Reg[addr_reg]; + + /* Compute the offset. */ + offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> + Reg[RHSReg]; + + /* Compute the sum of the two. */ + if (add_to_base) + sum = base + offset; + else + sum = base - offset; + + /* If this is a pre-indexed mode use the sum. */ + if (pre_indexed) + addr = sum; + else + addr = base; + + /* The address must be aligned on a 8 byte boundary. */ + if (addr & 0x7) { +#ifdef ABORTS + ARMul_DATAABORT (addr); +#else + ARMul_UndefInstr (state, instr); +#endif + return; + } + + /* For pre indexed or post indexed addressing modes, + check that the destination registers do not overlap + the address registers. */ + if ((!pre_indexed || write_back) + && (addr_reg == src_reg || addr_reg == src_reg + 1)) { + ARMul_UndefInstr (state, instr); + return; + } + + /* Load the words. */ + ARMul_StoreWordN (state, addr, state->Reg[src_reg]); + ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]); + + if (state->Aborted) { + TAKEABORT; + return; + } + + /* Do the post addressing and writeback. */ + if (!pre_indexed) + addr = sum; + + if (!pre_indexed || write_back) + state->Reg[addr_reg] = addr; +} + +/* This function does the work of storing a word from a STR instruction. */ + +static unsigned +StoreWord (ARMul_State * state, ARMword instr, ARMword address) +{ + //MEM_STORE_LOG("WORD"); + + BUSUSEDINCPCN; +#ifndef MODE32 + if (DESTReg == 15) + state->Reg[15] = ECC | ER15INT | R15PC | EMODE; +#endif +#ifdef MODE32 + ARMul_StoreWordN (state, address, DEST); +#else + if (VECTORACCESS (address) || ADDREXCEPT (address)) { + INTERNALABORT (address); + (void) ARMul_LoadWordN (state, address); + } + else + ARMul_StoreWordN (state, address, DEST); +#endif + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + + return TRUE; +} + +#ifdef MODET +/* This function does the work of storing a byte for a STRH instruction. */ + +static unsigned +StoreHalfWord (ARMul_State * state, ARMword instr, ARMword address) +{ + //MEM_STORE_LOG("HALFWORD"); + + BUSUSEDINCPCN; + +#ifndef MODE32 + if (DESTReg == 15) + state->Reg[15] = ECC | ER15INT | R15PC | EMODE; +#endif + +#ifdef MODE32 + ARMul_StoreHalfWord (state, address, DEST); +#else + if (VECTORACCESS (address) || ADDREXCEPT (address)) { + INTERNALABORT (address); + (void) ARMul_LoadHalfWord (state, address); + } + else + ARMul_StoreHalfWord (state, address, DEST); +#endif + + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + return TRUE; +} + +#endif /* MODET */ + +/* This function does the work of storing a byte for a STRB instruction. */ + +static unsigned +StoreByte (ARMul_State * state, ARMword instr, ARMword address) +{ + //MEM_STORE_LOG("BYTE"); + + BUSUSEDINCPCN; +#ifndef MODE32 + if (DESTReg == 15) + state->Reg[15] = ECC | ER15INT | R15PC | EMODE; +#endif +#ifdef MODE32 + ARMul_StoreByte (state, address, DEST); +#else + if (VECTORACCESS (address) || ADDREXCEPT (address)) { + INTERNALABORT (address); + (void) ARMul_LoadByte (state, address); + } + else + ARMul_StoreByte (state, address, DEST); +#endif + if (state->Aborted) { + TAKEABORT; + return state->lateabtSig; + } + //UNDEF_LSRBPC; + return TRUE; +} + +/* This function does the work of loading the registers listed in an LDM + instruction, when the S bit is clear. The code here is always increment + after, it's up to the caller to get the input address correct and to + handle base register modification. */ + +static void +LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) +{ + ARMword dest, temp; + + //UNDEF_LSMNoRegs; + //UNDEF_LSMPCBase; + //UNDEF_LSMBaseInListWb; + BUSUSEDINCPCS; +#ifndef MODE32 + if (ADDREXCEPT (address)) + INTERNALABORT (address); +#endif +/*chy 2004-05-23 may write twice + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; +*/ + /* N cycle first. */ + for (temp = 0; !BIT (temp); temp++); + + dest = ARMul_LoadWordN (state, address); + + if (!state->abortSig && !state->Aborted) + state->Reg[temp++] = dest; + else if (!state->Aborted) { + XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); + state->Aborted = ARMul_DataAbortV; + } +/*chy 2004-05-23 chy goto end*/ + if (state->Aborted) + goto L_ldm_makeabort; + /* S cycles from here on. */ + for (; temp < 16; temp++) + if (BIT (temp)) { + /* Load this register. */ + address += 4; + dest = ARMul_LoadWordS (state, address); + + if (!state->abortSig && !state->Aborted) + state->Reg[temp] = dest; + else if (!state->Aborted) { + XScale_set_fsr_far (state, + ARMul_CP15_R5_ST_ALIGN, + address); + state->Aborted = ARMul_DataAbortV; + } + /*chy 2004-05-23 chy goto end */ + if (state->Aborted) + goto L_ldm_makeabort; + + } + + if (BIT (15) && !state->Aborted) + /* PC is in the reg list. */ + WriteR15Branch(state, (state->Reg[15] & PCMASK)); + + /* To write back the final register. */ +/* ARMul_Icycles (state, 1, 0L);*/ +/*chy 2004-05-23, see below + if (state->Aborted) + { + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + + TAKEABORT; + } +*/ +/*chy 2004-05-23 should compare the Abort Models*/ + L_ldm_makeabort: + /* To write back the final register. */ + ARMul_Icycles (state, 1, 0L); + + /* chy 2005-11-24, bug found by benjl@cse.unsw.edu.au, etc */ + /* + if (state->Aborted) + { + if (BIT (21) && LHSReg != 15) + if (!(state->abortSig && state->Aborted && state->lateabtSig == LOW)) + LSBase = WBBase; + TAKEABORT; + }else if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + */ + if (state->Aborted) { + if (BIT (21) && LHSReg != 15) { + if (!(state->abortSig)) { + } + } + TAKEABORT; + } + else if (BIT (21) && LHSReg != 15) { + LSBase = WBBase; + } + /* chy 2005-11-24, over */ + +} + +/* This function does the work of loading the registers listed in an LDM + instruction, when the S bit is set. The code here is always increment + after, it's up to the caller to get the input address correct and to + handle base register modification. */ + +static void +LoadSMult (ARMul_State * state, + ARMword instr, ARMword address, ARMword WBBase) +{ + ARMword dest, temp; + + //UNDEF_LSMNoRegs; + //UNDEF_LSMPCBase; + //UNDEF_LSMBaseInListWb; + + BUSUSEDINCPCS; + +#ifndef MODE32 + if (ADDREXCEPT (address)) + INTERNALABORT (address); +#endif +/* chy 2004-05-23, may write twice + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; +*/ + if (!BIT (15) && state->Bank != USERBANK) { + /* Temporary reg bank switch. */ + (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); + UNDEF_LSMUserBankWb; + } + + /* N cycle first. */ + for (temp = 0; !BIT (temp); temp++); + + dest = ARMul_LoadWordN (state, address); + + if (!state->abortSig) + state->Reg[temp++] = dest; + else if (!state->Aborted) { + XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); + state->Aborted = ARMul_DataAbortV; + } + +/*chy 2004-05-23 chy goto end*/ + if (state->Aborted) + goto L_ldm_s_makeabort; + /* S cycles from here on. */ + for (; temp < 16; temp++) + if (BIT (temp)) { + /* Load this register. */ + address += 4; + dest = ARMul_LoadWordS (state, address); + + if (!state->abortSig && !state->Aborted) + state->Reg[temp] = dest; + else if (!state->Aborted) { + XScale_set_fsr_far (state, + ARMul_CP15_R5_ST_ALIGN, + address); + state->Aborted = ARMul_DataAbortV; + } + /*chy 2004-05-23 chy goto end */ + if (state->Aborted) + goto L_ldm_s_makeabort; + } + +/*chy 2004-05-23 label of ldm_s_makeabort*/ + L_ldm_s_makeabort: +/*chy 2004-06-06 LSBase process should be here, not in the end of this function. Because ARMul_CPSRAltered maybe change R13(SP) R14(lr). If not, simulate INSTR ldmia sp!,[....pc]^ error.*/ +/*chy 2004-05-23 should compare the Abort Models*/ + if (state->Aborted) { + if (BIT (21) && LHSReg != 15) + if (! + (state->abortSig && state->Aborted + && state->lateabtSig == LOW)) + LSBase = WBBase; + TAKEABORT; + } + else if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + + if (BIT (15) && !state->Aborted) { + /* PC is in the reg list. */ +#ifdef MODE32 + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode != USER26MODE && state->Mode != USER32MODE ){ + state->Cpsr = GETSPSR (state->Bank); + ARMul_CPSRAltered (state); + } + + WriteR15 (state, (state->Reg[15] & PCMASK)); +#else + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode == USER26MODE || state->Mode == USER32MODE ) { + /* Protect bits in user mode. */ + ASSIGNN ((state->Reg[15] & NBIT) != 0); + ASSIGNZ ((state->Reg[15] & ZBIT) != 0); + ASSIGNC ((state->Reg[15] & CBIT) != 0); + ASSIGNV ((state->Reg[15] & VBIT) != 0); + } + else + ARMul_R15Altered (state); + + FLUSHPIPE; +#endif + } + + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (!BIT (15) && state->Mode != USER26MODE + && state->Mode != USER32MODE ) + /* Restore the correct bank. */ + (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); + + /* To write back the final register. */ + ARMul_Icycles (state, 1, 0L); +/* chy 2004-05-23, see below + if (state->Aborted) + { + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + + TAKEABORT; + } +*/ +} + +/* This function does the work of storing the registers listed in an STM + instruction, when the S bit is clear. The code here is always increment + after, it's up to the caller to get the input address correct and to + handle base register modification. */ + +static void +StoreMult (ARMul_State * state, + ARMword instr, ARMword address, ARMword WBBase) +{ + ARMword temp; + + UNDEF_LSMNoRegs; + UNDEF_LSMPCBase; + UNDEF_LSMBaseInListWb; + + if (!TFLAG) + /* N-cycle, increment the PC and update the NextInstr state. */ + BUSUSEDINCPCN; + +#ifndef MODE32 + if (VECTORACCESS (address) || ADDREXCEPT (address)) + INTERNALABORT (address); + + if (BIT (15)) + PATCHR15; +#endif + + /* N cycle first. */ + for (temp = 0; !BIT (temp); temp++); + +#ifdef MODE32 + ARMul_StoreWordN (state, address, state->Reg[temp++]); +#else + if (state->Aborted) { + (void) ARMul_LoadWordN (state, address); + + /* Fake the Stores as Loads. */ + for (; temp < 16; temp++) + if (BIT (temp)) { + /* Save this register. */ + address += 4; + (void) ARMul_LoadWordS (state, address); + } + + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + TAKEABORT; + return; + } + else + ARMul_StoreWordN (state, address, state->Reg[temp++]); +#endif + + if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); + state->Aborted = ARMul_DataAbortV; + } + +//chy 2004-05-23, needn't store other when aborted + if (state->Aborted) + goto L_stm_takeabort; + + /* S cycles from here on. */ + for (; temp < 16; temp++) + if (BIT (temp)) { + /* Save this register. */ + address += 4; + + ARMul_StoreWordS (state, address, state->Reg[temp]); + + if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far (state, + ARMul_CP15_R5_ST_ALIGN, + address); + state->Aborted = ARMul_DataAbortV; + } + //chy 2004-05-23, needn't store other when aborted + if (state->Aborted) + goto L_stm_takeabort; + + } + +//chy 2004-05-23,should compare the Abort Models + L_stm_takeabort: + if (BIT (21) && LHSReg != 15) { + if (! + (state->abortSig && state->Aborted + && state->lateabtSig == LOW)) + LSBase = WBBase; + } + if (state->Aborted) + TAKEABORT; +} + +/* This function does the work of storing the registers listed in an STM + instruction when the S bit is set. The code here is always increment + after, it's up to the caller to get the input address correct and to + handle base register modification. */ + +static void +StoreSMult (ARMul_State * state, + ARMword instr, ARMword address, ARMword WBBase) +{ + ARMword temp; + + UNDEF_LSMNoRegs; + UNDEF_LSMPCBase; + UNDEF_LSMBaseInListWb; + + BUSUSEDINCPCN; + +#ifndef MODE32 + if (VECTORACCESS (address) || ADDREXCEPT (address)) + INTERNALABORT (address); + + if (BIT (15)) + PATCHR15; +#endif + + if (state->Bank != USERBANK) { + /* Force User Bank. */ + (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); + UNDEF_LSMUserBankWb; + } + + for (temp = 0; !BIT (temp); temp++); /* N cycle first. */ + +#ifdef MODE32 + ARMul_StoreWordN (state, address, state->Reg[temp++]); +#else + if (state->Aborted) { + (void) ARMul_LoadWordN (state, address); + + for (; temp < 16; temp++) + /* Fake the Stores as Loads. */ + if (BIT (temp)) { + /* Save this register. */ + address += 4; + + (void) ARMul_LoadWordS (state, address); + } + + if (BIT (21) && LHSReg != 15) + LSBase = WBBase; + + TAKEABORT; + return; + } + else + ARMul_StoreWordN (state, address, state->Reg[temp++]); +#endif + + if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); + state->Aborted = ARMul_DataAbortV; + } + +//chy 2004-05-23, needn't store other when aborted + if (state->Aborted) + goto L_stm_s_takeabort; + /* S cycles from here on. */ + for (; temp < 16; temp++) + if (BIT (temp)) { + /* Save this register. */ + address += 4; + + ARMul_StoreWordS (state, address, state->Reg[temp]); + + if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far (state, + ARMul_CP15_R5_ST_ALIGN, + address); + state->Aborted = ARMul_DataAbortV; + } + //chy 2004-05-23, needn't store other when aborted + if (state->Aborted) + goto L_stm_s_takeabort; + } + + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode != USER26MODE && state->Mode != USER32MODE ) + /* Restore the correct bank. */ + (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); + + +//chy 2004-05-23,should compare the Abort Models + L_stm_s_takeabort: + if (BIT (21) && LHSReg != 15) { + if (! + (state->abortSig && state->Aborted + && state->lateabtSig == LOW)) + LSBase = WBBase; + } + + if (state->Aborted) + TAKEABORT; +} + +/* This function does the work of adding two 32bit values + together, and calculating if a carry has occurred. */ + +static ARMword +Add32 (ARMword a1, ARMword a2, int *carry) +{ + ARMword result = (a1 + a2); + unsigned int uresult = (unsigned int) result; + unsigned int ua1 = (unsigned int) a1; + + /* If (result == RdLo) and (state->Reg[nRdLo] == 0), + or (result > RdLo) then we have no carry. */ + if ((uresult == ua1) ? (a2 != 0) : (uresult < ua1)) + *carry = 1; + else + *carry = 0; + + return result; +} + +/* This function does the work of multiplying + two 32bit values to give a 64bit result. */ + +static unsigned +Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc) +{ + /* Operand register numbers. */ + int nRdHi, nRdLo, nRs, nRm; + ARMword RdHi = 0, RdLo = 0, Rm; + /* Cycle count. */ + int scount; + + nRdHi = BITS (16, 19); + nRdLo = BITS (12, 15); + nRs = BITS (8, 11); + nRm = BITS (0, 3); + + /* Needed to calculate the cycle count. */ + Rm = state->Reg[nRm]; + + /* Check for illegal operand combinations first. */ + if (nRdHi != 15 + && nRdLo != 15 + && nRs != 15 + //&& nRm != 15 && nRdHi != nRdLo && nRdHi != nRm && nRdLo != nRm) { + && nRm != 15 && nRdHi != nRdLo ) { + /* Intermediate results. */ + ARMword lo, mid1, mid2, hi; + int carry; + ARMword Rs = state->Reg[nRs]; + int sign = 0; + + if (msigned) { + /* Compute sign of result and adjust operands if necessary. */ + sign = (Rm ^ Rs) & 0x80000000; + + if (((signed int) Rm) < 0) + Rm = -Rm; + + if (((signed int) Rs) < 0) + Rs = -Rs; + } + + /* We can split the 32x32 into four 16x16 operations. This + ensures that we do not lose precision on 32bit only hosts. */ + lo = ((Rs & 0xFFFF) * (Rm & 0xFFFF)); + mid1 = ((Rs & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); + mid2 = (((Rs >> 16) & 0xFFFF) * (Rm & 0xFFFF)); + hi = (((Rs >> 16) & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); + + /* We now need to add all of these results together, taking + care to propogate the carries from the additions. */ + RdLo = Add32 (lo, (mid1 << 16), &carry); + RdHi = carry; + RdLo = Add32 (RdLo, (mid2 << 16), &carry); + RdHi += (carry + ((mid1 >> 16) & 0xFFFF) + + ((mid2 >> 16) & 0xFFFF) + hi); + + if (sign) { + /* Negate result if necessary. */ + RdLo = ~RdLo; + RdHi = ~RdHi; + if (RdLo == 0xFFFFFFFF) { + RdLo = 0; + RdHi += 1; + } + else + RdLo += 1; + } + + state->Reg[nRdLo] = RdLo; + state->Reg[nRdHi] = RdHi; + } + else{ + fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS, instr=0x%x\n", instr); + } + if (scc) + /* Ensure that both RdHi and RdLo are used to compute Z, + but don't let RdLo's sign bit make it to N. */ + ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); + + /* The cycle count depends on whether the instruction is a signed or + unsigned multiply, and what bits are clear in the multiplier. */ + if (msigned && (Rm & ((unsigned) 1 << 31))) + /* Invert the bits to make the check against zero. */ + Rm = ~Rm; + + if ((Rm & 0xFFFFFF00) == 0) + scount = 1; + else if ((Rm & 0xFFFF0000) == 0) + scount = 2; + else if ((Rm & 0xFF000000) == 0) + scount = 3; + else + scount = 4; + + return 2 + scount; +} + +/* This function does the work of multiplying two 32bit + values and adding a 64bit value to give a 64bit result. */ + +static unsigned +MultiplyAdd64 (ARMul_State * state, ARMword instr, int msigned, int scc) +{ + unsigned scount; + ARMword RdLo, RdHi; + int nRdHi, nRdLo; + int carry = 0; + + nRdHi = BITS (16, 19); + nRdLo = BITS (12, 15); + + RdHi = state->Reg[nRdHi]; + RdLo = state->Reg[nRdLo]; + + scount = Multiply64 (state, instr, msigned, LDEFAULT); + + RdLo = Add32 (RdLo, state->Reg[nRdLo], &carry); + RdHi = (RdHi + state->Reg[nRdHi]) + carry; + + state->Reg[nRdLo] = RdLo; + state->Reg[nRdHi] = RdHi; + + if (scc) + /* Ensure that both RdHi and RdLo are used to compute Z, + but don't let RdLo's sign bit make it to N. */ + ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); + + /* Extra cycle for addition. */ + return scount + 1; +} + +/* Attempt to emulate an ARMv6 instruction. + Returns non-zero upon success. */ + +static int +handle_v6_insn (ARMul_State * state, ARMword instr) +{ + switch (BITS (20, 27)) + { +#if 0 + case 0x03: printf ("Unhandled v6 insn: ldr\n"); break; + case 0x04: printf ("Unhandled v6 insn: umaal\n"); break; + case 0x06: printf ("Unhandled v6 insn: mls/str\n"); break; + case 0x16: printf ("Unhandled v6 insn: smi\n"); break; + case 0x18: printf ("Unhandled v6 insn: strex\n"); break; + case 0x19: printf ("Unhandled v6 insn: ldrex\n"); break; + case 0x1a: printf ("Unhandled v6 insn: strexd\n"); break; + case 0x1b: printf ("Unhandled v6 insn: ldrexd\n"); break; + case 0x1c: printf ("Unhandled v6 insn: strexb\n"); break; + case 0x1d: printf ("Unhandled v6 insn: ldrexb\n"); break; + case 0x1e: printf ("Unhandled v6 insn: strexh\n"); break; + case 0x1f: printf ("Unhandled v6 insn: ldrexh\n"); break; + case 0x30: printf ("Unhandled v6 insn: movw\n"); break; + case 0x32: printf ("Unhandled v6 insn: nop/sev/wfe/wfi/yield\n"); break; + case 0x34: printf ("Unhandled v6 insn: movt\n"); break; + case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; + case 0x61: printf ("Unhandled v6 insn: sadd/ssub\n"); break; + case 0x62: printf ("Unhandled v6 insn: qadd/qsub\n"); break; + case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break; + case 0x65: printf ("Unhandled v6 insn: uadd/usub\n"); break; + case 0x66: printf ("Unhandled v6 insn: uqadd/uqsub\n"); break; + case 0x67: printf ("Unhandled v6 insn: uhadd/uhsub\n"); break; + case 0x68: printf ("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); break; +#endif + case 0x6c: printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break; + case 0x70: printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break; + case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); break; + case 0x75: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); break; + case 0x78: printf ("Unhandled v6 insn: usad/usada8\n"); break; +#if 0 + case 0x7a: printf ("Unhandled v6 insn: usbfx\n"); break; + case 0x7c: printf ("Unhandled v6 insn: bfc/bfi\n"); break; +#endif + + +/* add new instr for arm v6. */ + ARMword lhs, temp; + case 0x18: /* ORR reg */ + { + /* dyf add armv6 instr strex 2010.9.17 */ + if (BITS (4, 7) == 0x9) { + lhs = LHS; + ARMul_StoreWordS(state, lhs, RHS); + //StoreWord(state, lhs, RHS) + if (state->Aborted) { + TAKEABORT; + } + + return 1; + } + break; + } + + case 0x19: /* orrs reg */ + { + /* dyf add armv6 instr ldrex */ + if (BITS (4, 7) == 0x9) { + lhs = LHS; + LoadWord (state, instr, lhs); + return 1; + } + break; + } + + case 0x1c: /* BIC reg */ + { + /* dyf add for STREXB */ + if (BITS (4, 7) == 0x9) { + lhs = LHS; + ARMul_StoreByte (state, lhs, RHS); + BUSUSEDINCPCN; + if (state->Aborted) { + TAKEABORT; + } + + //printf("In %s, strexb not implemented\n", __FUNCTION__); + UNDEF_LSRBPC; + /* WRITESDEST (dest); */ + return 1; + } + break; + } + + case 0x1d: /* BICS reg */ + { + if ((BITS (4, 7)) == 0x9) { + /* ldrexb */ + temp = LHS; + LoadByte (state, instr, temp, LUNSIGNED); + //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); + //printf("ldrexb\n"); + //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); + //exit(-1); + + //printf("In %s, ldrexb not implemented\n", __FUNCTION__); + return 1; + } + break; + } +/* add end */ + + case 0x6a: + { + ARMword Rm; + int ror = -1; + + switch (BITS (4, 11)) + { + case 0x07: ror = 0; break; + case 0x47: ror = 8; break; + case 0x87: ror = 16; break; + case 0xc7: ror = 24; break; + + case 0x01: + case 0xf3: + printf ("Unhandled v6 insn: ssat\n"); + return 0; + default: + break; + } + + if (ror == -1) + { + if (BITS (4, 6) == 0x7) + { + printf ("Unhandled v6 insn: ssat\n"); + return 0; + } + break; + } + + Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); + if (Rm & 0x80) + Rm |= 0xffffff00; + + if (BITS (16, 19) == 0xf) + /* SXTB */ + state->Reg[BITS (12, 15)] = Rm; + else + /* SXTAB */ + state->Reg[BITS (12, 15)] += Rm; + } + return 1; + + case 0x6b: + { + ARMword Rm; + int ror = -1; + + switch (BITS (4, 11)) + { + case 0x07: ror = 0; break; + case 0x47: ror = 8; break; + case 0x87: ror = 16; break; + case 0xc7: ror = 24; break; + + case 0xf3: + DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); + return 1; + case 0xfb: + DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); + return 1; + default: + break; + } + + if (ror == -1) + break; + + Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); + if (Rm & 0x8000) + Rm |= 0xffff0000; + + if (BITS (16, 19) == 0xf) + /* SXTH */ + state->Reg[BITS (12, 15)] = Rm; + else + /* SXTAH */ + state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; + } + return 1; + + case 0x6e: + { + ARMword Rm; + int ror = -1; + + switch (BITS (4, 11)) + { + case 0x07: ror = 0; break; + case 0x47: ror = 8; break; + case 0x87: ror = 16; break; + case 0xc7: ror = 24; break; + + case 0x01: + case 0xf3: + printf ("Unhandled v6 insn: usat\n"); + return 0; + default: + break; + } + + if (ror == -1) + { + if (BITS (4, 6) == 0x7) + { + printf ("Unhandled v6 insn: usat\n"); + return 0; + } + break; + } + + Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); + + if (BITS (16, 19) == 0xf) + /* UXTB */ + state->Reg[BITS (12, 15)] = Rm; + else + /* UXTAB */ + state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; + } + return 1; + + case 0x6f: + { + ARMword Rm; + int ror = -1; + + switch (BITS (4, 11)) + { + case 0x07: ror = 0; break; + case 0x47: ror = 8; break; + case 0x87: ror = 16; break; + case 0xc7: ror = 24; break; + + case 0xfb: + printf ("Unhandled v6 insn: revsh\n"); + return 0; + default: + break; + } + + if (ror == -1) + break; + + Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); + + /* UXT */ + /* state->Reg[BITS (12, 15)] = Rm; */ + /* dyf add */ + if (BITS (16, 19) == 0xf) { + state->Reg[BITS (12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF; + } else { + /* UXTAH */ + /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */ +// printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] +// , Rm, BITS(10, 11)); +// printf("icounter is %lld\n", state->NumInstrs); + state->Reg[BITS (12, 15)] = (state->Reg[BITS (16, 19)] >> (8 * (BITS(10, 11)))) + Rm; +// printf("rd is %x\n", state->Reg[BITS (12, 15)]); +// exit(-1); + } + } + return 1; + +#if 0 + case 0x84: printf ("Unhandled v6 insn: srs\n"); break; +#endif + default: + break; + } + printf ("Unhandled v6 insn: UNKNOWN: %08x\n", instr); + return 0; +} diff --git a/src/core/arm/interpreter/armemu.h b/src/core/arm/interpreter/armemu.h new file mode 100644 index 00000000..2ab317fd --- /dev/null +++ b/src/core/arm/interpreter/armemu.h @@ -0,0 +1,659 @@ +/* armemu.h -- ARMulator emulation macros: 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. */ +#ifndef __ARMEMU_H__ +#define __ARMEMU_H__ + +#include "common.h" +#include "armdefs.h" +//#include "skyeye.h" + +extern ARMword isize; + +/* Condition code values. */ +#define EQ 0 +#define NE 1 +#define CS 2 +#define CC 3 +#define MI 4 +#define PL 5 +#define VS 6 +#define VC 7 +#define HI 8 +#define LS 9 +#define GE 10 +#define LT 11 +#define GT 12 +#define LE 13 +#define AL 14 +#define NV 15 + +/* Shift Opcodes. */ +#define LSL 0 +#define LSR 1 +#define ASR 2 +#define ROR 3 + +/* Macros to twiddle the status flags and mode. */ +#define NBIT ((unsigned)1L << 31) +#define ZBIT (1L << 30) +#define CBIT (1L << 29) +#define VBIT (1L << 28) +#define SBIT (1L << 27) +#define IBIT (1L << 7) +#define FBIT (1L << 6) +#define IFBITS (3L << 6) +#define R15IBIT (1L << 27) +#define R15FBIT (1L << 26) +#define R15IFBITS (3L << 26) + +#define POS(i) ( (~(i)) >> 31 ) +#define NEG(i) ( (i) >> 31 ) + +#ifdef MODET /* Thumb support. */ +/* ??? This bit is actually in the low order bit of the PC in the hardware. + It isn't clear if the simulator needs to model that or not. */ +#define TBIT (1L << 5) +#define TFLAG state->TFlag +#define SETT state->TFlag = 1 +#define CLEART state->TFlag = 0 +#define ASSIGNT(res) state->TFlag = res +#define INSN_SIZE (TFLAG ? 2 : 4) +#else +#define TBIT (1L << 5) +#define INSN_SIZE 4 +#define TFLAG 0 +#endif + +/*add armv6 CPSR feature*/ +#define EFLAG state->EFlag +#define SETE state->EFlag = 1 +#define CLEARE state->EFlag = 0 +#define ASSIGNE(res) state->NFlag = res + +#define AFLAG state->AFlag +#define SETA state->AFlag = 1 +#define CLEARA state->AFlag = 0 +#define ASSIGNA(res) state->NFlag = res + +#define QFLAG state->QFlag +#define SETQ state->QFlag = 1 +#define CLEARQ state->AFlag = 0 +#define ASSIGNQ(res) state->QFlag = res + +/* add end */ + +#define NFLAG state->NFlag +#define SETN state->NFlag = 1 +#define CLEARN state->NFlag = 0 +#define ASSIGNN(res) state->NFlag = res + +#define ZFLAG state->ZFlag +#define SETZ state->ZFlag = 1 +#define CLEARZ state->ZFlag = 0 +#define ASSIGNZ(res) state->ZFlag = res + +#define CFLAG state->CFlag +#define SETC state->CFlag = 1 +#define CLEARC state->CFlag = 0 +#define ASSIGNC(res) state->CFlag = res + +#define VFLAG state->VFlag +#define SETV state->VFlag = 1 +#define CLEARV state->VFlag = 0 +#define ASSIGNV(res) state->VFlag = res + +#define SFLAG state->SFlag +#define SETS state->SFlag = 1 +#define CLEARS state->SFlag = 0 +#define ASSIGNS(res) state->SFlag = res + +#define IFLAG (state->IFFlags >> 1) +#define FFLAG (state->IFFlags & 1) +#define IFFLAGS state->IFFlags +#define ASSIGNINT(res) state->IFFlags = (((res) >> 6) & 3) +#define ASSIGNR15INT(res) state->IFFlags = (((res) >> 26) & 3) ; + +#define PSR_FBITS (0xff000000L) +#define PSR_SBITS (0x00ff0000L) +#define PSR_XBITS (0x0000ff00L) +#define PSR_CBITS (0x000000ffL) + +#if defined MODE32 || defined MODET +#define CCBITS (0xf8000000L) +#else +#define CCBITS (0xf0000000L) +#endif + +#define INTBITS (0xc0L) + +#if defined MODET && defined MODE32 +#define PCBITS (0xffffffffL) +#else +#define PCBITS (0xfffffffcL) +#endif + +#define MODEBITS (0x1fL) +#define R15INTBITS (3L << 26) + +#if defined MODET && defined MODE32 +#define R15PCBITS (0x03ffffffL) +#else +#define R15PCBITS (0x03fffffcL) +#endif + +#define R15PCMODEBITS (0x03ffffffL) +#define R15MODEBITS (0x3L) + +#ifdef MODE32 +#define PCMASK PCBITS +#define PCWRAP(pc) (pc) +#else +#define PCMASK R15PCBITS +#define PCWRAP(pc) ((pc) & R15PCBITS) +#endif + +#define R15CCINTMODE (state->Reg[15] & (CCBITS | R15INTBITS | R15MODEBITS)) +#define R15INT (state->Reg[15] & R15INTBITS) +#define R15INTPC (state->Reg[15] & (R15INTBITS | R15PCBITS)) +#define R15INTPCMODE (state->Reg[15] & (R15INTBITS | R15PCBITS | R15MODEBITS)) +#define R15INTMODE (state->Reg[15] & (R15INTBITS | R15MODEBITS)) +#define R15PC (state->Reg[15] & R15PCBITS) +#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS)) +#define R15MODE (state->Reg[15] & R15MODEBITS) + +#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27)) +#define EINT (IFFLAGS << 6) +#define ER15INT (IFFLAGS << 26) +#define EMODE (state->Mode) + +//#ifdef MODET +//#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) +//#else +//#define CPSR (ECC | EINT | EMODE) +//#endif + +#ifdef MODE32 +#define PATCHR15 +#else +#define PATCHR15 state->Reg[15] = ECC | ER15INT | EMODE | R15PC +#endif + +#define GETSPSR(bank) (ARMul_GetSPSR (state, EMODE)) +#define SETPSR_F(d,s) d = ((d) & ~PSR_FBITS) | ((s) & PSR_FBITS) +#define SETPSR_S(d,s) d = ((d) & ~PSR_SBITS) | ((s) & PSR_SBITS) +#define SETPSR_X(d,s) d = ((d) & ~PSR_XBITS) | ((s) & PSR_XBITS) +#define SETPSR_C(d,s) d = ((d) & ~PSR_CBITS) | ((s) & PSR_CBITS) + +#define SETR15PSR(s) \ + do \ + { \ + if (state->Mode == USER26MODE) \ + { \ + state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE; \ + ASSIGNN ((state->Reg[15] & NBIT) != 0); \ + ASSIGNZ ((state->Reg[15] & ZBIT) != 0); \ + ASSIGNC ((state->Reg[15] & CBIT) != 0); \ + ASSIGNV ((state->Reg[15] & VBIT) != 0); \ + } \ + else \ + { \ + state->Reg[15] = R15PC | ((s) & (CCBITS | R15INTBITS | R15MODEBITS)); \ + ARMul_R15Altered (state); \ + } \ + } \ + while (0) + +#define SETABORT(i, m, d) \ + do \ + { \ + int SETABORT_mode = (m); \ + \ + ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \ + ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \ + | (i) | SETABORT_mode)); \ + state->Reg[14] = temp - (d); \ + } \ + while (0) + +//#ifndef MODE32 +#define VECTORS 0x20 +#define LEGALADDR 0x03ffffff +#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig) +#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig) +//#endif + +#define INTERNALABORT(address) \ + do \ + { \ + if (address < VECTORS) \ + state->Aborted = ARMul_DataAbortV; \ + else \ + state->Aborted = ARMul_AddrExceptnV; \ + } \ + while (0) + +#ifdef MODE32 +#define TAKEABORT ARMul_Abort (state, ARMul_DataAbortV) +#else +#define TAKEABORT \ + do \ + { \ + if (state->Aborted == ARMul_AddrExceptnV) \ + ARMul_Abort (state, ARMul_AddrExceptnV); \ + else \ + ARMul_Abort (state, ARMul_DataAbortV); \ + } \ + while (0) +#endif + +#define CPTAKEABORT \ + do \ + { \ + if (!state->Aborted) \ + ARMul_Abort (state, ARMul_UndefinedInstrV); \ + else if (state->Aborted == ARMul_AddrExceptnV) \ + ARMul_Abort (state, ARMul_AddrExceptnV); \ + else \ + ARMul_Abort (state, ARMul_DataAbortV); \ + } \ + while (0); + + +/* Different ways to start the next instruction. */ +#define SEQ 0 +#define NONSEQ 1 +#define PCINCEDSEQ 2 +#define PCINCEDNONSEQ 3 +#define PRIMEPIPE 4 +#define RESUME 8 + +/************************************/ +/* shenoubang 2012-3-11 */ +/* for armv7 DBG DMB DSB instr*/ +/************************************/ +#define MBReqTypes_Writes 0 +#define MBReqTypes_All 1 + +#define NORMALCYCLE state->NextInstr = 0 +#define BUSUSEDN state->NextInstr |= 1 /* The next fetch will be an N cycle. */ +#define BUSUSEDINCPCS \ + do \ + { \ + if (! state->is_v4) \ + { \ + /* A standard PC inc and an S cycle. */ \ + state->Reg[15] += isize; \ + state->NextInstr = (state->NextInstr & 0xff) | 2; \ + } \ + } \ + while (0) + +#define BUSUSEDINCPCN \ + do \ + { \ + if (state->is_v4) \ + BUSUSEDN; \ + else \ + { \ + /* A standard PC inc and an N cycle. */ \ + state->Reg[15] += isize; \ + state->NextInstr |= 3; \ + } \ + } \ + while (0) + +#define INCPC \ + do \ + { \ + /* A standard PC inc. */ \ + state->Reg[15] += isize; \ + state->NextInstr |= 2; \ + } \ + while (0) + +#define FLUSHPIPE state->NextInstr |= PRIMEPIPE + +/* Cycle based emulation. */ + +#define OUTPUTCP(i,a,b) +#define NCYCLE +#define SCYCLE +#define ICYCLE +#define CCYCLE +#define NEXTCYCLE(c) + +/* Macros to extract parts of instructions. */ +#define DESTReg (BITS (12, 15)) +#define LHSReg (BITS (16, 19)) +#define RHSReg (BITS ( 0, 3)) + +#define DEST (state->Reg[DESTReg]) + +#ifdef MODE32 +#ifdef MODET +#define LHS ((LHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[LHSReg])) +#define RHS ((RHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[RHSReg])) +#else +#define LHS (state->Reg[LHSReg]) +#define RHS (state->Reg[RHSReg]) +#endif +#else +#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg])) +#define RHS ((RHSReg == 15) ? R15PC : (state->Reg[RHSReg])) +#endif + +#define MULDESTReg (BITS (16, 19)) +#define MULLHSReg (BITS ( 0, 3)) +#define MULRHSReg (BITS ( 8, 11)) +#define MULACCReg (BITS (12, 15)) + +#define DPImmRHS (ARMul_ImmedTable[BITS(0, 11)]) +#define DPSImmRHS temp = BITS(0,11) ; \ + rhs = ARMul_ImmedTable[temp] ; \ + if (temp > 255) /* There was a shift. */ \ + ASSIGNC (rhs >> 31) ; + +#ifdef MODE32 +#define DPRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ + : GetDPRegRHS (state, instr)) +#define DPSRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ + : GetDPSRegRHS (state, instr)) +#else +#define DPRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ + : GetDPRegRHS (state, instr)) +#define DPSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ + : GetDPSRegRHS (state, instr)) +#endif + +#define LSBase state->Reg[LHSReg] +#define LSImmRHS (BITS(0,11)) + +#ifdef MODE32 +#define LSRegRHS ((BITS (4, 11) == 0) ? state->Reg[RHSReg] \ + : GetLSRegRHS (state, instr)) +#else +#define LSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ + : GetLSRegRHS (state, instr)) +#endif + +#define LSMNumRegs ((ARMword) ARMul_BitList[BITS (0, 7)] + \ + (ARMword) ARMul_BitList[BITS (8, 15)] ) +#define LSMBaseFirst ((LHSReg == 0 && BIT (0)) || \ + (BIT (LHSReg) && BITS (0, LHSReg - 1) == 0)) + +#define SWAPSRC (state->Reg[RHSReg]) + +#define LSCOff (BITS (0, 7) << 2) +#define CPNum BITS (8, 11) + +/* Determine if access to coprocessor CP is permitted. + The XScale has a register in CP15 which controls access to CP0 - CP13. */ +//chy 2003-09-03, new CP_ACCESS_ALLOWED +/* +#define CP_ACCESS_ALLOWED(STATE, CP) \ + ( ((CP) >= 14) \ + || (! (STATE)->is_XScale) \ + || (read_cp15_reg (15, 0, 1) & (1 << (CP)))) +*/ +//#define CP_ACCESS_ALLOWED(STATE, CP) \ +// (((CP) >= 14) \ +// || (!(STATE)->is_XScale) \ +// || (xscale_cp15_cp_access_allowed(STATE, 15, CP))) + +#define CP_ACCESS_ALLOWED(STATE, CP) false // Disabled coprocessor shit /bunnei + +/* Macro to rotate n right by b bits. */ +#define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) + +/* Macros to store results of instructions. */ +#define WRITEDEST(d) \ + do \ + { \ + if (DESTReg == 15) \ + WriteR15 (state, d); \ + else \ + DEST = d; \ + } \ + while (0) + +#define WRITESDEST(d) \ + do \ + { \ + if (DESTReg == 15) \ + WriteSR15 (state, d); \ + else \ + { \ + DEST = d; \ + ARMul_NegZero (state, d); \ + } \ + } \ + while (0) + +#define WRITEDESTB(d) \ + do \ + { \ + if (DESTReg == 15){ \ + WriteR15Branch (state, d); \ + } \ + else{ \ + DEST = d; \ + } \ + } \ + while (0) + +#define BYTETOBUS(data) ((data & 0xff) | \ + ((data & 0xff) << 8) | \ + ((data & 0xff) << 16) | \ + ((data & 0xff) << 24)) + +#define BUSTOBYTE(address, data) \ + do \ + { \ + if (state->bigendSig) \ + temp = (data >> (((address ^ 3) & 3) << 3)) & 0xff; \ + else \ + temp = (data >> ((address & 3) << 3)) & 0xff; \ + } \ + while (0) + +#define LOADMULT(instr, address, wb) LoadMult (state, instr, address, wb) +#define LOADSMULT(instr, address, wb) LoadSMult (state, instr, address, wb) +#define STOREMULT(instr, address, wb) StoreMult (state, instr, address, wb) +#define STORESMULT(instr, address, wb) StoreSMult (state, instr, address, wb) + +#define POSBRANCH ((instr & 0x7fffff) << 2) +#define NEGBRANCH ((0xff000000 |(instr & 0xffffff)) << 2) + + +/* Values for Emulate. */ +#define STOP 0 /* stop */ +#define CHANGEMODE 1 /* change mode */ +#define ONCE 2 /* execute just one interation */ +#define RUN 3 /* continuous execution */ + +/* Stuff that is shared across modes. */ +extern unsigned ARMul_MultTable[]; /* Number of I cycles for a mult. */ +extern ARMword ARMul_ImmedTable[]; /* Immediate DP LHS values. */ +extern char ARMul_BitList[]; /* Number of bits in a byte table. */ + +#define EVENTLISTSIZE 1024L + +/* Thumb support. */ +typedef enum +{ + t_undefined, /* Undefined Thumb instruction. */ + t_decoded, /* Instruction decoded to ARM equivalent. */ + t_branch /* Thumb branch (already processed). */ +} +tdstate; + +/********************************************************************************* + * Check all the possible undef or unpredict behavior, Some of them probably is + * out-of-updated with the newer ISA. + * -- Michael.Kang + ********************************************************************************/ +#define UNDEF_WARNING ERROR_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n"); + +/* Macros to scrutinize instructions. */ +#define UNDEF_Test UNDEF_WARNING +//#define UNDEF_Test + +//#define UNDEF_Shift UNDEF_WARNING +#define UNDEF_Shift + +//#define UNDEF_MSRPC UNDEF_WARNING +#define UNDEF_MSRPC + +//#define UNDEF_MRSPC UNDEF_WARNING +#define UNDEF_MRSPC + +#define UNDEF_MULPCDest UNDEF_WARNING +//#define UNDEF_MULPCDest + +#define UNDEF_MULDestEQOp1 UNDEF_WARNING +//#define UNDEF_MULDestEQOp1 + +//#define UNDEF_LSRBPC UNDEF_WARNING +#define UNDEF_LSRBPC + +//#define UNDEF_LSRBaseEQOffWb UNDEF_WARNING +#define UNDEF_LSRBaseEQOffWb + +//#define UNDEF_LSRBaseEQDestWb UNDEF_WARNING +#define UNDEF_LSRBaseEQDestWb + +//#define UNDEF_LSRPCBaseWb UNDEF_WARNING +#define UNDEF_LSRPCBaseWb + +//#define UNDEF_LSRPCOffWb UNDEF_WARNING +#define UNDEF_LSRPCOffWb + +//#define UNDEF_LSMNoRegs UNDEF_WARNING +#define UNDEF_LSMNoRegs + +//#define UNDEF_LSMPCBase UNDEF_WARNING +#define UNDEF_LSMPCBase + +//#define UNDEF_LSMUserBankWb UNDEF_WARNING +#define UNDEF_LSMUserBankWb + +//#define UNDEF_LSMBaseInListWb UNDEF_WARNING +#define UNDEF_LSMBaseInListWb + +#define UNDEF_SWPPC UNDEF_WARNING +//#define UNDEF_SWPPC + +#define UNDEF_CoProHS UNDEF_WARNING +//#define UNDEF_CoProHS + +#define UNDEF_MCRPC UNDEF_WARNING +//#define UNDEF_MCRPC + +//#define UNDEF_LSCPCBaseWb UNDEF_WARNING +#define UNDEF_LSCPCBaseWb + +#define UNDEF_UndefNotBounced UNDEF_WARNING +//#define UNDEF_UndefNotBounced + +#define UNDEF_ShortInt UNDEF_WARNING +//#define UNDEF_ShortInt + +#define UNDEF_IllegalMode UNDEF_WARNING +//#define UNDEF_IllegalMode + +#define UNDEF_Prog32SigChange UNDEF_WARNING +//#define UNDEF_Prog32SigChange + +#define UNDEF_Data32SigChange UNDEF_WARNING +//#define UNDEF_Data32SigChange + +/* Prototypes for exported functions. */ +extern unsigned ARMul_NthReg (ARMword, unsigned); +extern int AddOverflow (ARMword, ARMword, ARMword); +extern int SubOverflow (ARMword, ARMword, ARMword); +/* Prototypes for exported functions. */ +#ifdef __cplusplus + extern "C" { +#endif +extern ARMword ARMul_Emulate26 (ARMul_State *); +extern ARMword ARMul_Emulate32 (ARMul_State *); +#ifdef __cplusplus + } +#endif +extern unsigned IntPending (ARMul_State *); +extern void ARMul_CPSRAltered (ARMul_State *); +extern void ARMul_R15Altered (ARMul_State *); +extern ARMword ARMul_GetPC (ARMul_State *); +extern ARMword ARMul_GetNextPC (ARMul_State *); +extern ARMword ARMul_GetR15 (ARMul_State *); +extern ARMword ARMul_GetCPSR (ARMul_State *); +extern void ARMul_EnvokeEvent (ARMul_State *); +extern unsigned int ARMul_Time (ARMul_State *); +extern void ARMul_NegZero (ARMul_State *, ARMword); +extern void ARMul_SetPC (ARMul_State *, ARMword); +extern void ARMul_SetR15 (ARMul_State *, ARMword); +extern void ARMul_SetCPSR (ARMul_State *, ARMword); +extern ARMword ARMul_GetSPSR (ARMul_State *, ARMword); +extern void ARMul_Abort26 (ARMul_State *, ARMword); +extern void ARMul_Abort32 (ARMul_State *, ARMword); +extern ARMword ARMul_MRC (ARMul_State *, ARMword); +extern void ARMul_MRRC (ARMul_State *, ARMword, ARMword *, ARMword *); +extern void ARMul_CDP (ARMul_State *, ARMword); +extern void ARMul_LDC (ARMul_State *, ARMword, ARMword); +extern void ARMul_STC (ARMul_State *, ARMword, ARMword); +extern void ARMul_MCR (ARMul_State *, ARMword, ARMword); +extern void ARMul_MCRR (ARMul_State *, ARMword, ARMword, ARMword); +extern void ARMul_SetSPSR (ARMul_State *, ARMword, ARMword); +extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); +extern ARMword ARMul_Align (ARMul_State *, ARMword, ARMword); +extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); +extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); +extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); +extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); +extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); +extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); +extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); +extern ARMword ARMul_GetReg (ARMul_State *, unsigned, unsigned); +extern void ARMul_SetReg (ARMul_State *, unsigned, unsigned, ARMword); +extern void ARMul_ScheduleEvent (ARMul_State *, unsigned int, + unsigned (*)(ARMul_State *)); +/* Coprocessor support functions. */ +extern unsigned 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); +extern ARMword read_cp15_reg (unsigned, unsigned, unsigned); + +extern unsigned DSPLDC4 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMCR4 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC4 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPSTC4 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP4 (ARMul_State *, unsigned, ARMword); +extern unsigned DSPMCR5 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC5 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPLDC5 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPSTC5 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP5 (ARMul_State *, unsigned, ARMword); +extern unsigned DSPMCR6 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC6 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP6 (ARMul_State *, unsigned, ARMword); + + +#endif diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp new file mode 100644 index 00000000..f48232ee --- /dev/null +++ b/src/core/arm/interpreter/arminit.cpp @@ -0,0 +1,579 @@ +/* arminit.c -- ARMulator initialization: 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. */ + + +#include "platform.h" +#if EMU_PLATFORM == PLATFORM_LINUX +#include +#endif + +#include + +#include "armdefs.h" +#include "armemu.h" + +/***************************************************************************\ +* Definitions for the emulator architecture * +\***************************************************************************/ + +void ARMul_EmulateInit (void); +ARMul_State *ARMul_NewState (ARMul_State * state); +void ARMul_Reset (ARMul_State * state); +ARMword ARMul_DoCycle (ARMul_State * state); +unsigned ARMul_DoCoPro (ARMul_State * state); +ARMword ARMul_DoProg (ARMul_State * state); +ARMword ARMul_DoInstr (ARMul_State * state); +void ARMul_Abort (ARMul_State * state, ARMword address); + +unsigned ARMul_MultTable[32] = + { 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16 +}; +ARMword ARMul_ImmedTable[4096]; /* immediate DP LHS values */ +char ARMul_BitList[256]; /* number of bits in a byte table */ + +//chy 2006-02-22 add test debugmode +extern int debugmode; +extern int remote_interrupt( void ); + + +void arm_dyncom_Abort(ARMul_State * state, ARMword vector) +{ + ARMul_Abort(state, vector); +} + + +/* ahe-ykl : the following code to initialize user mode + code is architecture dependent and probably model dependant. */ + +//#include "skyeye_arch.h" +//#include "skyeye_pref.h" +//#include "skyeye_exec_info.h" +//#include "bank_defs.h" +#include "armcpu.h" +//#include "skyeye_callback.h" + +//void arm_user_mode_init(generic_arch_t * arch_instance) +//{ +// sky_pref_t *pref = get_skyeye_pref(); +// +// if (pref->user_mode_sim) +// { +// sky_exec_info_t *info = get_skyeye_exec_info(); +// info->arch_page_size = 0x1000; +// info->arch_stack_top = 0x1ffffff0;// + 0x401fe7 - 0xff0; /* arbitrary value */ +// /* stack initial address specific to architecture may be placed here */ +// +// /* we need to mmap the stack space, if we are using skyeye space */ +// if (info->mmap_access) +// { +// /* get system stack size */ +// size_t stacksize = 0; +// pthread_attr_t attr; +// pthread_attr_init(&attr); +// pthread_attr_getstacksize(&attr, &stacksize); +// if (stacksize > info->arch_stack_top) +// { +// printf("arch_stack_top is too low\n"); +// stacksize = info->arch_stack_top; +// } +// +// /* Note: Skyeye is occupating 0x400000 to 0x600000 */ +// /* We do a mmap */ +// void* ret = mmap( (info->arch_stack_top) - stacksize, +// stacksize + 0x1000 , PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +// if (ret == MAP_FAILED){ +// /* ideally, we should find an empty space until it works */ +// printf("mmap error, stack couldn't be mapped: errno %d\n", errno); +// exit(-1); +// } else { +// memset(ret, '\0', stacksize); +// //printf("stack top has been defined at %x size %x\n", (uint32_t) ret + stacksize, stacksize); +// //info->arch_stack_top = (uint32_t) ret + stacksize; +// } +// } +// +// exec_stack_init(); +// +// ARM_CPU_State* cpu = get_current_cpu(); +// arm_core_t* core = &cpu->core[0]; +// +// uint32_t sp = info->initial_sp; +// +// core->Cpsr = 0x10; /* User mode */ +// /* FIXME: may need to add thumb */ +// core->Reg[13] = sp; +// core->Reg[10] = info->start_data; +// core->Reg[0] = 0; +// bus_read(32, sp + 4, &(core->Reg[1])); +// bus_read(32, sp + 8, &(core->Reg[2])); +// } +// +//} + +/***************************************************************************\ +* Call this routine once to set up the emulator's tables. * +\***************************************************************************/ + +void +ARMul_EmulateInit (void) +{ + unsigned int i, j; + + for (i = 0; i < 4096; i++) { /* the values of 12 bit dp rhs's */ + ARMul_ImmedTable[i] = ROTATER (i & 0xffL, (i >> 7L) & 0x1eL); + } + + for (i = 0; i < 256; ARMul_BitList[i++] = 0); /* how many bits in LSM */ + for (j = 1; j < 256; j <<= 1) + for (i = 0; i < 256; i++) + if ((i & j) > 0) + ARMul_BitList[i]++; + + for (i = 0; i < 256; i++) + ARMul_BitList[i] *= 4; /* you always need 4 times these values */ + +} + +/***************************************************************************\ +* Returns a new instantiation of the ARMulator's state * +\***************************************************************************/ + +ARMul_State * +ARMul_NewState (ARMul_State *state) +{ + unsigned i, j; + + memset (state, 0, sizeof (ARMul_State)); + + state->Emulate = RUN; + for (i = 0; i < 16; i++) { + state->Reg[i] = 0; + for (j = 0; j < 7; j++) + state->RegBank[j][i] = 0; + } + for (i = 0; i < 7; i++) + state->Spsr[i] = 0; + state->Mode = 0; + + state->CallDebug = FALSE; + state->Debug = FALSE; + state->VectorCatch = 0; + state->Aborted = FALSE; + state->Reseted = FALSE; + state->Inted = 3; + state->LastInted = 3; + + state->CommandLine = NULL; + + state->EventSet = 0; + state->Now = 0; + state->EventPtr = + (struct EventNode **) malloc ((unsigned) EVENTLISTSIZE * + sizeof (struct EventNode *)); +#if DIFF_STATE + state->state_log = fopen("/data/state.log", "w"); + printf("create pc log file.\n"); +#endif + if (state->EventPtr == NULL) { + printf ("SKYEYE: ARMul_NewState malloc state->EventPtr error\n"); + exit(-1); + } + for (i = 0; i < EVENTLISTSIZE; i++) + *(state->EventPtr + i) = NULL; +#if SAVE_LOG + state->state_log = fopen("/tmp/state.log", "w"); + printf("create pc log file.\n"); +#else +#if DIFF_LOG + state->state_log = fopen("/tmp/state.log", "r"); + printf("loaded pc log file.\n"); +#endif +#endif + +#ifdef ARM61 + state->prog32Sig = LOW; + state->data32Sig = LOW; +#else + state->prog32Sig = HIGH; + state->data32Sig = HIGH; +#endif + + state->lateabtSig = HIGH; + state->bigendSig = LOW; + + //chy:2003-08-19 + state->LastTime = 0; + state->CP14R0_CCD = -1; + + /* ahe-ykl: common function for interpret and dyncom */ + //sky_pref_t *pref = get_skyeye_pref(); + //if (pref->user_mode_sim) + // register_callback(arm_user_mode_init, Bootmach_callback); + + memset(&state->exclusive_tag_array[0], 0xFF, sizeof(state->exclusive_tag_array[0]) * 128); + state->exclusive_access_state = 0; + //state->cpu = (cpu_config_t *) malloc (sizeof (cpu_config_t)); + //state->mem_bank = (mem_config_t *) malloc (sizeof (mem_config_t)); + return (state); +} + +/***************************************************************************\ +* Call this routine to set ARMulator to model a certain processor * +\***************************************************************************/ + +void +ARMul_SelectProcessor (ARMul_State * state, unsigned properties) +{ + if (properties & ARM_Fix26_Prop) { + state->prog32Sig = LOW; + state->data32Sig = LOW; + } + else { + state->prog32Sig = HIGH; + state->data32Sig = HIGH; + } +/* 2004-05-09 chy +below line sould be in skyeye_mach_XXX.c 's XXX_mach_init function +*/ + // state->lateabtSig = HIGH; + + + state->is_v4 = + (properties & (ARM_v4_Prop | ARM_v5_Prop)) ? HIGH : LOW; + state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW; + state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW; + state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW; + state->is_iWMMXt = (properties & ARM_iWMMXt_Prop) ? HIGH : LOW; + /* state->is_v6 = LOW */; + /* jeff.du 2010-08-05 */ + state->is_v6 = (properties & ARM_v6_Prop) ? HIGH : LOW; + state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW; + //chy 2005-09-19 + state->is_pxa27x = (properties & ARM_PXA27X_Prop) ? HIGH : LOW; + + /* shenoubang 2012-3-11 */ + state->is_v7 = (properties & ARM_v7_Prop) ? HIGH : LOW; + + /* Only initialse the coprocessor support once we + know what kind of chip we are dealing with. */ + //ARMul_CoProInit (state); Commented out /bunnei + +} + +/***************************************************************************\ +* Call this routine to set up the initial machine state (or perform a RESET * +\***************************************************************************/ + +void +ARMul_Reset (ARMul_State * state) +{ + //fprintf(stderr,"armul_reset 0: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + state->NextInstr = 0; + if (state->prog32Sig) { + state->Reg[15] = 0; + state->Cpsr = INTBITS | SVC32MODE; + state->Mode = SVC32MODE; + } + else { + state->Reg[15] = R15INTBITS | SVC26MODE; + state->Cpsr = INTBITS | SVC26MODE; + state->Mode = SVC26MODE; + } + //fprintf(stderr,"armul_reset 1: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + ARMul_CPSRAltered (state); + state->Bank = SVCBANK; + FLUSHPIPE; + + state->EndCondition = 0; + state->ErrorCode = 0; + + //fprintf(stderr,"armul_reset 2: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + 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; + state->NumNcycles = 0; + state->NumScycles = 0; + state->NumIcycles = 0; + state->NumCcycles = 0; + state->NumFcycles = 0; + + //fprintf(stderr,"armul_reset 3: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + //mmu_reset (state); Commented out /bunnei + //fprintf(stderr,"armul_reset 4: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + + //mem_reset (state); /* move to memory/ram.c */ + + //fprintf(stderr,"armul_reset 5: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); + /*remove later. walimis 03.7.17 */ + //io_reset(state); + //lcd_disable(state); + + /*ywc 2005-04-07 move from ARMul_NewState , because skyeye_config.no_dbct will + *be configured in skyeye_option_init and it is called after ARMul_NewState*/ + state->tea_break_ok = 0; + state->tea_break_addr = 0; + state->tea_pc = 0; +#ifdef DBCT + if (!skyeye_config.no_dbct) { + //teawater add for arm2x86 2005.02.14------------------------------------------- + if (arm2x86_init (state)) { + printf ("SKYEYE: arm2x86_init error\n"); + skyeye_exit (-1); + } + //AJ2D-------------------------------------------------------------------------- + } +#endif +} + + +/***************************************************************************\ +* Emulate the execution of an entire program. Start the correct emulator * +* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * +* address of the last instruction that is executed. * +\***************************************************************************/ + +//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- +#ifdef DBCT_TEST_SPEED +static ARMul_State *dbct_test_speed_state = NULL; +static void +dbct_test_speed_sig(int signo) +{ + printf("\n0x%llx %llu\n", dbct_test_speed_state->instr_count, dbct_test_speed_state->instr_count); + skyeye_exit(0); +} +#endif //DBCT_TEST_SPEED +//AJ2D-------------------------------------------------------------------------- + +ARMword +ARMul_DoProg (ARMul_State * state) +{ + ARMword pc = 0; + + /* + * 2007-01-24 removed the term-io functions by Anthony Lee, + * moved to "device/uart/skyeye_uart_stdio.c". + */ + +//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- +#ifdef DBCT_TEST_SPEED + { + if (!dbct_test_speed_state) { + //init timer + struct itimerval value; + struct sigaction act; + + dbct_test_speed_state = state; + state->instr_count = 0; + act.sa_handler = dbct_test_speed_sig; + act.sa_flags = SA_RESTART; + //cygwin don't support ITIMER_VIRTUAL or ITIMER_PROF +#ifndef __CYGWIN__ + if (sigaction(SIGVTALRM, &act, NULL) == -1) { +#else + if (sigaction(SIGALRM, &act, NULL) == -1) { +#endif //__CYGWIN__ + fprintf(stderr, "init timer error.\n"); + skyeye_exit(-1); + } + if (skyeye_config.dbct_test_speed_sec) { + value.it_value.tv_sec = skyeye_config.dbct_test_speed_sec; + } + else { + value.it_value.tv_sec = DBCT_TEST_SPEED_SEC; + } + printf("dbct_test_speed_sec = %ld\n", value.it_value.tv_sec); + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; +#ifndef __CYGWIN__ + if (setitimer(ITIMER_VIRTUAL, &value, NULL) == -1) { +#else + if (setitimer(ITIMER_REAL, &value, NULL) == -1) { +#endif //__CYGWIN__ + fprintf(stderr, "init timer error.\n"); + skyeye_exit(-1); + } + } + } +#endif //DBCT_TEST_SPEED +//AJ2D-------------------------------------------------------------------------- + state->Emulate = RUN; + while (state->Emulate != STOP) { + state->Emulate = RUN; + + /*ywc 2005-03-31 */ + if (state->prog32Sig && ARMul_MODE32BIT) { +#ifdef DBCT + if (skyeye_config.no_dbct) { + pc = ARMul_Emulate32 (state); + } + else { + pc = ARMul_Emulate32_dbct (state); + } +#else + pc = ARMul_Emulate32 (state); +#endif + } + + else { + _dbg_assert_msg_(ARM11, false, "Unsupported ARM 26-bit Mode!"); + } + //chy 2006-02-22, should test debugmode first + //chy 2006-04-14, put below codes in ARMul_Emulate +#if 0 + if(debugmode) + if(remote_interrupt()) + state->Emulate = STOP; +#endif + } + + /* + * 2007-01-24 removed the term-io functions by Anthony Lee, + * moved to "device/uart/skyeye_uart_stdio.c". + */ + + return (pc); +} + +/***************************************************************************\ +* Emulate the execution of one instruction. Start the correct emulator * +* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * +* address of the instruction that is executed. * +\***************************************************************************/ + +ARMword +ARMul_DoInstr (ARMul_State * state) +{ + ARMword pc = 0; + + state->Emulate = ONCE; + + /*ywc 2005-03-31 */ + if (state->prog32Sig && ARMul_MODE32BIT) { +#ifdef DBCT + if (skyeye_config.no_dbct) { + pc = ARMul_Emulate32 (state); + } + else { +//teawater add compile switch for DBCT GDB RSP function 2005.10.21-------------- +#ifndef DBCT_GDBRSP + printf("DBCT GDBRSP function switch is off.\n"); + printf("To use this function, open \"#define DBCT_GDBRSP\" in arch/arm/common/armdefs.h & recompile skyeye.\n"); + skyeye_exit(-1); +#endif //DBCT_GDBRSP +//AJ2D-------------------------------------------------------------------------- + pc = ARMul_Emulate32_dbct (state); + } +#else + pc = ARMul_Emulate32 (state); +#endif + } + + else { + _dbg_assert_msg_(ARM11, false, "Unsupported ARM 26-bit Mode!"); + } + + return (pc); +} + +/***************************************************************************\ +* This routine causes an Abort to occur, including selecting the correct * +* mode, register bank, and the saving of registers. Call with the * +* appropriate vector's memory address (0,4,8 ....) * +\***************************************************************************/ + +void +ARMul_Abort (ARMul_State * state, ARMword vector) +{ + ARMword temp; + int isize = INSN_SIZE; + int esize = (TFLAG ? 0 : 4); + int e2size = (TFLAG ? -4 : 0); + + state->Aborted = FALSE; + + if (state->prog32Sig) + if (ARMul_MODE26BIT) + temp = R15PC; + else + temp = state->Reg[15]; + else + temp = R15PC | ECC | ER15INT | EMODE; + + switch (vector) { + case ARMul_ResetV: /* RESET */ + SETABORT (INTBITS, state->prog32Sig ? SVC32MODE : SVC26MODE, + 0); + break; + case ARMul_UndefinedInstrV: /* Undefined Instruction */ + SETABORT (IBIT, state->prog32Sig ? UNDEF32MODE : SVC26MODE, + isize); + break; + case ARMul_SWIV: /* Software Interrupt */ + SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE, + isize); + break; + case ARMul_PrefetchAbortV: /* Prefetch Abort */ + state->AbortAddr = 1; + SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, + esize); + break; + case ARMul_DataAbortV: /* Data Abort */ + SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, + e2size); + break; + case ARMul_AddrExceptnV: /* Address Exception */ + SETABORT (IBIT, SVC26MODE, isize); + break; + case ARMul_IRQV: /* IRQ */ + //chy 2003-09-02 the if sentence seems no use +#if 0 + if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) + || (temp & ARMul_CP13_R0_IRQ)) +#endif + SETABORT (IBIT, + state->prog32Sig ? IRQ32MODE : IRQ26MODE, + esize); + break; + case ARMul_FIQV: /* FIQ */ + //chy 2003-09-02 the if sentence seems no use +#if 0 + if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) + || (temp & ARMul_CP13_R0_FIQ)) +#endif + SETABORT (INTBITS, + state->prog32Sig ? FIQ32MODE : FIQ26MODE, + esize); + break; + } + + if (ARMul_MODE32BIT) { + if (state->mmu.control & CONTROL_VECTOR) + vector += 0xffff0000; //for v4 high exception address + if (state->vector_remap_flag) + vector += state->vector_remap_addr; /* support some remap function in LPC processor */ + ARMul_SetR15 (state, vector); + } + else + ARMul_SetR15 (state, R15CCINTMODE | vector); +} diff --git a/src/core/arm/interpreter/armmmu.cpp b/src/core/arm/interpreter/armmmu.cpp new file mode 100644 index 00000000..242e6a83 --- /dev/null +++ b/src/core/arm/interpreter/armmmu.cpp @@ -0,0 +1,238 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + 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 +#include +#include "armdefs.h" +/* two header for arm disassemble */ +//#include "skyeye_arch.h" +#include "armcpu.h" + + +extern mmu_ops_t xscale_mmu_ops; +exception_t arm_mmu_write(short size, u32 addr, uint32_t *value); +exception_t arm_mmu_read(short size, u32 addr, uint32_t *value); +#define MMU_OPS (state->mmu.ops) +ARMword skyeye_cachetype = -1; + +int +mmu_init (ARMul_State * state) +{ + int ret; + + state->mmu.control = 0x70; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + + switch (state->cpu->cpu_val & state->cpu->cpu_mask) { + //case SA1100: + //case SA1110: + // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n"); + // state->mmu.ops = sa_mmu_ops; + // break; + //case PXA250: + //case PXA270: //xscale + // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n"); + // state->mmu.ops = xscale_mmu_ops; + // break; + //case 0x41807200: //arm720t + //case 0x41007700: //arm7tdmi + //case 0x41007100: //arm7100 + // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n"); + // state->mmu.ops = arm7100_mmu_ops; + // break; + //case 0x41009200: + // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n"); + // state->mmu.ops = arm920t_mmu_ops; + // break; + //case 0x41069260: + // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n"); + // state->mmu.ops = arm926ejs_mmu_ops; + // break; + /* case 0x560f5810: */ + case 0x0007b000: + NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n"); + state->mmu.ops = arm1176jzf_s_mmu_ops; + break; + + default: + ERROR_LOG (ARM11, + "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n", + state->cpu->cpu_val & state->cpu->cpu_mask); + break; + + }; + ret = state->mmu.ops.init (state); + state->mmu_inited = (ret == 0); + /* initialize mmu_read and mmu_write for disassemble */ + //skyeye_config_t *config = get_current_config(); + //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); + //arch_instance->mmu_read = arm_mmu_read; + //arch_instance->mmu_write = arm_mmu_write; + + return ret; +} + +int +mmu_reset (ARMul_State * state) +{ + if (state->mmu_inited) + mmu_exit (state); + return mmu_init (state); +} + +void +mmu_exit (ARMul_State * state) +{ + MMU_OPS.exit (state); + state->mmu_inited = 0; +} + +fault_t +mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + return MMU_OPS.read_byte (state, virt_addr, data); +}; + +fault_t +mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + return MMU_OPS.read_halfword (state, virt_addr, data); +}; + +fault_t +mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + return MMU_OPS.read_word (state, virt_addr, data); +}; + +fault_t +mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + fault_t fault; + //static int count = 0; + //count ++; + fault = MMU_OPS.write_byte (state, virt_addr, data); + return fault; +} + +fault_t +mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + fault_t fault; + //static int count = 0; + //count ++; + fault = MMU_OPS.write_halfword (state, virt_addr, data); + return fault; +} + +fault_t +mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + fault_t fault; + fault = MMU_OPS.write_word (state, virt_addr, data); + + /*used for debug for MMU* + + if (!fault){ + ARMword tmp; + + if (mmu_read_word(state, virt_addr, &tmp)){ + err_msg("load back\n"); + exit(-1); + }else{ + if (tmp != data){ + err_msg("load back not equal %d %x\n", count, virt_addr); + } + } + } + */ + + return fault; +}; + +fault_t +mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr) +{ + return MMU_OPS.load_instr (state, virt_addr, instr); +} + +ARMword +mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) +{ + return MMU_OPS.mrc (state, instr, value); +} + +void +mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) +{ + MMU_OPS.mcr (state, instr, value); +} + +/*ywc 20050416*/ +int +mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) +{ + return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr)); +} + +// +// +///* dis_mmu_read for disassemble */ +//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value) +//{ +// ARMul_State *state; +// ARM_CPU_State *cpu = get_current_cpu(); +// state = &cpu->core[0]; +// switch(size){ +// case 8: +// MMU_OPS.read_byte (state, addr, value); +// break; +// case 16: +// case 32: +// break; +// default: +// ERROR_LOG(ARM11, "Error size %d", size); +// break; +// } +// return No_exp; +//} +///* dis_mmu_write for disassemble */ +//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value) +//{ +// ARMul_State *state; +// ARM_CPU_State *cpu = get_current_cpu(); +// state = &cpu->core[0]; +// switch(size){ +// case 8: +// MMU_OPS.write_byte (state, addr, value); +// break; +// case 16: +// case 32: +// break; +// default: +// printf("In %s error size %d Line %d\n", __func__, size, __LINE__); +// break; +// } +// return No_exp; +//} diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/interpreter/armmmu.h new file mode 100644 index 00000000..c28d8753 --- /dev/null +++ b/src/core/arm/interpreter/armmmu.h @@ -0,0 +1,254 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + 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 +*/ + +#ifndef _ARMMMU_H_ +#define _ARMMMU_H_ + + +#define WORD_SHT 2 +#define WORD_SIZE (1<mmu.control) +#define MMU_Enabled (state->mmu.control & CONTROL_MMU) +#define MMU_Disabled (!(MMU_Enabled)) +#define MMU_Aligned (state->mmu.control & CONTROL_ALIGN_FAULT) + +#define MMU_ICacheEnabled (MMU_CTL & CONTROL_INSTRUCTION_CACHE) +#define MMU_ICacheDisabled (!(MMU_ICacheDisabled)) + +#define MMU_DCacheEnabled (MMU_CTL & CONTROL_DATA_CACHE) +#define MMU_DCacheDisabled (!(MMU_DCacheEnabled)) + +#define MMU_CacheEnabled (MMU_CTL & CONTROL_CACHE) +#define MMU_CacheDisabled (!(MMU_CacheEnabled)) + +#define MMU_WBEnabled (MMU_CTL & CONTROL_WRITE_BUFFER) +#define MMU_WBDisabled (!(MMU_WBEnabled)) + +/*virt_addr exchange according to CP15.R13(process id virtul mapping)*/ +#define PID_VA_MAP_MASK 0xfe000000 +//#define mmu_pid_va_map(va) ({\ +// ARMword ret; \ +// if ((va) & PID_VA_MAP_MASK)\ +// ret = (va); \ +// else \ +// ret = ((va) | (state->mmu.process_id & PID_VA_MAP_MASK));\ +// ret;\ +//}) +#define mmu_pid_va_map(va) ((va) & PID_VA_MAP_MASK) ? (va) : ((va) | (state->mmu.process_id & PID_VA_MAP_MASK)) + +/* FS[3:0] in the fault status register: */ + +typedef enum fault_t +{ + NO_FAULT = 0x0, + ALIGNMENT_FAULT = 0x1, + + SECTION_TRANSLATION_FAULT = 0x5, + PAGE_TRANSLATION_FAULT = 0x7, + SECTION_DOMAIN_FAULT = 0x9, + PAGE_DOMAIN_FAULT = 0xB, + SECTION_PERMISSION_FAULT = 0xD, + SUBPAGE_PERMISSION_FAULT = 0xF, + + /* defined by skyeye */ + TLB_READ_MISS = 0x30, + TLB_WRITE_MISS = 0x40, + +} fault_t; + +typedef struct mmu_ops_s +{ + /*initilization */ + int (*init) (ARMul_State * state); + /*free on exit */ + void (*exit) (ARMul_State * state); + /*read byte data */ + fault_t (*read_byte) (ARMul_State * state, ARMword va, + ARMword * data); + /*write byte data */ + fault_t (*write_byte) (ARMul_State * state, ARMword va, + ARMword data); + /*read halfword data */ + fault_t (*read_halfword) (ARMul_State * state, ARMword va, + ARMword * data); + /*write halfword data */ + fault_t (*write_halfword) (ARMul_State * state, ARMword va, + ARMword data); + /*read word data */ + fault_t (*read_word) (ARMul_State * state, ARMword va, + ARMword * data); + /*write word data */ + fault_t (*write_word) (ARMul_State * state, ARMword va, + ARMword data); + /*load instr */ + fault_t (*load_instr) (ARMul_State * state, ARMword va, + ARMword * instr); + /*mcr */ + ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val); + /*mrc */ + ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val); + + /*ywc 2005-04-16 convert virtual address to physics address */ + int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr, + ARMword * phys_addr); +} mmu_ops_t; + + +#include "arm/mmu/tlb.h" +#include "arm/mmu/rb.h" +#include "arm/mmu/wb.h" +#include "arm/mmu/cache.h" + +/*special process mmu.h*/ +//#include "arm/mmu/sa_mmu.h" +//#include "arm/mmu/arm7100_mmu.h" +//#include "arm/mmu/arm920t_mmu.h" +//#include "arm/mmu/arm926ejs_mmu.h" +#include "arm/mmu/arm1176jzf_s_mmu.h" +//#include "arm/mmu/cortex_a9_mmu.h" + +typedef struct mmu_state_t +{ + ARMword control; + ARMword translation_table_base; +/* dyf 201-08-11 for arm1176 */ + ARMword auxiliary_control; + ARMword coprocessor_access_control; + ARMword translation_table_base0; + ARMword translation_table_base1; + ARMword translation_table_ctrl; +/* arm1176 end */ + + ARMword domain_access_control; + ARMword fault_status; + ARMword fault_statusi; /* prefetch fault status */ + ARMword fault_address; + ARMword last_domain; + ARMword process_id; + ARMword context_id; + ARMword thread_uro_id; + ARMword cache_locked_down; + ARMword tlb_locked_down; +//chy 2003-08-24 for xscale + ARMword cache_type; // 0 + ARMword aux_control; // 1 + ARMword copro_access; // 15 + + mmu_ops_t ops; + //union + //{ + //sa_mmu_t sa_mmu; + //arm7100_mmu_t arm7100_mmu; + //arm920t_mmu_t arm920t_mmu; + //arm926ejs_mmu_t arm926ejs_mmu; + //} u; +} mmu_state_t; + +int mmu_init (ARMul_State * state); +int mmu_reset (ARMul_State * state); +void mmu_exit (ARMul_State * state); + +fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr, + ARMword * data); +fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); +fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr, + ARMword * instr); + +ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); +void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); + +/*ywc 20050416*/ +int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, + ARMword * phys_addr); + +fault_t +mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data); +fault_t +mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data); +fault_t +mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data); +fault_t +mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data); +fault_t +mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data); +fault_t +mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); +#endif /* _ARMMMU_H_ */ diff --git a/src/core/arm/interpreter/armos.cpp b/src/core/arm/interpreter/armos.cpp new file mode 100644 index 00000000..43484ee5 --- /dev/null +++ b/src/core/arm/interpreter/armos.cpp @@ -0,0 +1,742 @@ +/* armos.c -- ARMulator OS interface: 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. */ + +/* This file contains a model of Demon, ARM Ltd's Debug Monitor, +including all the SWI's required to support the C library. The code in +it is not really for the faint-hearted (especially the abort handling +code), but it is a complete example. Defining NOOS will disable all the +fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI +0x11 to halt the emulator. */ + +//chy 2005-09-12 disable below line +//#include "config.h" + +#include +#include +#include +#include "skyeye_defs.h" +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/ +#endif +#include +#include + + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_WRONLY +#define O_WRONLY 1 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef __STDC__ +#define unlink(s) remove(s) +#endif + +#ifdef HAVE_UNISTD_H +#include /* For SEEK_SET etc */ +#endif + +#ifdef __riscos +extern int _fisatty (FILE *); +#define isatty_(f) _fisatty(f) +#else +#ifdef __ZTC__ +#include +#define isatty_(f) isatty((f)->_file) +#else +#ifdef macintosh +#include +#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL)) +#else +#define isatty_(f) isatty (fileno (f)) +#endif +#endif +#endif + +#include "armdefs.h" +#include "armos.h" +#include "armemu.h" + +#ifndef NOOS +#ifndef VALIDATE +/* #ifndef ASIM */ +//chy 2005-09-12 disable below line +//#include "armfpe.h" +/* #endif */ +#endif +#endif + +#define DUMP_SYSCALL 0 +#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0) +//#define debug(...) printf(__VA_ARGS__); +#define debug(...) ; + +extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); + +#ifndef FOPEN_MAX +#define FOPEN_MAX 64 +#endif + +/***************************************************************************\ +* OS private Information * +\***************************************************************************/ + +unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number) +{ + return ARMul_OSHandleSWI(state, number); +} + +//mmap_area_t *mmap_global = NULL; + +static int translate_open_mode[] = { + O_RDONLY, /* "r" */ + O_RDONLY + O_BINARY, /* "rb" */ + O_RDWR, /* "r+" */ + O_RDWR + O_BINARY, /* "r+b" */ + O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ + O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ + O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ + O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ + O_WRONLY + O_APPEND + O_CREAT, /* "a" */ + O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ + O_RDWR + O_APPEND + O_CREAT, /* "a+" */ + O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ +}; +// +//static void +//SWIWrite0 (ARMul_State * state, ARMword addr) +//{ +// ARMword temp; +// +// //while ((temp = ARMul_ReadByte (state, addr++)) != 0) +// while(1){ +// mem_read(8, addr++, &temp); +// if(temp != 0) +// (void) fputc ((char) temp, stdout); +// else +// break; +// } +//} +// +//static void +//WriteCommandLineTo (ARMul_State * state, ARMword addr) +//{ +// ARMword temp; +// char *cptr = state->CommandLine; +// if (cptr == NULL) +// cptr = "\0"; +// do { +// temp = (ARMword) * cptr++; +// //ARMul_WriteByte (state, addr++, temp); +// mem_write(8, addr++, temp); +// } +// while (temp != 0); +//} +// +//static void +//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) +//{ +// char dummy[2000]; +// int flags; +// int i; +// +// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++); +// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0]))); +// /* Now we need to decode the Demon open mode */ +// flags = translate_open_mode[SWIflags]; +// flags = SWIflags; +// +// /* Filename ":tt" is special: it denotes stdin/out */ +// if (strcmp (dummy, ":tt") == 0) { +// if (flags == O_RDONLY) /* opening tty "r" */ +// state->Reg[0] = 0; /* stdin */ +// else +// state->Reg[0] = 1; /* stdout */ +// } +// else { +// state->Reg[0] = (int) open (dummy, flags, 0666); +// } +//} +// +//static void +//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) +//{ +// int res; +// int i; +// char *local = (char*) malloc (len); +// +// if (local == NULL) { +// fprintf (stderr, +// "sim: Unable to read 0x%ulx bytes - out of memory\n", +// len); +// return; +// } +// +// res = read (f, local, len); +// if (res > 0) +// for (i = 0; i < res; i++) +// //ARMul_WriteByte (state, ptr + i, local[i]); +// mem_write(8, ptr + i, local[i]); +// free (local); +// //state->Reg[0] = res == -1 ? -1 : len - res; +// state->Reg[0] = res; +//} +// +//static void +//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) +//{ +// int res; +// ARMword i; +// char *local = malloc (len); +// +// if (local == NULL) { +// fprintf (stderr, +// "sim: Unable to write 0x%lx bytes - out of memory\n", +// (long unsigned int) len); +// return; +// } +// +// for (i = 0; i < len; i++){ +// //local[i] = ARMul_ReadByte (state, ptr + i); +// ARMword data; +// mem_read(8, ptr + i, &data); +// local[i] = data & 0xFF; +// } +// +// res = write (f, local, len); +// //state->Reg[0] = res == -1 ? -1 : len - res; +// state->Reg[0] = res; +// free (local); +//} + +//static void +//SWIflen (ARMul_State * state, ARMword fh) +//{ +// ARMword addr; +// +// if (fh == 0 || fh > FOPEN_MAX) { +// state->Reg[0] = -1L; +// return; +// } +// +// addr = lseek (fh, 0, SEEK_CUR); +// +// state->Reg[0] = lseek (fh, 0L, SEEK_END); +// (void) lseek (fh, addr, SEEK_SET); +// +//} + +/***************************************************************************\ +* The emulator calls this routine when a SWI instruction is encuntered. The * +* parameter passed is the SWI number (lower 24 bits of the instruction). * +\***************************************************************************/ +/* ahe-ykl information is retrieved from elf header and the starting value of + brk_static is in sky_info_t */ + +/* brk static hold the value of brk */ +static uint32_t brk_static = -1; + +unsigned +ARMul_OSHandleSWI (ARMul_State * state, ARMword number) +{ + number &= 0xfffff; + ARMword addr, temp; + + switch (number) { +// case SWI_Syscall: +// if (state->Reg[7] != 0) +// return ARMul_OSHandleSWI(state, state->Reg[7]); +// else +// return FALSE; +// case SWI_Read: +// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); +// return TRUE; +// +// case SWI_GetUID32: +// state->Reg[0] = getuid(); +// return TRUE; +// +// case SWI_GetGID32: +// state->Reg[0] = getgid(); +// return TRUE; +// +// case SWI_GetEUID32: +// state->Reg[0] = geteuid(); +// return TRUE; +// +// case SWI_GetEGID32: +// state->Reg[0] = getegid(); +// return TRUE; +// +// case SWI_Write: +// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); +// return TRUE; +// +// case SWI_Open: +// SWIopen (state, state->Reg[0], state->Reg[1]); +// return TRUE; +// +// case SWI_Close: +// state->Reg[0] = close (state->Reg[0]); +// return TRUE; +// +// case SWI_Seek:{ +// /* We must return non-zero for failure */ +// state->Reg[0] = +// lseek (state->Reg[0], state->Reg[1], +// SEEK_SET); +// return TRUE; +// } +// +// case SWI_ExitGroup: +// case SWI_Exit: +// { +// struct timeval tv; +// //gettimeofday(&tv,NULL); +// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec); +// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us()); +// +// /* quit here */ +// run_command("quit"); +// return TRUE; +// } +// case SWI_Times:{ +// uint32_t dest = state->Reg[0]; +// struct tms now; +// struct target_tms32 nowret; +// +// uint32_t ret = times(&now); +// +// if (ret == -1){ +// debug("syscall %s error %d\n", "SWI_Times", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// nowret.tms_cstime = now.tms_cstime; +// nowret.tms_cutime = now.tms_cutime; +// nowret.tms_stime = now.tms_stime; +// nowret.tms_utime = now.tms_utime; +// +// uint32_t offset; +// for (offset = 0; offset < sizeof(nowret); offset++) { +// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset)); +// } +// +// state->Reg[0] = ret; +// return TRUE; +// } +// +// case SWI_Gettimeofday: { +// uint32_t dest1 = state->Reg[0]; +// uint32_t dest2 = state->Reg[1]; // Unsure of this +// struct timeval val; +// struct timezone zone; +// struct target_timeval32 valret; +// struct target_timezone32 zoneret; +// +// uint32_t ret = gettimeofday(&val, &zone); +// valret.tv_sec = val.tv_sec; +// valret.tv_usec = val.tv_usec; +// zoneret.tz_dsttime = zoneret.tz_dsttime; +// zoneret.tz_minuteswest = zoneret.tz_minuteswest; +// +// if (ret == -1){ +// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// uint32_t offset; +// if (dest1) { +// for (offset = 0; offset < sizeof(valret); offset++) { +// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset)); +// } +// state->Reg[0] = ret; +// } +// if (dest2) { +// for (offset = 0; offset < sizeof(zoneret); offset++) { +// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset)); +// } +// state->Reg[0] = ret; +// } +// +// return TRUE; +// } +// case SWI_Brk: +// /* initialize brk value */ +// /* suppose that brk_static doesn't reach 0xffffffff... */ +// if (brk_static == -1) { +// brk_static = (get_skyeye_pref()->info).brk; +// } +// +// /* FIXME there might be a need to do a mmap */ +// +// if(state->Reg[0]){ +// if (get_skyeye_exec_info()->mmap_access) { +// /* if new brk is greater than current brk, allocate memory */ +// if (state->Reg[0] > brk_static) { +// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static, +// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 ); +// if (ret != MAP_FAILED) +// brk_static = ret; +// } +// } +// brk_static = state->Reg[0]; +// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */ +// } else { +// state->Reg[0] = brk_static; +// } +// return TRUE; +// +// case SWI_Break: +// state->Emulate = FALSE; +// return TRUE; +// +// case SWI_Mmap:{ +// int addr = state->Reg[0]; +// int len = state->Reg[1]; +// int prot = state->Reg[2]; +// int flag = state->Reg[3]; +// int fd = state->Reg[4]; +// int offset = state->Reg[5]; +// mmap_area_t *area = new_mmap_area(addr, len); +// state->Reg[0] = area->bank.addr; +// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\ +// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]); +// return TRUE; +// } +// +// case SWI_Munmap: +// state->Reg[0] = 0; +// return TRUE; +// +// case SWI_Mmap2:{ +// int addr = state->Reg[0]; +// int len = state->Reg[1]; +// int prot = state->Reg[2]; +// int flag = state->Reg[3]; +// int fd = state->Reg[4]; +// int offset = state->Reg[5] * 4096; /* page offset */ +// mmap_area_t *area = new_mmap_area(addr, len); +// state->Reg[0] = area->bank.addr; +// +// return TRUE; +// } +// +// case SWI_Breakpoint: +// //chy 2005-09-12 change below line +// //state->EndCondition = RDIError_BreakpointReached; +// //printf ("SKYEYE: in armos.c : should not come here!!!!\n"); +// state->EndCondition = 0; +// /*modified by ksh to support breakpoiont*/ +// state->Emulate = STOP; +// return (TRUE); +// case SWI_Uname: +// { +// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */ +// struct utsname utsbuf; +// //printf("Uname size is %x\n", sizeof(utsbuf)); +// char *buf; +// uintptr_t sp ; /* used as a temporary address */ +// +//#define COPY_UTS_STRING(addr) \ +// buf = addr; \ +// while(*buf != NULL) { \ +// bus_write(8, sp, *buf); \ +// sp++; \ +// buf++; \ +// } +//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \ +// sp = (uintptr_t) uts->field; \ +// COPY_UTS_STRING((&utsbuf)->field); +// +// if (uname(&utsbuf) < 0) { +// printf("syscall uname: utsname error\n"); +// state->Reg[0] = -1; +// return FALSE; +// } +// +// /* FIXME for now, this is just the host system call +// Some data should be missing, as it depends on +// the version of utsname */ +// COPY_UTS(sysname); +// COPY_UTS(nodename); +// COPY_UTS(release); +// COPY_UTS(version); +// COPY_UTS(machine); +// +// state->Reg[0] = 0; +// return TRUE; +// } +// case SWI_Fcntl: +// { +// uint32_t fd = state->Reg[0]; +// uint32_t cmd = state->Reg[1]; +// uint32_t arg = state->Reg[2]; +// uint32_t ret; +// +// switch(cmd){ +// case (F_GETFD): +// { +// ret = fcntl(fd, cmd, arg); +// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// default: +// break; +// } +// +// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd); +// state->Reg[0] = -1; +// return FALSE; +// +// } +// case SWI_Fstat64: +// { +// uint32_t dest = state->Reg[1]; +// uint32_t fd = state->Reg[0]; +// struct stat64 statbuf; +// struct target_stat64 statret; +// memset(&statret, 0, sizeof(struct target_stat64)); +// uint32_t ret = fstat64(fd, &statbuf); +// +// if (ret == -1){ +// printf("syscall %s returned error\n", "SWI_Fstat"); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// /* copy statbuf to the process memory space +// FIXME can't say if endian has an effect here */ +// uint32_t offset; +// //printf("Fstat system is size %x\n", sizeof(statbuf)); +// //printf("Fstat target is size %x\n", sizeof(statret)); +// +// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */ +// statret.st_dev = statbuf.st_dev; +// statret.st_ino = statbuf.st_ino; +// statret.st_mode = statbuf.st_mode; +// statret.st_nlink = statbuf.st_nlink; +// statret.st_uid = statbuf.st_uid; +// statret.st_gid = statbuf.st_gid; +// statret.st_rdev = statbuf.st_rdev; +// statret.st_size = statbuf.st_size; +// statret.st_blksize = statbuf.st_blksize; +// statret.st_blocks = statbuf.st_blocks; +// statret.st32_atime = statbuf.st_atime; +// statret.st32_mtime = statbuf.st_mtime; +// statret.st32_ctime = statbuf.st_ctime; +// +// for (offset = 0; offset < sizeof(statret); offset++) { +// bus_write(8, dest + offset, *((uint8_t *) &statret + offset)); +// } +// +// state->Reg[0] = ret; +// return TRUE; +// } +// case SWI_Set_tls: +// { +// //printf("syscall set_tls unimplemented\n"); +// state->mmu.thread_uro_id = state->Reg[0]; +// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0]; +// state->Reg[0] = 0; +// return FALSE; +// } +//#if 0 +// case SWI_Clock: +// /* return number of centi-seconds... */ +// state->Reg[0] = +//#ifdef CLOCKS_PER_SEC +// (CLOCKS_PER_SEC >= 100) +// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) +// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); +//#else +// /* presume unix... clock() returns microseconds */ +// (ARMword) (clock () / 10000); +//#endif +// return (TRUE); +// +// case SWI_Time: +// state->Reg[0] = (ARMword) time (NULL); +// return (TRUE); +// case SWI_Flen: +// SWIflen (state, state->Reg[0]); +// return (TRUE); +// +//#endif + default: + + _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!"); + + return (FALSE); + } +} +// +///** +// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc. +// */ +//static mmap_area_t* new_mmap_area(int sim_addr, int len){ +// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t)); +// if(area == NULL){ +// printf("error, failed %s\n",__FUNCTION__); +// exit(0); +// } +//#if FAST_MEMORY +// if (mmap_next_base == -1) +// { +// mmap_next_base = get_skyeye_exec_info()->brk; +// } +//#endif +// +// memset(area, 0x0, sizeof(mmap_area_t)); +// area->bank.addr = mmap_next_base; +// area->bank.len = len; +// area->bank.bank_write = mmap_mem_write; +// area->bank.bank_read = mmap_mem_read; +// area->bank.type = MEMTYPE_RAM; +// area->bank.objname = "mmap"; +// addr_mapping(&area->bank); +// +//#if FAST_MEMORY +// if (get_skyeye_exec_info()->mmap_access) +// { +// /* FIXME check proper flags */ +// /* FIXME we may delete the need of banks up there */ +// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +// mmap_next_base = ret; +// } +// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base); +//#else +// area->mmap_addr = malloc(len); +// if(area->mmap_addr == NULL){ +// printf("error mmap malloc\n"); +// exit(0); +// } +// memset(area->mmap_addr, 0x0, len); +//#endif +// +// area->next = NULL; +// if(mmap_global){ +// area->next = mmap_global->next; +// mmap_global->next = area; +// }else{ +// mmap_global = area; +// } +// mmap_next_base = mmap_next_base + len; +// return area; +//} +// +//static mmap_area_t *get_mmap_area(int addr){ +// mmap_area_t *tmp = mmap_global; +// while(tmp){ +// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){ +// return tmp; +// } +// tmp = tmp->next; +// } +// printf("cannot get mmap area:addr=0x%x\n", addr); +// return NULL; +//} +// +///** +// * @brief the mmap_area bank write function. Get from ppc. +// * +// * @param size size to write, 8/16/32 +// * @param addr address to write +// * @param value value to write +// * +// * @return sucess return 1,otherwise 0. +// */ +//static char mmap_mem_write(short size, int addr, uint32_t value){ +// mmap_area_t *area_tmp = get_mmap_area(addr); +// mem_bank_t *bank_tmp = &area_tmp->bank; +// int offset = addr - bank_tmp->addr; +// switch(size){ +// case 8:{ +// //uint8_t value_endian = value; +// uint8_t value_endian = (uint8_t)value; +// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// case 16:{ +// //uint16_t value_endian = half_to_BE((uint16_t)value); +// uint16_t value_endian = ((uint16_t)value); +// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// case 32:{ +// //uint32_t value_endian = word_to_BE((uint32_t)value); +// uint32_t value_endian = ((uint32_t)value); +// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// default: +// printf("invalid size %d\n",size); +// return 0; +// } +// return 1; +//} +// +///** +// * @brief the mmap_area bank read function. Get from ppc. +// * +// * @param size size to read, 8/16/32 +// * @param addr address to read +// * @param value value to read +// * +// * @return sucess return 1,otherwise 0. +// */ +//static char mmap_mem_read(short size, int addr, uint32_t * value){ +// mmap_area_t *area_tmp = get_mmap_area(addr); +// mem_bank_t *bank_tmp = &area_tmp->bank; +// int offset = addr - bank_tmp->addr; +// switch(size){ +// case 8:{ +// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); +// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); +// break; +// } +// case 16:{ +// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value); +// break; +// } +// case 32: +// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); +// break; +// default: +// printf("invalid size %d\n",size); +// return 0; +// } +// return 1; +//} diff --git a/src/core/arm/interpreter/armos.h b/src/core/arm/interpreter/armos.h new file mode 100644 index 00000000..4b58801a --- /dev/null +++ b/src/core/arm/interpreter/armos.h @@ -0,0 +1,138 @@ +/* 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. */ + +//#include "bank_defs.h" +//#include "dyncom/defines.h" + +//typedef struct mmap_area{ +// mem_bank_t bank; +// void *mmap_addr; +// struct mmap_area *next; +//}mmap_area_t; + +#if FAST_MEMORY +/* in user mode, mmap_base will be on initial brk, + set at the first mmap request */ +#define mmap_base -1 +#else +#define mmap_base 0x50000000 +#endif +static long mmap_next_base = mmap_base; + +//static mmap_area_t* new_mmap_area(int sim_addr, int len); +static char mmap_mem_write(short size, int addr, uint32_t value); +static char mmap_mem_read(short size, int addr, uint32_t * value); + +/***************************************************************************\ +* 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 + +#if 0 +#define SWI_Time 0xd +#define SWI_Clock 0x61 +#define SWI_Time 0x63 +#define SWI_Remove 0x64 +#define SWI_Rename 0x65 +#define SWI_Flen 0x6c +#endif + +#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 */ + +/***************************************************************************\ +* SWI structures * +\***************************************************************************/ + +/* Arm binaries (for now) only support 32 bit, and expect to receive + 32-bit compliant structure in return of a systen call. Because + we use host system calls to emulate system calls, the returned + structure can be 32-bit compliant or 64-bit compliant, depending + on the OS running skyeye. Therefore, we need a fixed size structure + adapted to arm.*/ + +/* Borrowed from qemu */ +struct target_stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + uint32_t __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + uint32_t st_uid; + uint32_t st_gid; + unsigned short st_rdev; + unsigned char __pad3[10]; + unsigned char __pad31[4]; + long long st_size; + uint32_t st_blksize; + unsigned char __pad32[4]; + uint32_t st_blocks; + uint32_t __pad4; + uint32_t st32_atime; + uint32_t __pad5; + uint32_t st32_mtime; + uint32_t __pad6; + uint32_t st32_ctime; + uint32_t __pad7; + unsigned long long st_ino; +};// __attribute__((packed)); + +struct target_tms32 { + uint32_t tms_utime; + uint32_t tms_stime; + uint32_t tms_cutime; + uint32_t tms_cstime; +}; + +struct target_timeval32 { + uint32_t tv_sec; /* seconds */ + uint32_t tv_usec; /* microseconds */ +}; + +struct target_timezone32 { + int32_t tz_minuteswest; /* minutes west of Greenwich */ + int32_t tz_dsttime; /* type of DST correction */ +}; + diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp new file mode 100644 index 00000000..a0c866c1 --- /dev/null +++ b/src/core/arm/interpreter/armsupp.cpp @@ -0,0 +1,954 @@ +/* armsupp.c -- ARMulator support code: 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. */ + +#include "armdefs.h" +#include "armemu.h" +//#include "ansidecl.h" +#include "skyeye_defs.h" +unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum); +//extern int skyeye_instr_debug; +/* Definitions for the support routines. */ + +static ARMword ModeToBank (ARMword); +static void EnvokeList (ARMul_State *, unsigned int, unsigned int); + +struct EventNode +{ /* An event list node. */ + unsigned (*func) (ARMul_State *); /* The function to call. */ + struct EventNode *next; +}; + +/* This routine returns the value of a register from a mode. */ + +ARMword +ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg) +{ + mode &= MODEBITS; + if (mode != state->Mode) + return (state->RegBank[ModeToBank ((ARMword) mode)][reg]); + else + return (state->Reg[reg]); +} + +/* This routine sets the value of a register for a mode. */ + +void +ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value) +{ + mode &= MODEBITS; + if (mode != state->Mode) + state->RegBank[ModeToBank ((ARMword) mode)][reg] = value; + else + state->Reg[reg] = value; +} + +/* This routine returns the value of the PC, mode independently. */ + +ARMword +ARMul_GetPC (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return state->Reg[15]; + else + return R15PC; +} + +/* This routine returns the value of the PC, mode independently. */ + +ARMword +ARMul_GetNextPC (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return state->Reg[15] + isize; + else + return (state->Reg[15] + isize) & R15PCBITS; +} + +/* This routine sets the value of the PC. */ + +void +ARMul_SetPC (ARMul_State * state, ARMword value) +{ + if (ARMul_MODE32BIT) + state->Reg[15] = value & PCBITS; + else + state->Reg[15] = R15CCINTMODE | (value & R15PCBITS); + FLUSHPIPE; +} + +/* This routine returns the value of register 15, mode independently. */ + +ARMword +ARMul_GetR15 (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return (state->Reg[15]); + else + return (R15PC | ECC | ER15INT | EMODE); +} + +/* This routine sets the value of Register 15. */ + +void +ARMul_SetR15 (ARMul_State * state, ARMword value) +{ + if (ARMul_MODE32BIT) + state->Reg[15] = value & PCBITS; + else { + state->Reg[15] = value; + ARMul_R15Altered (state); + } + FLUSHPIPE; +} + +/* This routine returns the value of the CPSR. */ + +ARMword +ARMul_GetCPSR (ARMul_State * state) +{ + //chy 2003-08-20: below is from gdb20030716, maybe isn't suitable for system simulator + //return (CPSR | state->Cpsr); for gdb20030716 + // NOTE(bunnei): Changed this from [now] commented out macro "CPSR" + return ((ECC | EINT | EMODE | (TFLAG << 5))); //had be tested in old skyeye with gdb5.0-5.3 +} + +/* This routine sets the value of the CPSR. */ + +void +ARMul_SetCPSR (ARMul_State * state, ARMword value) +{ + state->Cpsr = value; + ARMul_CPSRAltered (state); +} + +/* This routine does all the nasty bits involved in a write to the CPSR, + including updating the register bank, given a MSR instruction. */ + +void +ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs) +{ + state->Cpsr = ARMul_GetCPSR (state); + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { + /* In user mode, only write flags. */ + if (BIT (16)) + SETPSR_C (state->Cpsr, rhs); + if (BIT (17)) + SETPSR_X (state->Cpsr, rhs); + if (BIT (18)) + SETPSR_S (state->Cpsr, rhs); + } + if (BIT (19)) + SETPSR_F (state->Cpsr, rhs); + ARMul_CPSRAltered (state); +} + +/* Get an SPSR from the specified mode. */ + +ARMword +ARMul_GetSPSR (ARMul_State * state, ARMword mode) +{ + ARMword bank = ModeToBank (mode & MODEBITS); + + if (!BANK_CAN_ACCESS_SPSR (bank)) + return ARMul_GetCPSR (state); + + return state->Spsr[bank]; +} + +/* This routine does a write to an SPSR. */ + +void +ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) +{ + ARMword bank = ModeToBank (mode & MODEBITS); + + if (BANK_CAN_ACCESS_SPSR (bank)) + state->Spsr[bank] = value; +} + +/* This routine does a write to the current SPSR, given an MSR instruction. */ + +void +ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs) +{ + if (BANK_CAN_ACCESS_SPSR (state->Bank)) { + if (BIT (16)) + SETPSR_C (state->Spsr[state->Bank], rhs); + if (BIT (17)) + SETPSR_X (state->Spsr[state->Bank], rhs); + if (BIT (18)) + SETPSR_S (state->Spsr[state->Bank], rhs); + if (BIT (19)) + SETPSR_F (state->Spsr[state->Bank], rhs); + } +} + +/* This routine updates the state of the emulator after the Cpsr has been + changed. Both the processor flags and register bank are updated. */ + +void +ARMul_CPSRAltered (ARMul_State * state) +{ + ARMword oldmode; + + if (state->prog32Sig == LOW) + state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS); + + oldmode = state->Mode; + + if (state->Mode != (state->Cpsr & MODEBITS)) { + state->Mode = + ARMul_SwitchMode (state, state->Mode, + state->Cpsr & MODEBITS); + + state->NtransSig = (state->Mode & 3) ? HIGH : LOW; + } + //state->Cpsr &= ~MODEBITS; + + ASSIGNINT (state->Cpsr & INTBITS); + //state->Cpsr &= ~INTBITS; + ASSIGNN ((state->Cpsr & NBIT) != 0); + //state->Cpsr &= ~NBIT; + ASSIGNZ ((state->Cpsr & ZBIT) != 0); + //state->Cpsr &= ~ZBIT; + ASSIGNC ((state->Cpsr & CBIT) != 0); + //state->Cpsr &= ~CBIT; + ASSIGNV ((state->Cpsr & VBIT) != 0); + //state->Cpsr &= ~VBIT; + ASSIGNS ((state->Cpsr & SBIT) != 0); + //state->Cpsr &= ~SBIT; +#ifdef MODET + ASSIGNT ((state->Cpsr & TBIT) != 0); + //state->Cpsr &= ~TBIT; +#endif + + if (oldmode > SVC26MODE) { + if (state->Mode <= SVC26MODE) { + state->Emulate = CHANGEMODE; + state->Reg[15] = ECC | ER15INT | EMODE | R15PC; + } + } + else { + if (state->Mode > SVC26MODE) { + state->Emulate = CHANGEMODE; + state->Reg[15] = R15PC; + } + else + state->Reg[15] = ECC | ER15INT | EMODE | R15PC; + } +} + +/* This routine updates the state of the emulator after register 15 has + been changed. Both the processor flags and register bank are updated. + This routine should only be called from a 26 bit mode. */ + +void +ARMul_R15Altered (ARMul_State * state) +{ + if (state->Mode != R15MODE) { + state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE); + state->NtransSig = (state->Mode & 3) ? HIGH : LOW; + } + + if (state->Mode > SVC26MODE) + state->Emulate = CHANGEMODE; + + ASSIGNR15INT (R15INT); + + ASSIGNN ((state->Reg[15] & NBIT) != 0); + ASSIGNZ ((state->Reg[15] & ZBIT) != 0); + ASSIGNC ((state->Reg[15] & CBIT) != 0); + ASSIGNV ((state->Reg[15] & VBIT) != 0); +} + +/* This routine controls the saving and restoring of registers across mode + changes. The regbank matrix is largely unused, only rows 13 and 14 are + used across all modes, 8 to 14 are used for FIQ, all others use the USER + column. It's easier this way. old and new parameter are modes numbers. + Notice the side effect of changing the Bank variable. */ + +ARMword +ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode) +{ + unsigned i; + ARMword oldbank; + ARMword newbank; + static int revision_value = 53; + + oldbank = ModeToBank (oldmode); + newbank = state->Bank = ModeToBank (newmode); + + /* Do we really need to do it? */ + if (oldbank != newbank) { + if (oldbank == 3 && newbank == 2) { + //printf("icounter is %d PC is %x MODE CHANGED : %d --> %d\n", state->NumInstrs, state->pc, oldbank, newbank); + if (state->NumInstrs >= 5832487) { +// printf("%d, ", state->NumInstrs + revision_value); +// printf("revision_value : %d\n", revision_value); + revision_value ++; + } + } + /* Save away the old registers. */ + switch (oldbank) { + case USERBANK: + case IRQBANK: + case SVCBANK: + case ABORTBANK: + case UNDEFBANK: + if (newbank == FIQBANK) + for (i = 8; i < 13; i++) + state->RegBank[USERBANK][i] = + state->Reg[i]; + state->RegBank[oldbank][13] = state->Reg[13]; + state->RegBank[oldbank][14] = state->Reg[14]; + break; + case FIQBANK: + for (i = 8; i < 15; i++) + state->RegBank[FIQBANK][i] = state->Reg[i]; + break; + case DUMMYBANK: + for (i = 8; i < 15; i++) + state->RegBank[DUMMYBANK][i] = 0; + break; + default: + abort (); + } + + /* Restore the new registers. */ + switch (newbank) { + case USERBANK: + case IRQBANK: + case SVCBANK: + case ABORTBANK: + case UNDEFBANK: + if (oldbank == FIQBANK) + for (i = 8; i < 13; i++) + state->Reg[i] = + state->RegBank[USERBANK][i]; + state->Reg[13] = state->RegBank[newbank][13]; + state->Reg[14] = state->RegBank[newbank][14]; + break; + case FIQBANK: + for (i = 8; i < 15; i++) + state->Reg[i] = state->RegBank[FIQBANK][i]; + break; + case DUMMYBANK: + for (i = 8; i < 15; i++) + state->Reg[i] = 0; + break; + default: + abort (); + } + } + + return newmode; +} + +/* Given a processor mode, this routine returns the + register bank that will be accessed in that mode. */ + +static ARMword +ModeToBank (ARMword mode) +{ + static ARMword bankofmode[] = { + USERBANK, FIQBANK, IRQBANK, SVCBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + USERBANK, FIQBANK, IRQBANK, SVCBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK + }; + + if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0]))) + return DUMMYBANK; + + return bankofmode[mode]; +} + +/* Returns the register number of the nth register in a reg list. */ + +unsigned +ARMul_NthReg (ARMword instr, unsigned number) +{ + unsigned bit, upto; + + for (bit = 0, upto = 0; upto <= number; bit++) + if (BIT (bit)) + upto++; + + return (bit - 1); +} + +/* Assigns the N and Z flags depending on the value of result. */ + +void +ARMul_NegZero (ARMul_State * state, ARMword result) +{ + if (NEG (result)) { + SETN; + CLEARZ; + } + else if (result == 0) { + CLEARN; + SETZ; + } + else { + CLEARN; + CLEARZ; + } +} + +/* Compute whether an addition of A and B, giving RESULT, overflowed. */ + +int +AddOverflow (ARMword a, ARMword b, ARMword result) +{ + return ((NEG (a) && NEG (b) && POS (result)) + || (POS (a) && POS (b) && NEG (result))); +} + +/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */ + +int +SubOverflow (ARMword a, ARMword b, ARMword result) +{ + return ((NEG (a) && POS (b) && POS (result)) + || (POS (a) && NEG (b) && NEG (result))); +} + +/* Assigns the C flag after an addition of a and b to give result. */ + +void +ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNC ((NEG (a) && NEG (b)) || + (NEG (a) && POS (result)) || (NEG (b) && POS (result))); +} + +/* Assigns the V flag after an addition of a and b to give result. */ + +void +ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNV (AddOverflow (a, b, result)); +} + +/* Assigns the C flag after an subtraction of a and b to give result. */ + +void +ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNC ((NEG (a) && POS (b)) || + (NEG (a) && POS (result)) || (POS (b) && POS (result))); +} + +/* Assigns the V flag after an subtraction of a and b to give result. */ + +void +ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNV (SubOverflow (a, b, result)); +} + +/* This function does the work of generating the addresses used in an + LDC instruction. The code here is always post-indexed, it's up to the + caller to get the input address correct and to handle base register + modification. It also handles the Busy-Waiting. */ + +void +ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address) +{ + unsigned cpab; + ARMword data; + + UNDEF_LSCPCBaseWb; + //printf("SKYEYE ARMul_LDC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); +/*chy 2004-05-23 should update this function in the future,should concern dataabort*/ +// chy 2004-05-25 , fix it now,so needn't printf +// printf("SKYEYE ARMul_LDC, should update this function!!!!!\n"); + //exit(-1); + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + /* + printf + ("SKYEYE ARMul_LDC,NOT ALLOW, underinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + ARMul_UndefInstr (state, instr); + return; + } + + if (ADDREXCEPT (address)) + INTERNALABORT (address); + + cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, + 0); + } + if (cpab == ARMul_CANT) { + /* + printf + ("SKYEYE ARMul_LDC,NOT CAN, underinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + CPTAKEABORT; + return; + } + + cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0); + data = ARMul_LoadWordN (state, address); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_ldc_takeabort; + + BUSUSEDINCPCN; +//chy 2004-05-25 +/* + if (BIT (21)) + LSBase = state->Base; +*/ + + cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); + + while (cpab == ARMul_INC) { + address += 4; + data = ARMul_LoadWordN (state, address); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_ldc_takeabort; + + cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); + } + +//chy 2004-05-25 + L_ldc_takeabort: + if (BIT (21)) { + if (! + ((state->abortSig || state->Aborted) + && state->lateabtSig == LOW)) + LSBase = state->Base; + } + + if (state->abortSig || state->Aborted) + TAKEABORT; +} + +/* This function does the work of generating the addresses used in an + STC instruction. The code here is always post-indexed, it's up to the + caller to get the input address correct and to handle base register + modification. It also handles the Busy-Waiting. */ + +void +ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) +{ + unsigned cpab; + ARMword data; + + UNDEF_LSCPCBaseWb; + + //printf("SKYEYE ARMul_STC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); + /*chy 2004-05-23 should update this function in the future,should concern dataabort */ +// skyeye_instr_debug=0;printf("SKYEYE debug end!!!!\n"); +// chy 2004-05-25 , fix it now,so needn't printf +// printf("SKYEYE ARMul_STC, should update this function!!!!!\n"); + + //exit(-1); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + /* + printf + ("SKYEYE ARMul_STC,NOT ALLOW, undefinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + ARMul_UndefInstr (state, instr); + return; + } + + if (ADDREXCEPT (address) || VECTORACCESS (address)) + INTERNALABORT (address); + + cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, + &data); + } + + if (cpab == ARMul_CANT) { + /* + printf + ("SKYEYE ARMul_STC,CANT, undefinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + CPTAKEABORT; + return; + } +#ifndef MODE32 + if (ADDREXCEPT (address) || VECTORACCESS (address)) + INTERNALABORT (address); +#endif + BUSUSEDINCPCN; +//chy 2004-05-25 +/* + if (BIT (21)) + LSBase = state->Base; +*/ + cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); + ARMul_StoreWordN (state, address, data); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_stc_takeabort; + + while (cpab == ARMul_INC) { + address += 4; + cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); + ARMul_StoreWordN (state, address, data); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_stc_takeabort; + } +//chy 2004-05-25 + L_stc_takeabort: + if (BIT (21)) { + if (! + ((state->abortSig || state->Aborted) + && state->lateabtSig == LOW)) + LSBase = state->Base; + } + + if (state->abortSig || state->Aborted) + TAKEABORT; +} + +/* This function does the Busy-Waiting for an MCR instruction. */ + +void +ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source) +{ + unsigned cpab; + + //printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + //chy 2004-07-19 should fix in the future ????!!!! + //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); + + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, + source); + } + + if (cpab == ARMul_CANT) { + printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + } +} + +/* This function does the Busy-Waiting for an MCRR instruction. */ + +void +ARMul_MCRR (ARMul_State * state, ARMword instr, ARMword source1, ARMword source2) +{ + unsigned cpab; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MCRR[CPNum]) (state, ARMul_FIRST, instr, source1, source2); + + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->MCRR[CPNum]) (state, ARMul_INTERRUPT, + instr, 0, 0); + return; + } + else + cpab = (state->MCRR[CPNum]) (state, ARMul_BUSY, instr, + source1, source2); + } + if (cpab == ARMul_CANT) { + printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x, source %x %x\n", __FUNCTION__, CPNum, instr, source1, source2); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + } +} + +/* This function does the Busy-Waiting for an MRC instruction. */ + +ARMword +ARMul_MRC (ARMul_State * state, ARMword instr) +{ + unsigned cpab; + ARMword result = 0; + + //printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + //chy 2004-07-19 should fix in the future????!!!! + //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr); + ARMul_UndefInstr (state, instr); + return -1; + } + + cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return (0); + } + else + cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, + &result); + } + if (cpab == ARMul_CANT) { + printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); + /* Parent will destroy the flags otherwise. */ + result = ECC; + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + ARMul_Icycles (state, 1, 0); + } + + return result; +} + +/* This function does the Busy-Waiting for an MRRC instruction. (to verify) */ + +void +ARMul_MRRC (ARMul_State * state, ARMword instr, ARMword * dest1, ARMword * dest2) +{ + unsigned cpab; + ARMword result1 = 0; + ARMword result2 = 0; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MRRC[CPNum]) (state, ARMul_FIRST, instr, &result1, &result2); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->MRRC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0, 0); + return; + } + else + cpab = (state->MRRC[CPNum]) (state, ARMul_BUSY, instr, + &result1, &result2); + } + if (cpab == ARMul_CANT) { + printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x\n", __FUNCTION__, CPNum, instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + ARMul_Icycles (state, 1, 0); + } + + *dest1 = result1; + *dest2 = result2; +} + +/* This function does the Busy-Waiting for an CDP instruction. */ + +void +ARMul_CDP (ARMul_State * state, ARMword instr) +{ + unsigned cpab; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, + instr); + return; + } + else + cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr); + } + if (cpab == ARMul_CANT) + ARMul_Abort (state, ARMul_UndefinedInstrV); + else + BUSUSEDN; +} + +/* This function handles Undefined instructions, as CP isntruction. */ + +void +ARMul_UndefInstr (ARMul_State * state, ARMword instr) +{ + ERROR_LOG(ARM11, "Undefined instruction!! Instr: 0x%x", instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); +} + +/* Return TRUE if an interrupt is pending, FALSE otherwise. */ + +unsigned +IntPending (ARMul_State * state) +{ + /* Any exceptions. */ + if (state->NresetSig == LOW) { + ARMul_Abort (state, ARMul_ResetV); + return TRUE; + } + else if (!state->NfiqSig && !FFLAG) { + ARMul_Abort (state, ARMul_FIQV); + return TRUE; + } + else if (!state->NirqSig && !IFLAG) { + ARMul_Abort (state, ARMul_IRQV); + return TRUE; + } + + return FALSE; +} + +/* Align a word access to a non word boundary. */ + +ARMword +ARMul_Align (ARMul_State *state, ARMword address, ARMword data) +{ + /* This code assumes the address is really unaligned, + as a shift by 32 is undefined in C. */ + + address = (address & 3) << 3; /* Get the word address. */ + return ((data >> address) | (data << (32 - address))); /* rot right */ +} + +/* This routine is used to call another routine after a certain number of + cycles have been executed. The first parameter is the number of cycles + delay before the function is called, the second argument is a pointer + to the function. A delay of zero doesn't work, just call the function. */ + +void +ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, + unsigned (*what) (ARMul_State *)) +{ + unsigned int when; + struct EventNode *event; + + if (state->EventSet++ == 0) + state->Now = ARMul_Time (state); + when = (state->Now + delay) % EVENTLISTSIZE; + event = (struct EventNode *) malloc (sizeof (struct EventNode)); + + _dbg_assert_msg_(ARM11, event, "SKYEYE:ARMul_ScheduleEvent: malloc event error\n"); + + event->func = what; + event->next = *(state->EventPtr + when); + *(state->EventPtr + when) = event; +} + +/* This routine is called at the beginning of + every cycle, to envoke scheduled events. */ + +void +ARMul_EnvokeEvent (ARMul_State * state) +{ + static unsigned int then; + + then = state->Now; + state->Now = ARMul_Time (state) % EVENTLISTSIZE; + if (then < state->Now) + /* Schedule events. */ + EnvokeList (state, then, state->Now); + else if (then > state->Now) { + /* Need to wrap around the list. */ + EnvokeList (state, then, EVENTLISTSIZE - 1L); + EnvokeList (state, 0L, state->Now); + } +} + +/* Envokes all the entries in a range. */ + +static void +EnvokeList (ARMul_State * state, unsigned int from, unsigned int to) +{ + for (; from <= to; from++) { + struct EventNode *anevent; + + anevent = *(state->EventPtr + from); + while (anevent) { + (anevent->func) (state); + state->EventSet--; + anevent = anevent->next; + } + *(state->EventPtr + from) = NULL; + } +} + +/* This routine is returns the number of clock ticks since the last reset. */ + +unsigned int +ARMul_Time (ARMul_State * state) +{ + return (state->NumScycles + state->NumNcycles + + state->NumIcycles + state->NumCcycles + state->NumFcycles); +} diff --git a/src/core/arm/interpreter/armvirt.cpp b/src/core/arm/interpreter/armvirt.cpp new file mode 100644 index 00000000..a072b73b --- /dev/null +++ b/src/core/arm/interpreter/armvirt.cpp @@ -0,0 +1,680 @@ +/* armvirt.c -- ARMulator virtual memory interace: 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. */ + +/* This file contains a complete ARMulator memory model, modelling a +"virtual memory" system. A much simpler model can be found in armfast.c, +and that model goes faster too, but has a fixed amount of memory. This +model's memory has 64K pages, allocated on demand from a 64K entry page +table. The routines PutWord and GetWord implement this. Pages are never +freed as they might be needed again. A single area of memory may be +defined to generate aborts. */ + +#include "armdefs.h" +#include "skyeye_defs.h" +//#include "code_cov.h" + +#ifdef VALIDATE /* for running the validate suite */ +#define TUBE 48 * 1024 * 1024 /* write a char on the screen */ +#define ABORTS 1 +#endif + +/* #define ABORTS */ + +#ifdef ABORTS /* the memory system will abort */ +/* For the old test suite Abort between 32 Kbytes and 32 Mbytes + For the new test suite Abort between 8 Mbytes and 26 Mbytes */ +/* #define LOWABORT 32 * 1024 +#define HIGHABORT 32 * 1024 * 1024 */ +#define LOWABORT 8 * 1024 * 1024 +#define HIGHABORT 26 * 1024 * 1024 + +#endif + +#define NUMPAGES 64 * 1024 +#define PAGESIZE 64 * 1024 +#define PAGEBITS 16 +#define OFFSETBITS 0xffff +//chy 2003-08-19: seems no use ???? +int SWI_vector_installed = FALSE; +extern ARMword skyeye_cachetype; + +/***************************************************************************\ +* Get a byte into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +GetByte (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_byte (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: GetByte fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Get a halfword into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +GetHalfWord (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_halfword (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: GetHalfWord fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Get a Word from Virtual Memory, maybe allocating the page * +\***************************************************************************/ + +static fault_t +GetWord (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_word (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +#if 0 +/* XXX */ extern int hack; + hack = 1; +#endif +#if 0 + printf ("mmu_read_word at 0x%08x: ", address); + switch (fault) { + case ALIGNMENT_FAULT: + printf ("ALIGNMENT_FAULT"); + break; + case SECTION_TRANSLATION_FAULT: + printf ("SECTION_TRANSLATION_FAULT"); + break; + case PAGE_TRANSLATION_FAULT: + printf ("PAGE_TRANSLATION_FAULT"); + break; + case SECTION_DOMAIN_FAULT: + printf ("SECTION_DOMAIN_FAULT"); + break; + case SECTION_PERMISSION_FAULT: + printf ("SECTION_PERMISSION_FAULT"); + break; + case SUBPAGE_PERMISSION_FAULT: + printf ("SUBPAGE_PERMISSION_FAULT"); + break; + default: + printf ("Unrecognized fault number!"); + } + printf ("\tpc = 0x%08x\n", state->Reg[15]); +#endif + } + return fault; +} + +//2003-07-10 chy: lyh change +/****************************************************************************\ + * Load a Instrion Word into Virtual Memory * +\****************************************************************************/ +static fault_t +LoadInstr (ARMul_State * state, ARMword address, ARMword * instr) +{ + fault_t fault; + fault = mmu_load_instr (state, address, instr); + return fault; + //if (fault) + // log_msg("load_instr fault = %d, address = %x\n", fault, address); +} + +/***************************************************************************\ +* Put a byte into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +PutByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_byte (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: PutByte fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Put a halfword into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +PutHalfWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_halfword (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: PutHalfWord fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Put a Word into Virtual Memory, maybe allocating the page * +\***************************************************************************/ + +static fault_t +PutWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_word (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +#if 0 +/* XXX */ extern int hack; + hack = 1; +#endif +#if 0 + printf ("mmu_write_word at 0x%08x: ", address); + switch (fault) { + case ALIGNMENT_FAULT: + printf ("ALIGNMENT_FAULT"); + break; + case SECTION_TRANSLATION_FAULT: + printf ("SECTION_TRANSLATION_FAULT"); + break; + case PAGE_TRANSLATION_FAULT: + printf ("PAGE_TRANSLATION_FAULT"); + break; + case SECTION_DOMAIN_FAULT: + printf ("SECTION_DOMAIN_FAULT"); + break; + case SECTION_PERMISSION_FAULT: + printf ("SECTION_PERMISSION_FAULT"); + break; + case SUBPAGE_PERMISSION_FAULT: + printf ("SUBPAGE_PERMISSION_FAULT"); + break; + default: + printf ("Unrecognized fault number!"); + } + printf ("\tpc = 0x%08x\n", state->Reg[15]); +#endif + } + return fault; +} + +/***************************************************************************\ +* Initialise the memory interface * +\***************************************************************************/ + +unsigned +ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize) +{ + return TRUE; +} + +/***************************************************************************\ +* Remove the memory interface * +\***************************************************************************/ + +void +ARMul_MemoryExit (ARMul_State * state) +{ +} + +/***************************************************************************\ +* ReLoad Instruction * +\***************************************************************************/ + +ARMword +ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) +{ + ARMword data; + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } +#endif +#if 0 + /* do profiling for code coverage */ + if (skyeye_config.code_cov.prof_on) + cov_prof(EXEC_FLAG, address); +#endif +#if 1 + if ((isize == 2) && (address & 0x2)) { + ARMword lo, hi; + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetHalfWord (state, address, &lo); + else + fault = LoadInstr (state, address, &lo); +#if 0 + if (!fault) { + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetHalfWord (state, address + isize, &hi); + else + fault = LoadInstr (state, address + isize, &hi); + + } +#endif + if (fault) { + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + return lo; +#if 0 + if (state->bigendSig == HIGH) + return (lo << 16) | (hi >> 16); + else + return ((hi & 0xFFFF) << 16) | (lo >> 16); +#endif + } +#endif + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetWord (state, address, &data); + else + fault = LoadInstr (state, address, &data); + + if (fault) { + + /* dyf add for s3c6410 no instcache temporary 2010.9.17 */ + if (!(skyeye_cachetype == INSTCACHE)) { + /* set translation fault on prefetch abort */ + state->mmu.fault_statusi = fault & 0xFF; + state->mmu.fault_address = address; + } + /* add end */ + + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; +} + +/***************************************************************************\ +* Load Instruction, Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) +{ + state->NumScycles++; + +#ifdef HOURGLASS + if ((state->NumScycles & HOURGLASS_RATE) == 0) { + HOURGLASS; + } +#endif + + return ARMul_ReLoadInstr (state, address, isize); +} + +/***************************************************************************\ +* Load Instruction, Non Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) +{ + state->NumNcycles++; + + return ARMul_ReLoadInstr (state, address, isize); +} + +/***************************************************************************\ +* Read Word (but don't tell anyone!) * +\***************************************************************************/ + +ARMword +ARMul_ReadWord (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } +#endif + + fault = GetWord (state, address, &data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + return data; +} + +/***************************************************************************\ +* Load Word, Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadWordS (ARMul_State * state, ARMword address) +{ + state->NumScycles++; + + return ARMul_ReadWord (state, address); +} + +/***************************************************************************\ +* Load Word, Non Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadWordN (ARMul_State * state, ARMword address) +{ + state->NumNcycles++; + + return ARMul_ReadWord (state, address); +} + +/***************************************************************************\ +* Load Halfword, (Non Sequential Cycle) * +\***************************************************************************/ + +ARMword +ARMul_LoadHalfWord (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + + state->NumNcycles++; + fault = GetHalfWord (state, address, &data); + + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; + +} + +/***************************************************************************\ +* Read Byte (but don't tell anyone!) * +\***************************************************************************/ +int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult) +{ + ARMword data; + fault_t fault; + fault = GetByte (state, address, &data); + if (fault) { + *presult=-1; fault=ALIGNMENT_FAULT; return fault; + }else{ + *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault; + } +} + + +ARMword +ARMul_ReadByte (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + + fault = GetByte (state, address, &data); + + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; + +} + +/***************************************************************************\ +* Load Byte, (Non Sequential Cycle) * +\***************************************************************************/ + +ARMword +ARMul_LoadByte (ARMul_State * state, ARMword address) +{ + state->NumNcycles++; + + return ARMul_ReadByte (state, address); +} + +/***************************************************************************\ +* Write Word (but don't tell anyone!) * +\***************************************************************************/ + +void +ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +#endif + + fault = PutWord (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +/***************************************************************************\ +* Store Word, Sequential Cycle * +\***************************************************************************/ + +void +ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumScycles++; + + ARMul_WriteWord (state, address, data); +} + +/***************************************************************************\ +* Store Word, Non Sequential Cycle * +\***************************************************************************/ + +void +ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumNcycles++; + + ARMul_WriteWord (state, address, data); +} + +/***************************************************************************\ +* Store HalfWord, (Non Sequential Cycle) * +\***************************************************************************/ + +void +ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + state->NumNcycles++; + fault = PutHalfWord (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +//chy 2006-04-15 +int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + fault = PutByte (state, address, data); + if (fault) + return 1; + else + return 0; +} +/***************************************************************************\ +* Write Byte (but don't tell anyone!) * +\***************************************************************************/ +//chy 2003-07-10, add real write byte fun +void +ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + fault = PutByte (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +/***************************************************************************\ +* Store Byte, (Non Sequential Cycle) * +\***************************************************************************/ + +void +ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumNcycles++; + +#ifdef VALIDATE + if (address == TUBE) { + if (data == 4) + state->Emulate = FALSE; + else + (void) putc ((char) data, stderr); /* Write Char */ + return; + } +#endif + + ARMul_WriteByte (state, address, data); +} + +/***************************************************************************\ +* Swap Word, (Two Non Sequential Cycles) * +\***************************************************************************/ + +ARMword +ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) +{ + ARMword temp; + + state->NumNcycles++; + + temp = ARMul_ReadWord (state, address); + + state->NumNcycles++; + + PutWord (state, address, data); + + return temp; +} + +/***************************************************************************\ +* Swap Byte, (Two Non Sequential Cycles) * +\***************************************************************************/ + +ARMword +ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) +{ + ARMword temp; + + temp = ARMul_LoadByte (state, address); + ARMul_StoreByte (state, address, data); + + return temp; +} + +/***************************************************************************\ +* Count I Cycles * +\***************************************************************************/ + +void +ARMul_Icycles (ARMul_State * state, unsigned number, + ARMword address) +{ + state->NumIcycles += number; + ARMul_CLEARABORT; +} + +/***************************************************************************\ +* Count C Cycles * +\***************************************************************************/ + +void +ARMul_Ccycles (ARMul_State * state, unsigned number, + ARMword address) +{ + state->NumCcycles += number; + ARMul_CLEARABORT; +} diff --git a/src/core/arm/interpreter/skyeye_defs.h b/src/core/arm/interpreter/skyeye_defs.h new file mode 100644 index 00000000..6562e595 --- /dev/null +++ b/src/core/arm/interpreter/skyeye_defs.h @@ -0,0 +1,111 @@ +#ifndef CORE_ARM_SKYEYE_DEFS_H_ +#define CORE_ARM_SKYEYE_DEFS_H_ + +#include "common.h" + +#define MODE32 +#define MODET + +typedef struct +{ + 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; /*this cpu has what kind of cache */ +} cpu_config_t; + +typedef struct conf_object_s{ + char* objname; + void* obj; + char* class_name; +}conf_object_t; + +typedef 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 +}exception_t; + +typedef enum { + Align = 0, + UnAlign +}align_t; + +typedef enum { + Little_endian = 0, + Big_endian +}endian_t; +//typedef int exception_t; + +typedef enum{ + Phys_addr = 0, + Virt_addr +}addr_type_t; + +typedef exception_t(*read_byte_t)(conf_object_t* target, u32 addr, void *buf, size_t count); +typedef exception_t(*write_byte_t)(conf_object_t* target, u32 addr, const void *buf, size_t count); + +typedef struct memory_space{ + conf_object_t* conf_obj; + read_byte_t read; + write_byte_t write; +}memory_space_intf; + + +/* + * a running instance for a specific archteciture. + */ +typedef struct generic_arch_s +{ + char* arch_name; + void (*init) (void); + void (*reset) (void); + void (*step_once) (void); + void (*set_pc)(u32 addr); + u32 (*get_pc)(void); + u32 (*get_step)(void); + //chy 2004-04-15 + //int (*ICE_write_byte) (u32 addr, uint8_t v); + //int (*ICE_read_byte)(u32 addr, uint8_t *pv); + u32 (*get_regval_by_id)(int id); + u32 (*get_regnum)(void); + char* (*get_regname_by_id)(int id); + exception_t (*set_regval_by_id)(int id, u32 value); + /* + * read a data by virtual address. + */ + exception_t (*mmu_read)(short size, u32 addr, u32 * value); + /* + * write a data by a virtual address. + */ + exception_t (*mmu_write)(short size, u32 addr, u32 value); + /** + * get a signal from external + */ + //exception_t (*signal)(interrupt_signal_t* signal); + + endian_t endianess; + align_t alignment; +} generic_arch_t; + +#endif \ No newline at end of file diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp new file mode 100644 index 00000000..032d84b6 --- /dev/null +++ b/src/core/arm/interpreter/thumbemu.cpp @@ -0,0 +1,513 @@ +/* thumbemu.c -- Thumb instruction emulation. + Copyright (C) 1996, Cygnus Software Technologies 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. */ + +/* We can provide simple Thumb simulation by decoding the Thumb +instruction into its corresponding ARM instruction, and using the +existing ARM simulator. */ + +#include "skyeye_defs.h" + +#ifndef MODET /* required for the Thumb instruction support */ +#if 1 +#error "MODET needs to be defined for the Thumb world to work" +#else +#define MODET (1) +#endif +#endif + +#include "armdefs.h" +#include "armemu.h" +#include "armos.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 +ARMul_ThumbDecode ( + ARMul_State *state, + ARMword pc, + ARMword tinstr, + ARMword *ainstr) +{ + tdstate valid = t_decoded; /* default assumes a valid instruction */ + ARMword next_instr; + + if (state->bigendSig) { + next_instr = tinstr & 0xFFFF; + tinstr >>= 16; + } + else { + next_instr = tinstr >> 16; + tinstr &= 0xFFFF; + } + +#if 1 /* debugging to catch non updates */ + *ainstr = 0xDEADC0DE; +#endif + + switch ((tinstr & 0xF800) >> 11) { + case 0: /* LSL */ + case 1: /* LSR */ + case 2: /* ASR */ + /* Format 1 */ + *ainstr = 0xE1B00000 /* base opcode */ + | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */ + |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */ + |((tinstr & 0x0038) >> 3) /* Rs */ + |((tinstr & 0x0007) << 12); /* Rd */ + break; + case 3: /* ADD/SUB */ + /* Format 2 */ + { + ARMword subset[4] = { + 0xE0900000, /* ADDS Rd,Rs,Rn */ + 0xE0500000, /* SUBS Rd,Rs,Rn */ + 0xE2900000, /* ADDS Rd,Rs,#imm3 */ + 0xE2500000 /* SUBS Rd,Rs,#imm3 */ + }; + /* It is quicker indexing into a table, than performing switch + or conditionals: */ + *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */ + |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */ + |((tinstr & 0x0038) << (16 - 3)) /* Rs */ + |((tinstr & 0x0007) << (12 - 0)); /* Rd */ + } + break; + case 4: /* MOV */ + case 5: /* CMP */ + case 6: /* ADD */ + case 7: /* SUB */ + /* Format 3 */ + { + ARMword subset[4] = { + 0xE3B00000, /* MOVS Rd,#imm8 */ + 0xE3500000, /* CMP Rd,#imm8 */ + 0xE2900000, /* ADDS Rd,Rd,#imm8 */ + 0xE2500000, /* SUBS Rd,Rd,#imm8 */ + }; + *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */ + |((tinstr & 0x00FF) >> 0) /* imm8 */ + |((tinstr & 0x0700) << (16 - 8)) /* Rn */ + |((tinstr & 0x0700) << (12 - 8)); /* Rd */ + } + break; + case 8: /* Arithmetic and high register transfers */ + /* TODO: Since the subsets for both Format 4 and Format 5 + instructions are made up of different ARM encodings, we could + save the following conditional, and just have one large + subset. */ + if ((tinstr & (1 << 10)) == 0) { + /* Format 4 */ + enum OpcodeType { t_norm, t_shift, t_neg, t_mul }; + struct ThumbOpcode { + ARMword opcode; + OpcodeType otype; + }; + + ThumbOpcode subset[16] = { + { + 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */ + { + 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */ + { + 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */ + { + 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */ + { + 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */ + { + 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */ + { + 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */ + { + 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */ + { + 0xE1100000, t_norm}, /* TST Rd,Rs */ + { + 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */ + { + 0xE1500000, t_norm}, /* CMP Rd,Rs */ + { + 0xE1700000, t_norm}, /* CMN Rd,Rs */ + { + 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */ + { + 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */ + { + 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */ + { + 0xE1F00000, t_norm} /* MVNS Rd,Rs */ + }; + *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */ + switch (subset[(tinstr & 0x03C0) >> 6].otype) { + case t_norm: + *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */ + |((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0038) >> 3); /* Rs */ + break; + case t_shift: + *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0007) >> 0) /* Rm */ + |((tinstr & 0x0038) << (8 - 3)); /* Rs */ + break; + case t_neg: + *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)); /* Rn */ + break; + case t_mul: + *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */ + |((tinstr & 0x0007) << 8) /* Rs */ + |((tinstr & 0x0038) >> 3); /* Rm */ + break; + } + } + else { + /* Format 5 */ + ARMword Rd = ((tinstr & 0x0007) >> 0); + ARMword Rs = ((tinstr & 0x0038) >> 3); + if (tinstr & (1 << 7)) + Rd += 8; + if (tinstr & (1 << 6)) + Rs += 8; + switch ((tinstr & 0x03C0) >> 6) { + case 0x1: /* ADD Rd,Rd,Hs */ + case 0x2: /* ADD Hd,Hd,Rs */ + case 0x3: /* ADD Hd,Hd,Hs */ + *ainstr = 0xE0800000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0x5: /* CMP Rd,Hs */ + case 0x6: /* CMP Hd,Rs */ + case 0x7: /* CMP Hd,Hs */ + *ainstr = 0xE1500000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0x9: /* MOV Rd,Hs */ + case 0xA: /* MOV Hd,Rs */ + case 0xB: /* MOV Hd,Hs */ + *ainstr = 0xE1A00000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0xC: /* BX Rs */ + case 0xD: /* BX Hs */ + *ainstr = 0xE12FFF10 /* base */ + | ((tinstr & 0x0078) >> 3); /* Rd */ + break; + case 0x0: /* UNDEFINED */ + case 0x4: /* UNDEFINED */ + case 0x8: /* UNDEFINED */ + valid = t_undefined; + break; + case 0xE: /* BLX */ + case 0xF: /* BLX */ + if (state->is_v5) { + *ainstr = 0xE1200030 /* base */ + |(Rs << 0); /* Rm */ + } else { + valid = t_undefined; + } + break; + } + } + break; + case 9: /* LDR Rd,[PC,#imm8] */ + /* Format 6 */ + *ainstr = 0xE59F0000 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |((tinstr & 0x00FF) << (2 - 0)); /* off8 */ + break; + case 10: + case 11: + /* TODO: Format 7 and Format 8 perform the same ARM encoding, so + the following could be merged into a single subset, saving on + the following boolean: */ + if ((tinstr & (1 << 9)) == 0) { + /* Format 7 */ + ARMword subset[4] = { + 0xE7800000, /* STR Rd,[Rb,Ro] */ + 0xE7C00000, /* STRB Rd,[Rb,Ro] */ + 0xE7900000, /* LDR Rd,[Rb,Ro] */ + 0xE7D00000 /* LDRB Rd,[Rb,Ro] */ + }; + *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> 6); /* Ro */ + } + else { + /* Format 8 */ + ARMword subset[4] = { + 0xE18000B0, /* STRH Rd,[Rb,Ro] */ + 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */ + 0xE19000B0, /* LDRH Rd,[Rb,Ro] */ + 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */ + }; + *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> 6); /* Ro */ + } + break; + case 12: /* STR Rd,[Rb,#imm5] */ + case 13: /* LDR Rd,[Rb,#imm5] */ + case 14: /* STRB Rd,[Rb,#imm5] */ + case 15: /* LDRB Rd,[Rb,#imm5] */ + /* Format 9 */ + { + ARMword subset[4] = { + 0xE5800000, /* STR Rd,[Rb,#imm5] */ + 0xE5900000, /* LDR Rd,[Rb,#imm5] */ + 0xE5C00000, /* STRB Rd,[Rb,#imm5] */ + 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */ + }; + /* The offset range defends on whether we are transferring a + byte or word value: */ + *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */ + } + break; + case 16: /* STRH Rd,[Rb,#imm5] */ + case 17: /* LDRH Rd,[Rb,#imm5] */ + /* Format 10 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE1D000B0 /* LDRH */ + : 0xE1C000B0) /* STRH */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */ + |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */ + break; + case 18: /* STR Rd,[SP,#imm8] */ + case 19: /* LDR Rd,[SP,#imm8] */ + /* Format 11 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE59D0000 /* LDR */ + : 0xE58D0000) /* STR */ + |((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |((tinstr & 0x00FF) << 2); /* off8 */ + break; + case 20: /* ADD Rd,PC,#imm8 */ + case 21: /* ADD Rd,SP,#imm8 */ + /* Format 12 */ + if ((tinstr & (1 << 11)) == 0) { + /* NOTE: The PC value used here should by word aligned */ + /* We encode shift-left-by-2 in the rotate immediate field, + so no shift of off8 is needed. */ + *ainstr = 0xE28F0F00 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |(tinstr & 0x00FF); /* off8 */ + } + else { + /* We encode shift-left-by-2 in the rotate immediate field, + so no shift of off8 is needed. */ + *ainstr = 0xE28D0F00 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |(tinstr & 0x00FF); /* off8 */ + } + break; + case 22: + case 23: + if ((tinstr & 0x0F00) == 0x0000) { + /* Format 13 */ + /* NOTE: The instruction contains a shift left of 2 + equivalent (implemented as ROR #30): */ + *ainstr = ((tinstr & (1 << 7)) /* base */ + ? 0xE24DDF00 /* SUB */ + : 0xE28DDF00) /* ADD */ + |(tinstr & 0x007F); /* off7 */ + } + else if ((tinstr & 0x0F00) == 0x0e00) + *ainstr = 0xEF000000 | SWI_Breakpoint; + else { + /* Format 14 */ + ARMword subset[4] = { + 0xE92D0000, /* STMDB sp!,{rlist} */ + 0xE92D4000, /* STMDB sp!,{rlist,lr} */ + 0xE8BD0000, /* LDMIA sp!,{rlist} */ + 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */ + }; + *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */ + |(tinstr & 0x00FF); /* mask8 */ + } + break; + case 24: /* STMIA */ + case 25: /* LDMIA */ + /* Format 15 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE8B00000 /* LDMIA */ + : 0xE8A00000) /* STMIA */ + |((tinstr & 0x0700) << (16 - 8)) /* Rb */ + |(tinstr & 0x00FF); /* mask8 */ + break; + case 26: /* Bcc */ + case 27: /* Bcc/SWI */ + if ((tinstr & 0x0F00) == 0x0F00) { + if (tinstr == (ARMul_ABORTWORD & 0xffff) && + state->AbortAddr == pc) { + *ainstr = ARMul_ABORTWORD; + break; + } + /* Format 17 : SWI */ + *ainstr = 0xEF000000; + /* Breakpoint must be handled specially. */ + if ((tinstr & 0x00FF) == 0x18) + *ainstr |= ((tinstr & 0x00FF) << 16); + /* New breakpoint value. See gdb/arm-tdep.c */ + else if ((tinstr & 0x00FF) == 0xFE) + *ainstr |= SWI_Breakpoint; + else + *ainstr |= (tinstr & 0x00FF); + } + else if ((tinstr & 0x0F00) != 0x0E00) { + /* Format 16 */ + int doit = FALSE; + /* TODO: Since we are doing a switch here, we could just add + the SWI and undefined instruction checks into this + switch to same on a couple of conditionals: */ + switch ((tinstr & 0x0F00) >> 8) { + case EQ: + doit = ZFLAG; + break; + case NE: + doit = !ZFLAG; + break; + case VS: + doit = VFLAG; + break; + case VC: + doit = !VFLAG; + break; + case MI: + doit = NFLAG; + break; + case PL: + doit = !NFLAG; + break; + case CS: + doit = CFLAG; + break; + case CC: + doit = !CFLAG; + break; + case HI: + doit = (CFLAG && !ZFLAG); + break; + case LS: + doit = (!CFLAG || ZFLAG); + break; + case GE: + doit = ((!NFLAG && !VFLAG) + || (NFLAG && VFLAG)); + break; + case LT: + doit = ((NFLAG && !VFLAG) + || (!NFLAG && VFLAG)); + break; + case GT: + doit = ((!NFLAG && !VFLAG && !ZFLAG) + || (NFLAG && VFLAG && !ZFLAG)); + break; + case LE: + doit = ((NFLAG && !VFLAG) + || (!NFLAG && VFLAG)) || ZFLAG; + break; + } + if (doit) { + state->Reg[15] = (pc + 4 + + (((tinstr & 0x7F) << 1) + | ((tinstr & (1 << 7)) ? + 0xFFFFFF00 : 0))); + FLUSHPIPE; + } + valid = t_branch; + } + else /* UNDEFINED : cc=1110(AL) uses different format */ + valid = t_undefined; + break; + case 28: /* B */ + /* Format 18 */ + state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1) + | ((tinstr & (1 << 10)) ? + 0xFFFFF800 : 0))); + FLUSHPIPE; + valid = t_branch; + break; + case 29: + if(tinstr & 0x1) + valid = t_undefined; + else{ + /* BLX 1 for armv5t and above */ + ARMword tmp = (pc + 2); + state->Reg[15] = + (state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; + state->Reg[14] = (tmp | 1); + CLEART; + DEBUG_LOG(ARM11, "In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); + valid = t_branch; + FLUSHPIPE; + } + break; + case 30: /* BL instruction 1 */ + /* Format 19 */ + /* There is no single ARM instruction equivalent for this Thumb + instruction. To keep the simulation simple (from the user + perspective) we check if the following instruction is the + second half of this BL, and if it is we simulate it + immediately. */ + state->Reg[14] = state->Reg[15] + + (((tinstr & 0x07FF) << 12) + | ((tinstr & (1 << 10)) ? 0xFF800000 : 0)); + valid = t_branch; /* in-case we don't have the 2nd half */ + //tinstr = next_instr; /* move the instruction down */ + //if (((tinstr & 0xF800) >> 11) != 31) + // break; /* exit, since not correct instruction */ + /* else we fall through to process the second half of the BL */ + //pc += 2; /* point the pc at the 2nd half */ + state->Reg[15] = pc + 2; + FLUSHPIPE; + break; + case 31: /* BL instruction 2 */ + /* Format 19 */ + /* There is no single ARM instruction equivalent for this + instruction. Also, it should only ever be matched with the + fmt19 "BL instruction 1" instruction. However, we do allow + the simulation of it on its own, with undefined results if + r14 is not suitably initialised. */ + { + ARMword tmp = (pc + 2); + state->Reg[15] = + (state->Reg[14] + ((tinstr & 0x07FF) << 1)); + state->Reg[14] = (tmp | 1); + valid = t_branch; + FLUSHPIPE; + } + break; + } + + return valid; +} diff --git a/src/core/arm/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/mmu/arm1176jzf_s_mmu.cpp new file mode 100644 index 00000000..0a3206ab --- /dev/null +++ b/src/core/arm/mmu/arm1176jzf_s_mmu.cpp @@ -0,0 +1,1132 @@ +/* + arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation. + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to + + 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 +#include +#include + +#include "mem_map.h" + +#include "arm/interpreter/skyeye_defs.h" + +#include "arm/interpreter/armdefs.h" +//#include "bank_defs.h" +#if 0 +#define TLB_SIZE 1024 * 1024 +#define ASID 255 +static uint32_t tlb_entry_array[TLB_SIZE][ASID]; +static inline void invalidate_all_tlb(ARMul_State *state){ + memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID); +} +static inline void invalidate_by_mva(ARMul_State *state, ARMword va){ + memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t)); + return; +} +static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){ + int i; + for(i = 0; i < TLB_SIZE; i++) + memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t)); + return; +} + +static uint32_t get_phys_page(ARMul_State* state, ARMword va){ + uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF]; + //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page); + return phys_page; +} + +static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){ + //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa); + //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12); + tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12; + + return; +} +#endif +#define BANK0_START 0x50000000 +static void* mem_ptr = NULL; + +static int exclusive_detect(ARMul_State* state, ARMword addr){ + #if 0 + for(int i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == addr) + return 0; + } + #endif + if(state->exclusive_tag_array[0] == addr) + return 0; + else + return -1; +} + +static void add_exclusive_addr(ARMul_State* state, ARMword addr){ + #if 0 + for(int i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == 0xffffffff){ + state->exclusive_tag_array[i] = addr; + //printf("In %s, add addr 0x%x\n", __func__, addr); + return; + } + } + printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__); + #endif + state->exclusive_tag_array[0] = addr; + return; +} + +static void remove_exclusive(ARMul_State* state, ARMword addr){ + #if 0 + int i; + for(i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == addr){ + state->exclusive_tag_array[i] = 0xffffffff; + //printf("In %s, remove addr 0x%x\n", __func__, addr); + return; + } + } + #endif + state->exclusive_tag_array[0] = 0xFFFFFFFF; +} + +/* This function encodes table 8-2 Interpreting AP bits, + returning non-zero if access is allowed. */ +static int +check_perms (ARMul_State *state, int ap, int read) +{ + int s, r, user; + + s = state->mmu.control & CONTROL_SYSTEM; + r = state->mmu.control & CONTROL_ROM; + /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */ +// printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read); +// printf("mode is %x\n", state->Mode); + user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); + + switch (ap) { + case 0: + return read && ((s && !user) || r); + case 1: + return !user; + case 2: + return read || !user; + case 3: + return 1; + } + return 0; +} + +#if 0 +fault_t +check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb, + int read) +{ + int access; + + state->mmu.last_domain = tlb->domain; + access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; + if ((access == 0) || (access == 2)) { + /* It's unclear from the documentation whether this + should always raise a section domain fault, or if + it should be a page domain fault in the case of an + L1 that describes a page table. In the ARM710T + datasheets, "Figure 8-9: Sequence for checking faults" + seems to indicate the former, while "Table 8-4: Priority + encoding of fault status" gives a value for FS[3210] in + the event of a domain fault for a page. Hmm. */ + return SECTION_DOMAIN_FAULT; + } + if (access == 1) { + /* client access - check perms */ + int subpage, ap; +#if 0 + switch (tlb->mapping) { + /*ks 2004-05-09 + * only for XScale + * Extend Small Page(ESP) Format + * 31-12 bits the base addr of ESP + * 11-10 bits SBZ + * 9-6 bits TEX + * 5-4 bits AP + * 3 bit C + * 2 bit B + * 1-0 bits 11 + * */ + case TLB_ESMALLPAGE: /* xj */ + subpage = 0; + /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */ + break; + + case TLB_TINYPAGE: + subpage = 0; + /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */ + break; + + case TLB_SMALLPAGE: + subpage = (virt_addr >> 10) & 3; + break; + case TLB_LARGEPAGE: + subpage = (virt_addr >> 14) & 3; + break; + case TLB_SECTION: + subpage = 3; + break; + default: + assert (0); + subpage = 0; /* cleans a warning */ + } + ap = (tlb->perms >> (subpage * 2 + 4)) & 3; + if (!check_perms (state, ap, read)) { + if (tlb->mapping == TLB_SECTION) { + return SECTION_PERMISSION_FAULT; + } else { + return SUBPAGE_PERMISSION_FAULT; + } + } +#endif + } else { /* access == 3 */ + /* manager access - don't check perms */ + } + return NO_FAULT; +} +#endif + +#if 0 +fault_t +mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr) +#endif + +/* ap: AP bits value. + * sop: section or page description 0:section 1:page + */ +fault_t +mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop) +{ + { + /* walk the translation tables */ + ARMword l1addr, l1desc; + if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) { + l1addr = state->mmu.translation_table_base1; + l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3; + } else { + l1addr = state->mmu.translation_table_base0; + l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3; + } + + /* l1desc = mem_read_word (state, l1addr); */ + if (state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, l1addr, &l1desc, 4); + else + l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc); + + #if 0 + if (virt_addr == 0xc000d2bc) { + printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); + printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); + printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); + printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); + // exit(-1); + } + #endif + switch (l1desc & 3) { + case 0: + case 3: + /* + * according to Figure 3-9 Sequence for checking faults in arm manual, + * section translation fault should be returned here. + */ + { + return SECTION_TRANSLATION_FAULT; + } + case 1: + /* coarse page table */ + { + ARMword l2addr, l2desc; + + + l2addr = l1desc & 0xFFFFFC00; + l2addr = (l2addr | + ((virt_addr & 0x000FF000) >> 10)) & + ~3; + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, l2addr, &l2desc, 4); + else + l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc); + + /* chy 2003-09-02 for xscale */ + *ap = (l2desc >> 4) & 0x3; + *sop = 1; /* page */ + + switch (l2desc & 3) { + case 0: + return PAGE_TRANSLATION_FAULT; + break; + case 1: + *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF); + break; + case 2: + case 3: + *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF); + break; + + } + } + break; + case 2: + /* section */ + + *ap = (l1desc >> 10) & 3; + *sop = 0; /* section */ + #if 0 + if (virt_addr == 0xc000d2bc) { + printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); + printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); + printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); + printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); +// printf("l2addr is %x l2desc is %x\n", l2addr, l2desc); + printf("ap is %x, sop is %x\n", *ap, *sop); + printf("mode is %d\n", state->Mode); +// exit(-1); + } + #endif + + if (l1desc & 0x30000) + *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF); + else + *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF); + break; + } + } + return NO_FAULT; +} + + +static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, + ARMword data, ARMword datatype); +static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, + ARMword *data, ARMword datatype); + +int +arm1176jzf_s_mmu_init (ARMul_State *state) +{ + state->mmu.control = 0x50078; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + state->mmu.context_id = 0; + state->mmu.thread_uro_id = 0; + //invalidate_all_tlb(state); + + return No_exp; +} + +void +arm1176jzf_s_mmu_exit (ARMul_State *state) +{ +} + + +static fault_t +arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) +{ + fault_t fault; + int c; /* cache bit */ + ARMword pa; /* physical addr */ + ARMword perm; /* physical addr access permissions */ + int ap, sop; + + static int debug_count = 0; /* used for debug */ + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + if (MMU_Enabled) { +// printf("MMU enabled.\n"); +// sleep(1); + /* align check */ + if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } else + va &= ~(WORD_SIZE - 1); + + /* translate tlb */ + fault = mmu_translate (state, va, &pa, &ap, &sop); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault); + return fault; + } + + + /* no tlb, only check permission */ + if (!check_perms(state, ap, 1)) { + if (sop == 0) { + return SECTION_PERMISSION_FAULT; + } else { + return SUBPAGE_PERMISSION_FAULT; + } + } + +#if 0 + /*check access */ + fault = check_access (state, va, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } +#endif + } + + /*if MMU disabled or C flag is set alloc cache */ + if (MMU_Disabled) { +// printf("MMU disabled.\n"); +// sleep(1); + pa = va; + } + if(state->space.conf_obj == NULL) + state->space.read(state->space.conf_obj, pa, instr, 4); + else + *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr); + + return NO_FAULT; +} + +static fault_t +arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data) +{ + /* ARMword temp,offset; */ + fault_t fault; + fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); + return fault; +} + +static fault_t +arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr, + ARMword *data) +{ + /* ARMword temp,offset; */ + fault_t fault; + fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); + return fault; +} + +static fault_t +arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data) +{ + return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); +} + +static fault_t +arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, + ARMword datatype) +{ + fault_t fault; + ARMword pa, real_va, temp, offset; + ARMword perm; /* physical addr access permissions */ + int ap, sop; + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + real_va = va; + /* if MMU disabled, memory_read */ + if (MMU_Disabled) { +// printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va); +// sleep(1); + + /* *data = mem_read_word(state, va); */ + if (datatype == ARM_BYTE_TYPE) + /* *data = mem_read_byte (state, va); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, va, data, 1); + else + *data = Memory::Read8(va); //mem_read_raw(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* *data = mem_read_halfword (state, va); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, va, data, 2); + else + *data = Memory::Read16(va); //mem_read_raw(16, va, data); + else if (datatype == ARM_WORD_TYPE) + /* *data = mem_read_word (state, va); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, va, data, 4); + else + *data = Memory::Read32(va); //mem_read_raw(32, va, data); + else { + ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); + } + + return NO_FAULT; + } +// printf("MMU enabled.\n"); +// sleep(1); + + /* align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + + /* va &= ~(WORD_SIZE - 1); */ + #if 0 + uint32_t page_base; + page_base = get_phys_page(state, va); + if((page_base & 0xFFF) == 0){ + pa = (page_base << 12) | (va & 0xFFF); + goto skip_translation; + } + #endif + /*translate va to tlb */ +#if 0 + fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb); +#endif + fault = mmu_translate (state, va, &pa, &ap, &sop); +#if 0 + if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){ + //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); + printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); + int i; + for(i = 0; i < 16; i++) + printf("Reg[%d]=0x%x\t", i, state->Reg[i]); + printf("\n"); + } +#endif + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + //printf("mmu read fault at %x\n", va); + //printf("fault is %d\n", fault); + return fault; + } +// printf("va is %x pa is %x\n", va, pa); + + /* no tlb, only check permission */ + if (!check_perms(state, ap, 1)) { + if (sop == 0) { + return SECTION_PERMISSION_FAULT; + } else { + return SUBPAGE_PERMISSION_FAULT; + } + } +#if 0 + /*check access permission */ + fault = check_access (state, va, tlb, 1); + if (fault) + return fault; +#endif + + //insert_tlb(state, va, pa); +skip_translation: + /* *data = mem_read_word(state, pa); */ + if (datatype == ARM_BYTE_TYPE) { + /* *data = mem_read_byte (state, pa | (real_va & 3)); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1); + else + *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data); + /* mem_read_raw(32, pa | (real_va & 3), data); */ + } else if (datatype == ARM_HALFWORD_TYPE) { + /* *data = mem_read_halfword (state, pa | (real_va & 2)); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2); + else + *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data); + /* mem_read_raw(32, pa | (real_va & 2), data); */ + } else if (datatype == ARM_WORD_TYPE) + /* *data = mem_read_word (state, pa); */ + if(state->space.conf_obj != NULL) + state->space.read(state->space.conf_obj, pa , data, 4); + else + *data = Memory::Read32(pa); //mem_read_raw(32, pa, data); + else { + ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); + } + if(0 && (va == 0x2869c)){ + printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr); + } + + /* ldrex or ldrexb */ + if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) || + ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){ + int rn = (state->CurrInstr & 0xF0000) >> 16; + if(state->Reg[rn] == va){ + add_exclusive_addr(state, pa | (real_va & 3)); + state->exclusive_access_state = 1; + } + } +#if 0 + if (state->pc == 0xc011a868) { + printf("pa is %x value is %x size is %x\n", pa, data, datatype); + printf("icounter is %lld\n", state->NumInstrs); +// exit(-1); + } +#endif + + return NO_FAULT; +} + + +static fault_t +arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data) +{ + return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); +} + +static fault_t +arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr, + ARMword data) +{ + return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); +} + +static fault_t +arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data) +{ + return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); +} + + + +static fault_t +arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, + ARMword datatype) +{ + int b; + ARMword pa, real_va; + ARMword perm; /* physical addr access permissions */ + fault_t fault; + int ap, sop; + +#if 0 + /8 for sky_printk debugger.*/ + if (va == 0xffffffff) { + putchar((char)data); + return 0; + } + if (va == 0xBfffffff) { + putchar((char)data); + return 0; + } +#endif + + DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + va = mmu_pid_va_map (va); + real_va = va; + + if (MMU_Disabled) { + /* mem_write_word(state, va, data); */ + if (datatype == ARM_BYTE_TYPE) + /* mem_write_byte (state, va, data); */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, va, &data, 1); + else + Memory::Write8(va, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* mem_write_halfword (state, va, data); */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, va, &data, 2); + else + Memory::Write16(va, data); + else if (datatype == ARM_WORD_TYPE) + /* mem_write_word (state, va, data); */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, va, &data, 4); + else + Memory::Write32(va, data); + else { + ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype); + } + goto finished_write; + //return 0; + } + /*align check */ + /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + va &= ~(WORD_SIZE - 1); + #if 0 + uint32_t page_base; + page_base = get_phys_page(state, va); + if((page_base & 0xFFF) == 0){ + pa = (page_base << 12) | (va & 0xFFF); + goto skip_translation; + } + #endif + /*tlb translate */ + fault = mmu_translate (state, va, &pa, &ap, &sop); +#if 0 + if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){ + //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); + printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); + int i; + for(i = 0; i < 16; i++) + printf("Reg[%d]=0x%x\t", i, state->Reg[i]); + printf("\n"); + } +#endif + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + //printf("mmu write fault at %x\n", va); + return fault; + } +// printf("va is %x pa is %x\n", va, pa); + + /* no tlb, only check permission */ + if (!check_perms(state, ap, 0)) { + if (sop == 0) { + return SECTION_PERMISSION_FAULT; + } else { + return SUBPAGE_PERMISSION_FAULT; + } + } + +#if 0 + /* tlb check access */ + fault = check_access (state, va, tlb, 0); + if (fault) { + DEBUG_LOG(ARM11, "check_access\n"); + return fault; + } +#endif +#if 0 + if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) { + printf("pa is %x value is %x size is %x\n", pa, data, datatype); + } +#endif +#if 0 + if (state->pc == 0xc011a878) { + printf("write pa is %x value is %x size is %x\n", pa, data, datatype); + printf("icounter is %lld\n", state->NumInstrs); + exit(-1); + } +#endif + //insert_tlb(state, va, pa); +skip_translation: + /* strex */ + if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) || + ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){ + /* failed , the address is monitord now. */ + int dest_reg = (state->CurrInstr & 0xF000) >> 12; + if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){ + remove_exclusive(state, pa | (real_va & 3)); + state->Reg[dest_reg] = 0; + state->exclusive_access_state = 0; + } + else{ + state->Reg[dest_reg] = 1; + //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa); + return NO_FAULT; + } + } + + if (datatype == ARM_BYTE_TYPE) { + /* mem_write_byte (state, + (pa | (real_va & 3)), + data); + */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1); + else + Memory::Write8((pa | (real_va & 3)), data); + + } else if (datatype == ARM_HALFWORD_TYPE) + /* mem_write_halfword (state, + (pa | + (real_va & 2)), + data); + */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2); + else + Memory::Write16((pa | (real_va & 3)), data); + else if (datatype == ARM_WORD_TYPE) + /* mem_write_word (state, pa, data); */ + if(state->space.conf_obj != NULL) + state->space.write(state->space.conf_obj, pa, &data, 4); + else + Memory::Write32(pa, data); +#if 0 + if (state->NumInstrs > 236403) { + printf("write memory\n"); + printf("pa is %x value is %x size is %x\n", pa, data, datatype); + printf("icounter is %lld\n", state->NumInstrs); + } +#endif +finished_write: +#if DIFF_WRITE + if(state->icounter > state->debug_icounter){ + if(state->CurrWrite >= 17 ){ + printf("Wrong write array, 0x%x", state->CurrWrite); + exit(-1); + } + uint32 record_data = data; + if(datatype == ARM_BYTE_TYPE) + record_data &= 0xFF; + if(datatype == ARM_HALFWORD_TYPE) + record_data &= 0xFFFF; + + state->WriteAddr[state->CurrWrite] = pa | (real_va & 3); + state->WriteData[state->CurrWrite] = record_data; + state->WritePc[state->CurrWrite] = state->Reg[15]; + state->CurrWrite++; + //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag); + } +#endif + + return NO_FAULT; +} + +ARMword +arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value) +{ + int creg = BITS (16, 19) & 0xf; + int OPC_1 = BITS (21, 23) & 0x7; + int OPC_2 = BITS (5, 7) & 0x7; + ARMword data; + + switch (creg) { + case MMU_ID: + if (OPC_2 == 0) { + data = state->cpu->cpu_val; + } else if (OPC_2 == 1) { + /* Cache type: + * 000 0110 1 000 101 110 0 10 000 101 110 0 10 + * */ + data = 0x0D172172; + } + break; + case MMU_CONTROL: + /* + * 6:3 read as 1 + * 10 read as 0 + * 18,16 read as 1 + * */ + data = (state->mmu.control | 0x50078) & 0xFFFFFBFF; + break; + case MMU_TRANSLATION_TABLE_BASE: +#if 0 + data = state->mmu.translation_table_base; +#endif + switch (OPC_2) { + case 0: + data = state->mmu.translation_table_base0; + break; + case 1: + data = state->mmu.translation_table_base1; + break; + case 2: + data = state->mmu.translation_table_ctrl; + break; + default: + printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2); + break; + } + break; + case MMU_DOMAIN_ACCESS_CONTROL: + data = state->mmu.domain_access_control; + break; + case MMU_FAULT_STATUS: + /* OPC_2 = 0: data FSR value + * */ + if (OPC_2 == 0) + data = state->mmu.fault_status; + if (OPC_2 == 1) + data = state->mmu.fault_statusi; + break; + case MMU_FAULT_ADDRESS: + data = state->mmu.fault_address; + break; + case MMU_PID: + //data = state->mmu.process_id; + if(OPC_2 == 0) + data = state->mmu.process_id; + else if(OPC_2 == 1) + data = state->mmu.context_id; + else if(OPC_2 == 3){ + data = state->mmu.thread_uro_id; + } + else{ + printf ("mmu_mcr read UNKNOWN - reg %d\n", creg); + } + //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr); + //exit(-1); + break; + default: + printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); + data = 0; + break; + } +/* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */ + *value = data; + return data; +} + + +static ARMword +arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value) +{ + int creg = BITS (16, 19) & 0xf; + int CRm = BITS (0, 3) & 0xf; + int OPC_1 = BITS (21, 23) & 0x7; + int OPC_2 = BITS (5, 7) & 0x7; + if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) { + switch (creg) { + case MMU_CONTROL: + /* + * 6:3 read as 1 + * 10 read as 0 + * 18,16 read as 1 + * */ + if(OPC_2 == 0) + state->mmu.control = (value | 0x50078) & 0xFFFFFBFF; + else if(OPC_2 == 1) + state->mmu.auxiliary_control = value; + else if(OPC_2 == 2) + state->mmu.coprocessor_access_control = value; + else + fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2); + break; + case MMU_TRANSLATION_TABLE_BASE: + switch (OPC_2) { + /* int i; */ + case 0: +#if 0 + /* TTBR0 */ + if (state->mmu.translation_table_ctrl & 0x7) { + for (i = 0; i <= state->mmu.translation_table_ctrl; i++) + state->mmu.translation_table_base0 &= ~(1 << (5 + i)); + } +#endif + state->mmu.translation_table_base0 = (value); + break; + case 1: +#if 0 + /* TTBR1 */ + if (state->mmu.translation_table_ctrl & 0x7) { + for (i = 0; i <= state->mmu.translation_table_ctrl; i++) + state->mmu.translation_table_base1 &= 1 << (5 + i); + } +#endif + state->mmu.translation_table_base1 = (value); + break; + case 2: + /* TTBC */ + state->mmu.translation_table_ctrl = value & 0x7; + break; + default: + printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2); + break; + } + //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); + //invalidate_all_tlb(state); + break; + case MMU_DOMAIN_ACCESS_CONTROL: + /* printf("mmu_mcr wrote DACR "); */ + state->mmu.domain_access_control = value; + break; + + case MMU_FAULT_STATUS: + if (OPC_2 == 0) + state->mmu.fault_status = value & 0xFF; + if (OPC_2 == 1) { + printf("set fault status instr\n"); + } + break; + case MMU_FAULT_ADDRESS: + state->mmu.fault_address = value; + break; + + case MMU_CACHE_OPS: + break; + case MMU_TLB_OPS: + { + switch(CRm){ + case 5: /* ITLB */ + { + switch(OPC_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + break; + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + break; + } + case 6: /* DTLB */ + { + switch(OPC_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + break; + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + break; + } + case 7: /* Unified TLB */ + { + switch(OPC_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + break; + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + break; + } + + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm); + break; + } + //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr); + } + break; + case MMU_CACHE_LOCKDOWN: + /* + * FIXME: cache lock down*/ + break; + case MMU_TLB_LOCKDOWN: + printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); + /* FIXME:tlb lock down */ + break; + case MMU_PID: + //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); + //state->mmu.process_id = value; + /*0:24 should be zero. */ + //state->mmu.process_id = value & 0xfe000000; + if(OPC_2 == 0) + state->mmu.process_id = value; + else if(OPC_2 == 1) + state->mmu.context_id = value; + else if(OPC_2 == 3){ + state->mmu.thread_uro_id = value; + } + else{ + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + } + break; + + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + } + + return No_exp; +} + +///* teawater add for arm2x86 2005.06.19------------------------------------------- */ +//static int +//arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr, +// ARMword *phys_addr) +//{ +// fault_t fault; +// int ap, sop; +// +// ARMword perm; /* physical addr access permissions */ +// virt_addr = mmu_pid_va_map (virt_addr); +// if (MMU_Enabled) { +// +// /*align check */ +// if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { +// DEBUG_LOG(ARM11, "align\n"); +// return ALIGNMENT_FAULT; +// } else +// virt_addr &= ~(WORD_SIZE - 1); +// +// /*translate tlb */ +// fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop); +// if (fault) { +// DEBUG_LOG(ARM11, "translate\n"); +// return fault; +// } +// +// /* permission check */ +// if (!check_perms(state, ap, 1)) { +// if (sop == 0) { +// return SECTION_PERMISSION_FAULT; +// } else { +// return SUBPAGE_PERMISSION_FAULT; +// } +// } +//#if 0 +// /*check access */ +// fault = check_access (state, virt_addr, tlb, 1); +// if (fault) { +// DEBUG_LOG(ARM11, "check_fault\n"); +// return fault; +// } +//#endif +// } +// +// if (MMU_Disabled) { +// *phys_addr = virt_addr; +// } +// +// return 0; +//} + +/* AJ2D-------------------------------------------------------------------------- */ + +/*arm1176jzf-s mmu_ops_t*/ +mmu_ops_t arm1176jzf_s_mmu_ops = { + arm1176jzf_s_mmu_init, + arm1176jzf_s_mmu_exit, + arm1176jzf_s_mmu_read_byte, + arm1176jzf_s_mmu_write_byte, + arm1176jzf_s_mmu_read_halfword, + arm1176jzf_s_mmu_write_halfword, + arm1176jzf_s_mmu_read_word, + arm1176jzf_s_mmu_write_word, + arm1176jzf_s_mmu_load_instr, + arm1176jzf_s_mmu_mcr, + arm1176jzf_s_mmu_mrc +/* teawater add for arm2x86 2005.06.19------------------------------------------- */ +/* arm1176jzf_s_mmu_v2p_dbct, */ +/* AJ2D-------------------------------------------------------------------------- */ +}; diff --git a/src/core/arm/mmu/arm1176jzf_s_mmu.h b/src/core/arm/mmu/arm1176jzf_s_mmu.h new file mode 100644 index 00000000..299c6b46 --- /dev/null +++ b/src/core/arm/mmu/arm1176jzf_s_mmu.h @@ -0,0 +1,37 @@ +/* + arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation. + + 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 +*/ + +#ifndef _ARM1176JZF_S_MMU_H_ +#define _ARM1176JZF_S_MMU_H_ + +#if 0 +typedef struct arm1176jzf-s_mmu_s +{ + tlb_t i_tlb; + cache_t i_cache; + + tlb_t d_tlb; + cache_t d_cache; + wb_t wb_t; +} arm1176jzf-s_mmu_t; +#endif +extern mmu_ops_t arm1176jzf_s_mmu_ops; + +ARMword +arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value); +#endif /*_ARM1176JZF_S_MMU_H_*/ diff --git a/src/core/arm/mmu/cache.h b/src/core/arm/mmu/cache.h new file mode 100644 index 00000000..d308d9b8 --- /dev/null +++ b/src/core/arm/mmu/cache.h @@ -0,0 +1,168 @@ +#ifndef _MMU_CACHE_H_ +#define _MMU_CACHE_H_ + +typedef struct cache_line_t +{ + ARMword tag; /* cache line align address | + bit2: last half dirty + bit1: first half dirty + bit0: cache valid flag + */ + ARMword pa; /*physical address */ + ARMword *data; /*array of cached data */ +} cache_line_t; +#define TAG_VALID_FLAG 0x00000001 +#define TAG_FIRST_HALF_DIRTY 0x00000002 +#define TAG_LAST_HALF_DIRTY 0x00000004 + +/*cache set association*/ +typedef struct cache_set_s +{ + cache_line_t *lines; + int cycle; +} cache_set_t; + +enum +{ + CACHE_WRITE_BACK, + CACHE_WRITE_THROUGH, +}; + +typedef struct cache_s +{ + int width; /*bytes in a line */ + int way; /*way of set asscociate */ + int set; /*num of set */ + int w_mode; /*write back or write through */ + //int a_mode; /*alloc mode: random or round-bin*/ + cache_set_t *sets; + /**/} cache_s; + +typedef struct cache_desc_s +{ + int width; + int way; + int set; + int w_mode; +// int a_mode; +} cache_desc_t; + + +/*virtual address to cache set index*/ +#define va_cache_set(va, cache_t) \ + (((va) / (cache_t)->width) & ((cache_t)->set - 1)) +/*virtual address to cahce line aligned*/ +#define va_cache_align(va, cache_t) \ + ((va) & ~((cache_t)->width - 1)) +/*virtaul address to cache line word index*/ +#define va_cache_index(va, cache_t) \ + (((va) & ((cache_t)->width - 1)) >> WORD_SHT) + +/*see Page 558 in arm manual*/ +/*set/index format value to cache set value*/ +#define index_cache_set(index, cache_t) \ + (((index) / (cache_t)->width) & ((cache_t)->set - 1)) + +/*************************cache********************/ +/* mmu cache init + * + * @cache_t :cache_t to init + * @width :cache line width in byte + * @way :way of each cache set + * @set :cache set num + * @w_mode :cache w_mode + * + * $ -1: error + * 0: sucess + */ +int +mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode); + +/* free a cache_t's inner data, the ptr self is not freed, + * when needed do like below: + * mmu_cache_exit(cache); + * free(cache_t); + * + * @cache_t : the cache_t to free + */ +void mmu_cache_exit (cache_s * cache_t); + +/* mmu cache search + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @va :virtual address + * + * $ NULL: no cache match + * cache :cache matched + * */ +cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t, + ARMword va); + +/* mmu cache search by set/index + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @index :set/index value. + * + * $ NULL: no cache match + * cache :cache matched + * */ + +cache_line_t *mmu_cache_search_by_index (ARMul_State * state, + cache_s * cache_t, ARMword index); + +/* mmu cache alloc + * + * @state :ARMul_State + * @cache_t :cache_t to alloc from + * @va :virtual address that require cache alloc, need not cache aligned + * @pa :physical address of va + * + * $ cache_alloced, always alloc OK + */ +cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, + ARMword va, ARMword pa); + +/* mmu_cache_write_back write cache data to memory + * + * @state: + * @cache_t :cache_t of the cache line + * @cache : cache line + */ +void +mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, + cache_line_t * cache); + +/* mmu_cache_clean: clean a cache of va in cache_t + * + * @state :ARMul_State + * @cache_t :cache_t to clean + * @va :virtaul address + */ +void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va); +void +mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index); + +/* mmu_cache_invalidate : invalidate a cache of va + * + * @state :ARMul_State + * @cache_t :cache_t to invalid + * @va :virt_addr to invalid + */ +void +mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va); + +void +mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index); + +void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t); + +void +mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa); + +cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t); + +#endif /*_MMU_CACHE_H_*/ diff --git a/src/core/arm/mmu/rb.h b/src/core/arm/mmu/rb.h new file mode 100644 index 00000000..7bf0ebb2 --- /dev/null +++ b/src/core/arm/mmu/rb.h @@ -0,0 +1,55 @@ +#ifndef _MMU_RB_H +#define _MMU_RB_H + +enum rb_type_t +{ + RB_INVALID = 0, //invalid + RB_1, //1 word + RB_4, //4 word + RB_8, //8 word +}; + +/*bytes of each rb_type*/ +extern ARMword rb_masks[]; + +#define RB_WORD_NUM 8 +typedef struct rb_entry_s +{ + ARMword data[RB_WORD_NUM]; //array to store data + ARMword va; //first word va + int type; //rb type + fault_t fault; //fault set by rb alloc +} rb_entry_t; + +typedef struct rb_s +{ + int num; + rb_entry_t *entrys; +} rb_s; + +/*mmu_rb_init + * @rb_t :rb_t to init + * @num :number of entry + * */ +int mmu_rb_init (rb_s * rb_t, int num); + +/*mmu_rb_exit*/ +void mmu_rb_exit (rb_s * rb_t); + + +/*mmu_rb_search + * @rb_t :rb_t to serach + * @va :va address to math + * + * $ NULL :not match + * NO-NULL: + * */ +rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va); + + +void mmu_rb_invalidate_entry (rb_s * rb_t, int i); +void mmu_rb_invalidate_all (rb_s * rb_t); +void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, + int type, ARMword va); + +#endif /*_MMU_RB_H_*/ diff --git a/src/core/arm/mmu/tlb.h b/src/core/arm/mmu/tlb.h new file mode 100644 index 00000000..938c0178 --- /dev/null +++ b/src/core/arm/mmu/tlb.h @@ -0,0 +1,94 @@ +#ifndef _MMU_TLB_H_ +#define _MMU_TLB_H_ + +typedef enum tlb_mapping_t +{ + TLB_INVALID = 0, + TLB_SMALLPAGE = 1, + TLB_LARGEPAGE = 2, + TLB_SECTION = 3, + TLB_ESMALLPAGE = 4, + TLB_TINYPAGE = 5 +} tlb_mapping_t; + +extern ARMword tlb_masks[]; + +/* Permissions bits in a TLB entry: + * + * 31 12 11 10 9 8 7 6 5 4 3 2 1 0 + * +-------------+-----+-----+-----+-----+---+---+-------+ + * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | | + * +-------------+-----+-----+-----+-----+---+---+-------+ + * + * 31 12 11 10 9 4 3 2 1 0 + * +-------------+-----+-----------------+---+---+-------+ + * Section: | | AP | | C | B | | + * +-------------+-----+-----------------+---+---+-------+ + */ + +/* +section: + section base address [31:20] + AP - table 8-2, page 8-8 + domain + C,B + +page: + page base address [31:16] or [31:12] + ap[3:0] + domain (from L1) + C,B +*/ + + +typedef struct tlb_entry_t +{ + ARMword virt_addr; + ARMword phys_addr; + ARMword perms; + ARMword domain; + tlb_mapping_t mapping; +} tlb_entry_t; + +typedef struct tlb_s +{ + int num; /*num of tlb entry */ + int cycle; /*current tlb cycle */ + tlb_entry_t *entrys; +} tlb_s; + + +#define tlb_c_flag(tlb) \ + ((tlb)->perms & 0x8) +#define tlb_b_flag(tlb) \ + ((tlb)->perms & 0x4) + +#define tlb_va_to_pa(tlb, va) \ +(\ + {\ + ARMword mask = tlb_masks[tlb->mapping]; \ + (tlb->phys_addr & mask) | (va & ~mask);\ + }\ +) + +fault_t +check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, + int read); + +fault_t +translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, + tlb_entry_t ** tlb); + +int mmu_tlb_init (tlb_s * tlb_t, int num); + +void mmu_tlb_exit (tlb_s * tlb_t); + +void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t); + +void +mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr); + +tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, + ARMword virt_addr); + +#endif /*_MMU_TLB_H_*/ diff --git a/src/core/arm/mmu/wb.h b/src/core/arm/mmu/wb.h new file mode 100644 index 00000000..8fb7de94 --- /dev/null +++ b/src/core/arm/mmu/wb.h @@ -0,0 +1,63 @@ +#ifndef _MMU_WB_H_ +#define _MMU_WB_H_ + +typedef struct wb_entry_s +{ + ARMword pa; //phy_addr + ARMbyte *data; //data + int nb; //number byte to write +} wb_entry_t; + +typedef struct wb_s +{ + int num; //number of wb_entry + int nb; //number of byte of each entry + int first; // + int last; // + int used; // + wb_entry_t *entrys; +} wb_s; + +typedef struct wb_desc_s +{ + int num; + int nb; +} wb_desc_t; + +/* wb_init + * @wb_t :wb_t to init + * @num :num of entrys + * @nw :num of word of each entry + * + * $ -1:error + * 0:ok + * */ +int mmu_wb_init (wb_s * wb_t, int num, int nb); + + +/* wb_exit + * @wb_t :wb_t to exit + * */ +void mmu_wb_exit (wb_s * wb); + + +/* wb_write_bytes :put bytess in Write Buffer + * @state: ARMul_State + * @wb_t: write buffer + * @pa: physical address + * @data: data ptr + * @n number of byte to write + * + * Note: write buffer merge is not implemented, can be done late + * */ +void +mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa, + ARMbyte * data, int n); + + +/* wb_drain_all + * @wb_t wb_t to drain + * */ +void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t); + +#endif /*_MMU_WB_H_*/ diff --git a/src/core/core.cpp b/src/core/core.cpp new file mode 100644 index 00000000..540b20f2 --- /dev/null +++ b/src/core/core.cpp @@ -0,0 +1,58 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "log.h" +#include "core.h" +#include "mem_map.h" +#include "hw/hw.h" +#include "arm/disassembler/arm_disasm.h" +#include "arm/interpreter/arm_interpreter.h" + +namespace Core { + +ARM_Disasm* g_disasm = NULL; ///< ARM disassembler +ARM_Interface* g_app_core = NULL; ///< ARM11 application core +ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core + +/// Run the core CPU loop +void RunLoop() { + // TODO(ShizZy): ImplementMe +} + +/// Step the CPU one instruction +void SingleStep() { + g_app_core->Step(); + HW::Update(); +} + +/// Halt the core +void Halt(const char *msg) { + // TODO(ShizZy): ImplementMe +} + +/// Kill the core +void Stop() { + // TODO(ShizZy): ImplementMe +} + +/// Initialize the core +int Init() { + NOTICE_LOG(MASTER_LOG, "Core initialized OK"); + + g_disasm = new ARM_Disasm(); + g_app_core = new ARM_Interpreter(); + g_sys_core = new ARM_Interpreter(); + + return 0; +} + +void Shutdown() { + delete g_disasm; + delete g_app_core; + delete g_sys_core; + + NOTICE_LOG(MASTER_LOG, "Core shutdown OK"); +} + +} // namespace diff --git a/src/core/core.h b/src/core/core.h new file mode 100644 index 00000000..bae9f3e3 --- /dev/null +++ b/src/core/core.h @@ -0,0 +1,40 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "arm/arm_interface.h" +#include "arm/interpreter/armdefs.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace Core { + +extern ARM_Interface* g_app_core; ///< ARM11 application core +extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Start the core +void Start(); + +/// Run the core CPU loop +void RunLoop(); + +/// Step the CPU one instruction +void SingleStep(); + +/// Halt the core +void Halt(const char *msg); + +/// Kill the core +void Stop(); + +/// Initialize the core +int Init(); + +/// Shutdown the core +void Shutdown(); + +} // namespace diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp new file mode 100644 index 00000000..78bbaafe --- /dev/null +++ b/src/core/core_timing.cpp @@ -0,0 +1,623 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "msg_handler.h" +#include "std_mutex.h" +#include "atomic.h" +#include "core_timing.h" +#include "core.h" +#include "chunk_file.h" + +int g_clock_rate_arm11 = 268123480; + +// is this really necessary? +#define INITIAL_SLICE_LENGTH 20000 +#define MAX_SLICE_LENGTH 100000000 + +namespace CoreTiming +{ + +struct EventType +{ + EventType() {} + + EventType(TimedCallback cb, const char *n) + : callback(cb), name(n) {} + + TimedCallback callback; + const char *name; +}; + +std::vector event_types; + +struct BaseEvent +{ + s64 time; + u64 userdata; + int type; + // Event *next; +}; + +typedef LinkedListItem Event; + +Event *first; +Event *tsFirst; +Event *tsLast; + +// event pools +Event *eventPool = 0; +Event *eventTsPool = 0; +int allocatedTsEvents = 0; +// Optimization to skip MoveEvents when possible. +volatile u32 hasTsEvents = false; + +// Downcount has been moved to currentMIPS, to save a couple of clocks in every ARM JIT block +// as we can already reach that structure through a register. +int slicelength; + +MEMORY_ALIGNED16(s64) globalTimer; +s64 idledCycles; + +static std::recursive_mutex externalEventSection; + +// Warning: not included in save state. +void(*advanceCallback)(int cyclesExecuted) = NULL; + +void SetClockFrequencyMHz(int cpuMhz) +{ + g_clock_rate_arm11 = cpuMhz * 1000000; + // TODO: Rescale times of scheduled events? +} + +int GetClockFrequencyMHz() +{ + return g_clock_rate_arm11 / 1000000; +} + + +Event* GetNewEvent() +{ + if (!eventPool) + return new Event; + + Event* ev = eventPool; + eventPool = ev->next; + return ev; +} + +Event* GetNewTsEvent() +{ + allocatedTsEvents++; + + if (!eventTsPool) + return new Event; + + Event* ev = eventTsPool; + eventTsPool = ev->next; + return ev; +} + +void FreeEvent(Event* ev) +{ + ev->next = eventPool; + eventPool = ev; +} + +void FreeTsEvent(Event* ev) +{ + ev->next = eventTsPool; + eventTsPool = ev; + allocatedTsEvents--; +} + +int RegisterEvent(const char *name, TimedCallback callback) +{ + event_types.push_back(EventType(callback, name)); + return (int)event_types.size() - 1; +} + +void AntiCrashCallback(u64 userdata, int cyclesLate) +{ + ERROR_LOG(TIME, "Savestate broken: an unregistered event was called."); + Core::Halt("invalid timing events"); +} + +void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback) +{ + if (event_type >= (int)event_types.size()) + event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT")); + + event_types[event_type] = EventType(callback, name); +} + +void UnregisterAllEvents() +{ + if (first) + PanicAlert("Cannot unregister events with events pending"); + event_types.clear(); +} + +void Init() +{ + //currentMIPS->downcount = INITIAL_SLICE_LENGTH; + //slicelength = INITIAL_SLICE_LENGTH; + globalTimer = 0; + idledCycles = 0; + hasTsEvents = 0; +} + +void Shutdown() +{ + MoveEvents(); + ClearPendingEvents(); + UnregisterAllEvents(); + + while (eventPool) + { + Event *ev = eventPool; + eventPool = ev->next; + delete ev; + } + + std::lock_guard lk(externalEventSection); + while (eventTsPool) + { + Event *ev = eventTsPool; + eventTsPool = ev->next; + delete ev; + } +} + +u64 GetTicks() +{ + ERROR_LOG(TIME, "Unimplemented function!"); + return 0; + //return (u64)globalTimer + slicelength - currentMIPS->downcount; +} + +u64 GetIdleTicks() +{ + return (u64)idledCycles; +} + + +// This is to be called when outside threads, such as the graphics thread, wants to +// schedule things to be executed on the main thread. +void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata) +{ + std::lock_guard lk(externalEventSection); + Event *ne = GetNewTsEvent(); + ne->time = GetTicks() + cyclesIntoFuture; + ne->type = event_type; + ne->next = 0; + ne->userdata = userdata; + if (!tsFirst) + tsFirst = ne; + if (tsLast) + tsLast->next = ne; + tsLast = ne; + + Common::AtomicStoreRelease(hasTsEvents, 1); +} + +// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread +// in which case the event will get handled immediately, before returning. +void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) +{ + if (false) //Core::IsCPUThread()) + { + std::lock_guard lk(externalEventSection); + event_types[event_type].callback(userdata, 0); + } + else + ScheduleEvent_Threadsafe(0, event_type, userdata); +} + +void ClearPendingEvents() +{ + while (first) + { + Event *e = first->next; + FreeEvent(first); + first = e; + } +} + +void AddEventToQueue(Event* ne) +{ + Event* prev = NULL; + Event** pNext = &first; + for (;;) + { + Event*& next = *pNext; + if (!next || ne->time < next->time) + { + ne->next = next; + next = ne; + break; + } + prev = next; + pNext = &prev->next; + } +} + +// This must be run ONLY from within the cpu thread +// cyclesIntoFuture may be VERY inaccurate if called from anything else +// than Advance +void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) +{ + Event *ne = GetNewEvent(); + ne->userdata = userdata; + ne->type = event_type; + ne->time = GetTicks() + cyclesIntoFuture; + AddEventToQueue(ne); +} + +// Returns cycles left in timer. +s64 UnscheduleEvent(int event_type, u64 userdata) +{ + s64 result = 0; + if (!first) + return result; + while (first) + { + if (first->type == event_type && first->userdata == userdata) + { + result = first->time - globalTimer; + + Event *next = first->next; + FreeEvent(first); + first = next; + } + else + { + break; + } + } + if (!first) + return result; + Event *prev = first; + Event *ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type && ptr->userdata == userdata) + { + result = ptr->time - globalTimer; + + prev->next = ptr->next; + FreeEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } + + return result; +} + +s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) +{ + s64 result = 0; + std::lock_guard lk(externalEventSection); + if (!tsFirst) + return result; + while (tsFirst) + { + if (tsFirst->type == event_type && tsFirst->userdata == userdata) + { + result = tsFirst->time - globalTimer; + + Event *next = tsFirst->next; + FreeTsEvent(tsFirst); + tsFirst = next; + } + else + { + break; + } + } + if (!tsFirst) + { + tsLast = NULL; + return result; + } + + Event *prev = tsFirst; + Event *ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type && ptr->userdata == userdata) + { + result = ptr->time - globalTimer; + + prev->next = ptr->next; + if (ptr == tsLast) + tsLast = prev; + FreeTsEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } + + return result; +} + +// Warning: not included in save state. +void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted)) +{ + advanceCallback = callback; +} + +bool IsScheduled(int event_type) +{ + if (!first) + return false; + Event *e = first; + while (e) { + if (e->type == event_type) + return true; + e = e->next; + } + return false; +} + +void RemoveEvent(int event_type) +{ + if (!first) + return; + while (first) + { + if (first->type == event_type) + { + Event *next = first->next; + FreeEvent(first); + first = next; + } + else + { + break; + } + } + if (!first) + return; + Event *prev = first; + Event *ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type) + { + prev->next = ptr->next; + FreeEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } +} + +void RemoveThreadsafeEvent(int event_type) +{ + std::lock_guard lk(externalEventSection); + if (!tsFirst) + { + return; + } + while (tsFirst) + { + if (tsFirst->type == event_type) + { + Event *next = tsFirst->next; + FreeTsEvent(tsFirst); + tsFirst = next; + } + else + { + break; + } + } + if (!tsFirst) + { + tsLast = NULL; + return; + } + Event *prev = tsFirst; + Event *ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type) + { + prev->next = ptr->next; + if (ptr == tsLast) + tsLast = prev; + FreeTsEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } +} + +void RemoveAllEvents(int event_type) +{ + RemoveThreadsafeEvent(event_type); + RemoveEvent(event_type); +} + +//This raise only the events required while the fifo is processing data +void ProcessFifoWaitEvents() +{ + while (first) + { + if (first->time <= globalTimer) + { + // LOG(TIMER, "[Scheduler] %s (%lld, %lld) ", + // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time); + Event* evt = first; + first = first->next; + event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); + FreeEvent(evt); + } + else + { + break; + } + } +} + +void MoveEvents() +{ + Common::AtomicStoreRelease(hasTsEvents, 0); + + std::lock_guard lk(externalEventSection); + // Move events from async queue into main queue + while (tsFirst) + { + Event *next = tsFirst->next; + AddEventToQueue(tsFirst); + tsFirst = next; + } + tsLast = NULL; + + // Move free events to threadsafe pool + while (allocatedTsEvents > 0 && eventPool) + { + Event *ev = eventPool; + eventPool = ev->next; + ev->next = eventTsPool; + eventTsPool = ev; + allocatedTsEvents--; + } +} + +void Advance() +{ + ERROR_LOG(TIME, "Unimplemented function!"); + //int cyclesExecuted = slicelength - currentMIPS->downcount; + //globalTimer += cyclesExecuted; + //currentMIPS->downcount = slicelength; + + //if (Common::AtomicLoadAcquire(hasTsEvents)) + // MoveEvents(); + //ProcessFifoWaitEvents(); + + //if (!first) + //{ + // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000"); + // currentMIPS->downcount += 10000; + //} + //else + //{ + // slicelength = (int)(first->time - globalTimer); + // if (slicelength > MAX_SLICE_LENGTH) + // slicelength = MAX_SLICE_LENGTH; + // currentMIPS->downcount = slicelength; + //} + //if (advanceCallback) + // advanceCallback(cyclesExecuted); +} + +void LogPendingEvents() +{ + Event *ptr = first; + while (ptr) + { + //INFO_LOG(TIMER, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type); + ptr = ptr->next; + } +} + +void Idle(int maxIdle) +{ + ERROR_LOG(TIME, "Unimplemented function!"); + //int cyclesDown = currentMIPS->downcount; + //if (maxIdle != 0 && cyclesDown > maxIdle) + // cyclesDown = maxIdle; + + //if (first && cyclesDown > 0) + //{ + // int cyclesExecuted = slicelength - currentMIPS->downcount; + // int cyclesNextEvent = (int) (first->time - globalTimer); + + // if (cyclesNextEvent < cyclesExecuted + cyclesDown) + // { + // cyclesDown = cyclesNextEvent - cyclesExecuted; + // // Now, now... no time machines, please. + // if (cyclesDown < 0) + // cyclesDown = 0; + // } + //} + + //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f)); + + //idledCycles += cyclesDown; + //currentMIPS->downcount -= cyclesDown; + //if (currentMIPS->downcount == 0) + // currentMIPS->downcount = -1; +} + +std::string GetScheduledEventsSummary() +{ + Event *ptr = first; + std::string text = "Scheduled events\n"; + text.reserve(1000); + while (ptr) + { + unsigned int t = ptr->type; + if (t >= event_types.size()) + PanicAlert("Invalid event type"); // %i", t); + const char *name = event_types[ptr->type].name; + if (!name) + name = "[unknown]"; + char temp[512]; + sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); + text += temp; + ptr = ptr->next; + } + return text; +} + +void Event_DoState(PointerWrap &p, BaseEvent *ev) +{ + p.Do(*ev); +} + +void DoState(PointerWrap &p) +{ + std::lock_guard lk(externalEventSection); + + auto s = p.Section("CoreTiming", 1); + if (!s) + return; + + int n = (int)event_types.size(); + p.Do(n); + // These (should) be filled in later by the modules. + event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT")); + + p.DoLinkedList(first, (Event **)NULL); + p.DoLinkedList(tsFirst, &tsLast); + + p.Do(g_clock_rate_arm11); + p.Do(slicelength); + p.Do(globalTimer); + p.Do(idledCycles); +} + +} // namespace diff --git a/src/core/core_timing.h b/src/core/core_timing.h new file mode 100644 index 00000000..b62acea6 --- /dev/null +++ b/src/core/core_timing.h @@ -0,0 +1,109 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// This is a system to schedule events into the emulated machine's future. Time is measured +// in main CPU clock cycles. + +// To schedule an event, you first have to register its type. This is where you pass in the +// callback. You then schedule events using the type id you get back. + +// See HW/SystemTimers.cpp for the main part of Dolphin's usage of this scheduler. + +// The int cyclesLate that the callbacks get is how many cycles late it was. +// So to schedule a new event on a regular basis: +// inside callback: +// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") + +#include "common.h" + +class PointerWrap; + +extern int g_clock_rate_arm11; + +inline s64 msToCycles(int ms) { + return g_clock_rate_arm11 / 1000 * ms; +} + +inline s64 msToCycles(float ms) { + return (s64)(g_clock_rate_arm11 * ms * (0.001f)); +} + +inline s64 msToCycles(double ms) { + return (s64)(g_clock_rate_arm11 * ms * (0.001)); +} + +inline s64 usToCycles(float us) { + return (s64)(g_clock_rate_arm11 * us * (0.000001f)); +} + +inline s64 usToCycles(int us) { + return (g_clock_rate_arm11 / 1000000 * (s64)us); +} + +inline s64 usToCycles(s64 us) { + return (g_clock_rate_arm11 / 1000000 * us); +} + +inline s64 usToCycles(u64 us) { + return (s64)(g_clock_rate_arm11 / 1000000 * us); +} + +inline s64 cyclesToUs(s64 cycles) { + return cycles / (g_clock_rate_arm11 / 1000000); +} + +namespace CoreTiming { + +void Init(); +void Shutdown(); + +typedef void(*TimedCallback)(u64 userdata, int cyclesLate); + +u64 GetTicks(); +u64 GetIdleTicks(); + +// Returns the event_type identifier. +int RegisterEvent(const char *name, TimedCallback callback); +// For save states. +void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback); +void UnregisterAllEvents(); + +// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, +// when we implement state saves. +void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata = 0); +void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata = 0); +void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata = 0); +s64 UnscheduleEvent(int event_type, u64 userdata); +s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata); + +void RemoveEvent(int event_type); +void RemoveThreadsafeEvent(int event_type); +void RemoveAllEvents(int event_type); +bool IsScheduled(int event_type); +void Advance(); +void MoveEvents(); +void ProcessFifoWaitEvents(); + +// Pretend that the main CPU has executed enough cycles to reach the next event. +void Idle(int maxIdle = 0); + +// Clear all pending events. This should ONLY be done on exit or state load. +void ClearPendingEvents(); + +void LogPendingEvents(); + +// Warning: not included in save states. +void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted)); + +std::string GetScheduledEventsSummary(); + +void DoState(PointerWrap &p); + +void SetClockFrequencyMHz(int cpuMhz); +int GetClockFrequencyMHz(); +extern int slicelength; + +}; // namespace diff --git a/src/core/elf/elf_reader.cpp b/src/core/elf/elf_reader.cpp new file mode 100644 index 00000000..aef7c13e --- /dev/null +++ b/src/core/elf/elf_reader.cpp @@ -0,0 +1,239 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "common.h" +#include "mem_map.h" + +#include "elf/elf_reader.h" +//#include "Core/Debugger/Debugger_SymbolMap.h" +//#include "Core/HW/Memmap.h" +//#include "Core/PowerPC/PPCSymbolDB.h" + +//void bswap(Elf32_Word &w) {w = Common::swap32(w);} +//void bswap(Elf32_Half &w) {w = Common::swap16(w);} + +#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway + +static void byteswapHeader(Elf32_Ehdr &ELF_H) +{ + bswap(ELF_H.e_type); + bswap(ELF_H.e_machine); + bswap(ELF_H.e_ehsize); + bswap(ELF_H.e_phentsize); + bswap(ELF_H.e_phnum); + bswap(ELF_H.e_shentsize); + bswap(ELF_H.e_shnum); + bswap(ELF_H.e_shstrndx); + bswap(ELF_H.e_version); + bswap(ELF_H.e_entry); + bswap(ELF_H.e_phoff); + bswap(ELF_H.e_shoff); + bswap(ELF_H.e_flags); +} + +static void byteswapSegment(Elf32_Phdr &sec) +{ + bswap(sec.p_align); + bswap(sec.p_filesz); + bswap(sec.p_flags); + bswap(sec.p_memsz); + bswap(sec.p_offset); + bswap(sec.p_paddr); + bswap(sec.p_vaddr); + bswap(sec.p_type); +} + +static void byteswapSection(Elf32_Shdr &sec) +{ + bswap(sec.sh_addr); + bswap(sec.sh_addralign); + bswap(sec.sh_entsize); + bswap(sec.sh_flags); + bswap(sec.sh_info); + bswap(sec.sh_link); + bswap(sec.sh_name); + bswap(sec.sh_offset); + bswap(sec.sh_size); + bswap(sec.sh_type); +} + +ElfReader::ElfReader(void *ptr) +{ + base = (char*)ptr; + base32 = (u32 *)ptr; + header = (Elf32_Ehdr*)ptr; + byteswapHeader(*header); + + segments = (Elf32_Phdr *)(base + header->e_phoff); + sections = (Elf32_Shdr *)(base + header->e_shoff); + + //for (int i = 0; i < GetNumSegments(); i++) + //{ + // byteswapSegment(segments[i]); + //} + + //for (int i = 0; i < GetNumSections(); i++) + //{ + // byteswapSection(sections[i]); + //} + entryPoint = header->e_entry; +} + +const char *ElfReader::GetSectionName(int section) const +{ + if (sections[section].sh_type == SHT_NULL) + return nullptr; + + int nameOffset = sections[section].sh_name; + char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); + + if (ptr) + return ptr + nameOffset; + else + return nullptr; +} + +bool ElfReader::LoadInto(u32 vaddr) +{ + DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); + +// sectionOffsets = new u32[GetNumSections()]; +// sectionAddrs = new u32[GetNumSections()]; + + // Should we relocate? + bRelocate = (header->e_type != ET_EXEC); + + if (bRelocate) + { + DEBUG_LOG(MASTER_LOG,"Relocatable module"); + entryPoint += vaddr; + } + else + { + DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); + } + + INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); + + // First pass : Get the bits into RAM + u32 segmentVAddr[32]; + + u32 baseAddress = bRelocate?vaddr:0; + + for (int i = 0; i < header->e_phnum; i++) + { + Elf32_Phdr *p = segments + i; + + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); + + if (p->p_type == PT_LOAD) + { + segmentVAddr[i] = baseAddress + p->p_vaddr; + u32 writeAddr = segmentVAddr[i]; + + const u8 *src = GetSegmentPtr(i); + u8 *dst = Memory::GetPointer(writeAddr); + u32 srcSize = p->p_filesz; + u32 dstSize = p->p_memsz; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = /*_byteswap_ulong*/(*s++); + } + if (srcSize < dstSize) + { + //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss + } + INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); + } + } + + /* + LOG(MASTER_LOG,"%i sections:", header->e_shnum); + + for (int i=0; ish_addr + baseAddress; + sectionOffsets[i] = writeAddr - vaddr; + sectionAddrs[i] = writeAddr; + + if (s->sh_flags & SHF_ALLOC) + { + LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size); + + } + else + { + LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags); + } + } +*/ + INFO_LOG(MASTER_LOG,"Done loading."); + return true; +} + +SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const +{ + for (int i = firstSection; i < header->e_shnum; i++) + { + const char *secname = GetSectionName(i); + + if (secname != nullptr && strcmp(name, secname) == 0) + return i; + } + return -1; +} + +/* TODO(bunnei): The following is verbatim from Dolphin - needs to be updated for this project: + +bool ElfReader::LoadSymbols() +{ + bool hasSymbols = false; + SectionID sec = GetSectionByName(".symtab"); + if (sec != -1) + { + int stringSection = sections[sec].sh_link; + const char *stringBase = (const char *)GetSectionDataPtr(stringSection); + + //We have a symbol table! + Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); + int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); + for (int sym = 0; sym < numSymbols; sym++) + { + int size = Common::swap32(symtab[sym].st_size); + if (size == 0) + continue; + + // int bind = symtab[sym].st_info >> 4; + int type = symtab[sym].st_info & 0xF; + int sectionIndex = Common::swap16(symtab[sym].st_shndx); + int value = Common::swap32(symtab[sym].st_value); + const char *name = stringBase + Common::swap32(symtab[sym].st_name); + if (bRelocate) + value += sectionAddrs[sectionIndex]; + + int symtype = Symbol::SYMBOL_DATA; + switch (type) + { + case STT_OBJECT: + symtype = Symbol::SYMBOL_DATA; break; + case STT_FUNC: + symtype = Symbol::SYMBOL_FUNCTION; break; + default: + continue; + } + g_symbolDB.AddKnownSymbol(value, size, name, symtype); + hasSymbols = true; + } + } + g_symbolDB.Index(); + return hasSymbols; +} +*/ diff --git a/src/core/elf/elf_reader.h b/src/core/elf/elf_reader.h new file mode 100644 index 00000000..9393a589 --- /dev/null +++ b/src/core/elf/elf_reader.h @@ -0,0 +1,75 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "elf/elf_types.h" + +enum KnownElfTypes +{ + KNOWNELF_PSP = 0, + KNOWNELF_DS = 1, + KNOWNELF_GBA = 2, + KNOWNELF_GC = 3, +}; + +typedef int SectionID; + +class ElfReader +{ +private: + char *base; + u32 *base32; + + Elf32_Ehdr *header; + Elf32_Phdr *segments; + Elf32_Shdr *sections; + + u32 *sectionAddrs; + bool bRelocate; + u32 entryPoint; + +public: + ElfReader(void *ptr); + ~ElfReader() { } + + u32 Read32(int off) const { return base32[off>>2]; } + + // Quick accessors + ElfType GetType() const { return (ElfType)(header->e_type); } + ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } + u32 GetEntryPoint() const { return entryPoint; } + u32 GetFlags() const { return (u32)(header->e_flags); } + bool LoadInto(u32 vaddr); + bool LoadSymbols(); + + int GetNumSegments() const { return (int)(header->e_phnum); } + int GetNumSections() const { return (int)(header->e_shnum); } + const u8 *GetPtr(int offset) const { return (u8*)base + offset; } + const char *GetSectionName(int section) const; + const u8 *GetSectionDataPtr(int section) const + { + if (section < 0 || section >= header->e_shnum) + return nullptr; + if (sections[section].sh_type != SHT_NOBITS) + return GetPtr(sections[section].sh_offset); + else + return nullptr; + } + bool IsCodeSection(int section) const + { + return sections[section].sh_type == SHT_PROGBITS; + } + const u8 *GetSegmentPtr(int segment) + { + return GetPtr(segments[segment].p_offset); + } + u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } + int GetSectionSize(SectionID section) const { return sections[section].sh_size; } + SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found + + bool DidRelocate() { + return bRelocate; + } +}; diff --git a/src/core/elf/elf_types.h b/src/core/elf/elf_types.h new file mode 100644 index 00000000..f1bf3db7 --- /dev/null +++ b/src/core/elf/elf_types.h @@ -0,0 +1,281 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// ELF Header Constants + +// File type +enum ElfType +{ + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xFF00, + ET_HIPROC = 0xFFFF, +}; + +// Machine/Architecture +enum ElfMachine +{ + EM_NONE = 0, + EM_M32 = 1, + EM_SPARC = 2, + EM_386 = 3, + EM_68K = 4, + EM_88K = 5, + EM_860 = 7, + EM_MIPS = 8 +}; + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + + + +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Custom section types +#define SHT_PSPREL 0x700000a0 + + +// Section flags +enum ElfSectionFlags +{ + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MASKPROC = 0xF0000000, +}; + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +typedef unsigned int Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Off; +typedef signed int Elf32_Sword; +typedef unsigned int Elf32_Word; + + +// ELF file header +struct Elf32_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +// Relocation entries +struct Elf32_Rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + + +struct Elf32_Dyn +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; diff --git a/src/core/file_sys/directory_file_system.cpp b/src/core/file_sys/directory_file_system.cpp new file mode 100644 index 00000000..29369eec --- /dev/null +++ b/src/core/file_sys/directory_file_system.cpp @@ -0,0 +1,671 @@ +// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "chunk_file.h" +#include "file_util.h" +#include "directory_file_system.h" +//#include "ISOFileSystem.h" +//#include "Core/HLE/sceKernel.h" +//#include "file/zip_read.h" +#include "utf8.h" + +#if EMU_PLATFORM == PLATFORM_WINDOWS +#include +#include +#else +#include +#include +#include +#include +#endif + +#if HOST_IS_CASE_SENSITIVE +static bool FixFilenameCase(const std::string &path, std::string &filename) +{ + // Are we lucky? + if (File::Exists(path + filename)) + return true; + + size_t filenameSize = filename.size(); // size in bytes, not characters + for (size_t i = 0; i < filenameSize; i++) + { + filename[i] = tolower(filename[i]); + } + + //TODO: lookup filename in cache for "path" + + struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; } diren; + struct dirent_large; + struct dirent *result = NULL; + + DIR *dirp = opendir(path.c_str()); + if (!dirp) + return false; + + bool retValue = false; + + while (!readdir_r(dirp, (dirent*) &diren, &result) && result) + { + if (strlen(result->d_name) != filenameSize) + continue; + + size_t i; + for (i = 0; i < filenameSize; i++) + { + if (filename[i] != tolower(result->d_name[i])) + break; + } + + if (i < filenameSize) + continue; + + filename = result->d_name; + retValue = true; + } + + closedir(dirp); + + return retValue; +} + +bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior) +{ + size_t len = path.size(); + + if (len == 0) + return true; + + if (path[len - 1] == '/') + { + len--; + + if (len == 0) + return true; + } + + std::string fullPath; + fullPath.reserve(basePath.size() + len + 1); + fullPath.append(basePath); + + size_t start = 0; + while (start < len) + { + size_t i = path.find('/', start); + if (i == std::string::npos) + i = len; + + if (i > start) + { + std::string component = path.substr(start, i - start); + + // Fix case and stop on nonexistant path component + if (FixFilenameCase(fullPath, component) == false) { + // Still counts as success if partial matches allowed or if this + // is the last component and only the ones before it are required + return (behavior == FPC_PARTIAL_ALLOWED || (behavior == FPC_PATH_MUST_EXIST && i >= len)); + } + + path.replace(start, i - start, component); + + fullPath.append(component); + fullPath.append(1, '/'); + } + + start = i + 1; + } + + return true; +} + +#endif + +std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath) +{ + if (localpath.empty()) + return basePath; + + if (localpath[0] == '/') + localpath.erase(0,1); + //Convert slashes +#ifdef _WIN32 + for (size_t i = 0; i < localpath.size(); i++) { + if (localpath[i] == '/') + localpath[i] = '\\'; + } +#endif + return basePath + localpath; +} + +bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, FileAccess access) +{ +#if HOST_IS_CASE_SENSITIVE + if (access & (FILEACCESS_APPEND|FILEACCESS_CREATE|FILEACCESS_WRITE)) + { + DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); + if ( ! FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST) ) + return false; // or go on and attempt (for a better error code than just 0?) + } + // else we try fopen first (in case we're lucky) before simulating case insensitivity +#endif + + std::string fullName = GetLocalPath(basePath,fileName); + INFO_LOG(FILESYS,"Actually opening %s", fullName.c_str()); + + //TODO: tests, should append seek to end of file? seeking in a file opened for append? +#ifdef _WIN32 + // Convert parameters to Windows permissions and access + DWORD desired = 0; + DWORD sharemode = 0; + DWORD openmode = 0; + if (access & FILEACCESS_READ) { + desired |= GENERIC_READ; + sharemode |= FILE_SHARE_READ; + } + if (access & FILEACCESS_WRITE) { + desired |= GENERIC_WRITE; + sharemode |= FILE_SHARE_WRITE; + } + if (access & FILEACCESS_CREATE) { + openmode = OPEN_ALWAYS; + } else { + openmode = OPEN_EXISTING; + } + //Let's do it! + hFile = CreateFile(ConvertUTF8ToWString(fullName).c_str(), desired, sharemode, 0, openmode, 0, 0); + bool success = hFile != INVALID_HANDLE_VALUE; +#else + // Convert flags in access parameter to fopen access mode + const char *mode = NULL; + if (access & FILEACCESS_APPEND) { + if (access & FILEACCESS_READ) + mode = "ab+"; // append+read, create if needed + else + mode = "ab"; // append only, create if needed + } else if (access & FILEACCESS_WRITE) { + if (access & FILEACCESS_READ) { + // FILEACCESS_CREATE is ignored for read only, write only, and append + // because C++ standard fopen's nonexistant file creation can only be + // customized for files opened read+write + if (access & FILEACCESS_CREATE) + mode = "wb+"; // read+write, create if needed + else + mode = "rb+"; // read+write, but don't create + } else { + mode = "wb"; // write only, create if needed + } + } else { // neither write nor append, so default to read only + mode = "rb"; // read only, don't create + } + + hFile = fopen(fullName.c_str(), mode); + bool success = hFile != 0; +#endif + +#if HOST_IS_CASE_SENSITIVE + if (!success && + !(access & FILEACCESS_APPEND) && + !(access & FILEACCESS_CREATE) && + !(access & FILEACCESS_WRITE)) + { + if ( ! FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) ) + return 0; // or go on and attempt (for a better error code than just 0?) + fullName = GetLocalPath(basePath,fileName); + const char* fullNameC = fullName.c_str(); + + DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullNameC, fileName.c_str()); + + // And try again with the correct case this time +#ifdef _WIN32 + hFile = CreateFile(fullNameC, desired, sharemode, 0, openmode, 0, 0); + success = hFile != INVALID_HANDLE_VALUE; +#else + hFile = fopen(fullNameC, mode); + success = hFile != 0; +#endif + } +#endif + + return success; +} + +size_t DirectoryFileHandle::Read(u8* pointer, s64 size) +{ + size_t bytesRead = 0; +#ifdef _WIN32 + ::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0); +#else + bytesRead = fread(pointer, 1, size, hFile); +#endif + return bytesRead; +} + +size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) +{ + size_t bytesWritten = 0; +#ifdef _WIN32 + ::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0); +#else + bytesWritten = fwrite(pointer, 1, size, hFile); +#endif + return bytesWritten; +} + +size_t DirectoryFileHandle::Seek(s32 position, FileMove type) +{ +#ifdef _WIN32 + DWORD moveMethod = 0; + switch (type) { + case FILEMOVE_BEGIN: moveMethod = FILE_BEGIN; break; + case FILEMOVE_CURRENT: moveMethod = FILE_CURRENT; break; + case FILEMOVE_END: moveMethod = FILE_END; break; + } + DWORD newPos = SetFilePointer(hFile, (LONG)position, 0, moveMethod); + return newPos; +#else + int moveMethod = 0; + switch (type) { + case FILEMOVE_BEGIN: moveMethod = SEEK_SET; break; + case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break; + case FILEMOVE_END: moveMethod = SEEK_END; break; + } + fseek(hFile, position, moveMethod); + return ftell(hFile); +#endif +} + +void DirectoryFileHandle::Close() +{ +#ifdef _WIN32 + if (hFile != (HANDLE)-1) + CloseHandle(hFile); +#else + if (hFile != 0) + fclose(hFile); +#endif +} + +DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) { + File::CreateFullPath(basePath); + hAlloc = _hAlloc; +} + +DirectoryFileSystem::~DirectoryFileSystem() { + for (auto iter = entries.begin(); iter != entries.end(); ++iter) { + iter->second.hFile.Close(); + } +} + +std::string DirectoryFileSystem::GetLocalPath(std::string localpath) { + if (localpath.empty()) + return basePath; + + if (localpath[0] == '/') + localpath.erase(0,1); + //Convert slashes +#ifdef _WIN32 + for (size_t i = 0; i < localpath.size(); i++) { + if (localpath[i] == '/') + localpath[i] = '\\'; + } +#endif + return basePath + localpath; +} + +bool DirectoryFileSystem::MkDir(const std::string &dirname) { +#if HOST_IS_CASE_SENSITIVE + // Must fix case BEFORE attempting, because MkDir would create + // duplicate (different case) directories + + std::string fixedCase = dirname; + if ( ! FixPathCase(basePath,fixedCase, FPC_PARTIAL_ALLOWED) ) + return false; + + return File::CreateFullPath(GetLocalPath(fixedCase)); +#else + return File::CreateFullPath(GetLocalPath(dirname)); +#endif +} + +bool DirectoryFileSystem::RmDir(const std::string &dirname) { + std::string fullName = GetLocalPath(dirname); + +#if HOST_IS_CASE_SENSITIVE + // Maybe we're lucky? + if (File::DeleteDirRecursively(fullName)) + return true; + + // Nope, fix case and try again + fullName = dirname; + if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) ) + return false; // or go on and attempt (for a better error code than just false?) + + fullName = GetLocalPath(fullName); +#endif + +/*#ifdef _WIN32 + return RemoveDirectory(fullName.c_str()) == TRUE; +#else + return 0 == rmdir(fullName.c_str()); +#endif*/ + return File::DeleteDirRecursively(fullName); +} + +int DirectoryFileSystem::RenameFile(const std::string &from, const std::string &to) { + std::string fullTo = to; + + // Rename ignores the path (even if specified) on to. + size_t chop_at = to.find_last_of('/'); + if (chop_at != to.npos) + fullTo = to.substr(chop_at + 1); + + // Now put it in the same directory as from. + size_t dirname_end = from.find_last_of('/'); + if (dirname_end != from.npos) + fullTo = from.substr(0, dirname_end + 1) + fullTo; + + // At this point, we should check if the paths match and give an already exists error. + if (from == fullTo) + return -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS; + + std::string fullFrom = GetLocalPath(from); + +#if HOST_IS_CASE_SENSITIVE + // In case TO should overwrite a file with different case + if ( ! FixPathCase(basePath,fullTo, FPC_PATH_MUST_EXIST) ) + return -1; // or go on and attempt (for a better error code than just false?) +#endif + + fullTo = GetLocalPath(fullTo); + const char * fullToC = fullTo.c_str(); + +#ifdef _WIN32 + bool retValue = (MoveFile(ConvertUTF8ToWString(fullFrom).c_str(), ConvertUTF8ToWString(fullToC).c_str()) == TRUE); +#else + bool retValue = (0 == rename(fullFrom.c_str(), fullToC)); +#endif + +#if HOST_IS_CASE_SENSITIVE + if (! retValue) + { + // May have failed due to case sensitivity on FROM, so try again + fullFrom = from; + if ( ! FixPathCase(basePath,fullFrom, FPC_FILE_MUST_EXIST) ) + return -1; // or go on and attempt (for a better error code than just false?) + fullFrom = GetLocalPath(fullFrom); + +#ifdef _WIN32 + retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE); +#else + retValue = (0 == rename(fullFrom.c_str(), fullToC)); +#endif + } +#endif + + // TODO: Better error codes. + return retValue ? 0 : -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS; +} + +bool DirectoryFileSystem::RemoveFile(const std::string &filename) { + std::string fullName = GetLocalPath(filename); +#ifdef _WIN32 + bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE); +#else + bool retValue = (0 == unlink(fullName.c_str())); +#endif + +#if HOST_IS_CASE_SENSITIVE + if (! retValue) + { + // May have failed due to case sensitivity, so try again + fullName = filename; + if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) ) + return false; // or go on and attempt (for a better error code than just false?) + fullName = GetLocalPath(fullName); + +#ifdef _WIN32 + retValue = (::DeleteFileA(fullName.c_str()) == TRUE); +#else + retValue = (0 == unlink(fullName.c_str())); +#endif + } +#endif + + return retValue; +} + +u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { + OpenFileEntry entry; + bool success = entry.hFile.Open(basePath,filename,access); + + if (!success) { +#ifdef _WIN32 + ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access); +#else + ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, access = %i", (int)access); +#endif + //wwwwaaaaahh!! + return 0; + } else { +#ifdef _WIN32 + if (access & FILEACCESS_APPEND) + entry.hFile.Seek(0,FILEMOVE_END); +#endif + + u32 newHandle = hAlloc->GetNewHandle(); + entries[newHandle] = entry; + + return newHandle; + } +} + +void DirectoryFileSystem::CloseFile(u32 handle) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) { + hAlloc->FreeHandle(handle); + iter->second.hFile.Close(); + entries.erase(iter); + } else { + //This shouldn't happen... + ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle); + } +} + +bool DirectoryFileSystem::OwnsHandle(u32 handle) { + EntryMap::iterator iter = entries.find(handle); + return (iter != entries.end()); +} + +size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) + { + size_t bytesRead = iter->second.hFile.Read(pointer,size); + return bytesRead; + } else { + //This shouldn't happen... + ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle); + return 0; + } +} + +size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) + { + size_t bytesWritten = iter->second.hFile.Write(pointer,size); + return bytesWritten; + } else { + //This shouldn't happen... + ERROR_LOG(FILESYS,"Cannot write to file that hasn't been opened: %08x", handle); + return 0; + } +} + +size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { + EntryMap::iterator iter = entries.find(handle); + if (iter != entries.end()) { + return iter->second.hFile.Seek(position,type); + } else { + //This shouldn't happen... + ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle); + return 0; + } +} + +FileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { + FileInfo x; + x.name = filename; + + std::string fullName = GetLocalPath(filename); + if (! File::Exists(fullName)) { +#if HOST_IS_CASE_SENSITIVE + if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST)) + return x; + fullName = GetLocalPath(filename); + + if (! File::Exists(fullName)) + return x; +#else + return x; +#endif + } + x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; + x.exists = true; + + if (x.type != FILETYPE_DIRECTORY) + { +#ifdef _WIN32 + struct _stat64i32 s; + _wstat64i32(ConvertUTF8ToWString(fullName).c_str(), &s); +#else + struct stat s; + stat(fullName.c_str(), &s); +#endif + + x.size = File::GetSize(fullName); + x.access = s.st_mode & 0x1FF; + localtime_r((time_t*)&s.st_atime,&x.atime); + localtime_r((time_t*)&s.st_ctime,&x.ctime); + localtime_r((time_t*)&s.st_mtime,&x.mtime); + } + + return x; +} + +bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { + outpath = GetLocalPath(inpath); + return true; +} + +#ifdef _WIN32 +#define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL + +static void tmFromFiletime(tm &dest, FILETIME &src) +{ + u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; + u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; + + time_t t = (time_t) (from_1970_us / 1000000UL); + localtime_r(&t, &dest); +} +#endif + +std::vector DirectoryFileSystem::GetDirListing(std::string path) { + std::vector myVector; +#ifdef _WIN32 + WIN32_FIND_DATA findData; + HANDLE hFind; + + std::string w32path = GetLocalPath(path) + "\\*.*"; + + hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData); + + if (hFind == INVALID_HANDLE_VALUE) { + return myVector; //the empty list + } + + while (true) { + FileInfo entry; + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + entry.type = FILETYPE_DIRECTORY; + else + entry.type = FILETYPE_NORMAL; + + // TODO: Make this more correct? + entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777; + // TODO: is this just for .. or all subdirectories? Need to add a directory to the test + // to find out. Also why so different than the old test results? + if (!wcscmp(findData.cFileName, L"..") ) + entry.size = 4096; + else + entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); + entry.name = ConvertWStringToUTF8(findData.cFileName); + tmFromFiletime(entry.atime, findData.ftLastAccessTime); + tmFromFiletime(entry.ctime, findData.ftCreationTime); + tmFromFiletime(entry.mtime, findData.ftLastWriteTime); + myVector.push_back(entry); + + int retval = FindNextFile(hFind, &findData); + if (!retval) + break; + } +#else + dirent *dirp; + std::string localPath = GetLocalPath(path); + DIR *dp = opendir(localPath.c_str()); + +#if HOST_IS_CASE_SENSITIVE + if(dp == NULL && FixPathCase(basePath,path, FPC_FILE_MUST_EXIST)) { + // May have failed due to case sensitivity, try again + localPath = GetLocalPath(path); + dp = opendir(localPath.c_str()); + } +#endif + + if (dp == NULL) { + ERROR_LOG(FILESYS,"Error opening directory %s\n",path.c_str()); + return myVector; + } + + while ((dirp = readdir(dp)) != NULL) { + FileInfo entry; + struct stat s; + std::string fullName = GetLocalPath(path) + "/"+dirp->d_name; + stat(fullName.c_str(), &s); + if (S_ISDIR(s.st_mode)) + entry.type = FILETYPE_DIRECTORY; + else + entry.type = FILETYPE_NORMAL; + entry.access = s.st_mode & 0x1FF; + entry.name = dirp->d_name; + entry.size = s.st_size; + localtime_r((time_t*)&s.st_atime,&entry.atime); + localtime_r((time_t*)&s.st_ctime,&entry.ctime); + localtime_r((time_t*)&s.st_mtime,&entry.mtime); + myVector.push_back(entry); + } + closedir(dp); +#endif + return myVector; +} + +void DirectoryFileSystem::DoState(PointerWrap &p) { + if (!entries.empty()) { + p.SetError(p.ERROR_WARNING); + ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); + } +} diff --git a/src/core/file_sys/directory_file_system.h b/src/core/file_sys/directory_file_system.h new file mode 100644 index 00000000..a11331a2 --- /dev/null +++ b/src/core/file_sys/directory_file_system.h @@ -0,0 +1,158 @@ +// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#ifndef CORE_FILE_SYS_DIRECTORY_H_ +#define CORE_FILE_SYS_DIRECTORY_H_ + +// TODO: Remove the Windows-specific code, FILE is fine there too. + +#include + +#include "file_sys.h" + +#ifdef _WIN32 +typedef void * HANDLE; +#endif + +#if defined(__APPLE__) + +#if TARGET_OS_IPHONE +#define HOST_IS_CASE_SENSITIVE 1 +#elif TARGET_IPHONE_SIMULATOR +#define HOST_IS_CASE_SENSITIVE 0 +#else +// Mac OSX case sensitivity defaults off, but is user configurable (when +// creating a filesytem), so assume the worst: +#define HOST_IS_CASE_SENSITIVE 1 +#endif + +#elif defined(_WIN32) || defined(__SYMBIAN32__) +#define HOST_IS_CASE_SENSITIVE 0 + +#else // Android, Linux, BSD (and the rest?) +#define HOST_IS_CASE_SENSITIVE 1 + +#endif + +#if HOST_IS_CASE_SENSITIVE +enum FixPathCaseBehavior { + FPC_FILE_MUST_EXIST, // all path components must exist (rmdir, move from) + FPC_PATH_MUST_EXIST, // all except the last one must exist - still tries to fix last one (fopen, move to) + FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive) +}; + +bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior); +#endif + +struct DirectoryFileHandle +{ +#ifdef _WIN32 + HANDLE hFile; +#else + FILE* hFile; +#endif + DirectoryFileHandle() + { +#ifdef _WIN32 + hFile = (HANDLE)-1; +#else + hFile = 0; +#endif + } + + std::string GetLocalPath(std::string& basePath, std::string localpath); + bool Open(std::string& basePath, std::string& fileName, FileAccess access); + size_t Read(u8* pointer, s64 size); + size_t Write(const u8* pointer, s64 size); + size_t Seek(s32 position, FileMove type); + void Close(); +}; + +class DirectoryFileSystem : public IFileSystem { +public: + DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); + ~DirectoryFileSystem(); + + void DoState(PointerWrap &p); + std::vector GetDirListing(std::string path); + u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL); + void CloseFile(u32 handle); + size_t ReadFile(u32 handle, u8 *pointer, s64 size); + size_t WriteFile(u32 handle, const u8 *pointer, s64 size); + size_t SeekFile(u32 handle, s32 position, FileMove type); + FileInfo GetFileInfo(std::string filename); + bool OwnsHandle(u32 handle); + + bool MkDir(const std::string &dirname); + bool RmDir(const std::string &dirname); + int RenameFile(const std::string &from, const std::string &to); + bool RemoveFile(const std::string &filename); + bool GetHostPath(const std::string &inpath, std::string &outpath); + +private: + struct OpenFileEntry { + DirectoryFileHandle hFile; + }; + + typedef std::map EntryMap; + EntryMap entries; + std::string basePath; + IHandleAllocator *hAlloc; + + // In case of Windows: Translate slashes, etc. + std::string GetLocalPath(std::string localpath); +}; + +// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts. +// Very inefficient - always load the whole file on open. +class VFSFileSystem : public IFileSystem { +public: + VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); + ~VFSFileSystem(); + + void DoState(PointerWrap &p); + std::vector GetDirListing(std::string path); + u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL); + void CloseFile(u32 handle); + size_t ReadFile(u32 handle, u8 *pointer, s64 size); + size_t WriteFile(u32 handle, const u8 *pointer, s64 size); + size_t SeekFile(u32 handle, s32 position, FileMove type); + FileInfo GetFileInfo(std::string filename); + bool OwnsHandle(u32 handle); + + bool MkDir(const std::string &dirname); + bool RmDir(const std::string &dirname); + int RenameFile(const std::string &from, const std::string &to); + bool RemoveFile(const std::string &filename); + bool GetHostPath(const std::string &inpath, std::string &outpath); + +private: + struct OpenFileEntry { + u8 *fileData; + size_t size; + size_t seekPos; + }; + + typedef std::map EntryMap; + EntryMap entries; + std::string basePath; + IHandleAllocator *hAlloc; + + std::string GetLocalPath(std::string localpath); +}; + +#endif // CORE_FILE_SYS_DIRECTORY_H_ diff --git a/src/core/file_sys/file_sys.h b/src/core/file_sys/file_sys.h new file mode 100644 index 00000000..b27e36c8 --- /dev/null +++ b/src/core/file_sys/file_sys.h @@ -0,0 +1,138 @@ +// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "common.h" +#include "chunk_file.h" + +enum FileAccess { + FILEACCESS_NONE=0, + FILEACCESS_READ=1, + FILEACCESS_WRITE=2, + FILEACCESS_APPEND=4, + FILEACCESS_CREATE=8 +}; + +enum FileMove { + FILEMOVE_BEGIN=0, + FILEMOVE_CURRENT=1, + FILEMOVE_END=2 +}; + +enum FileType { + FILETYPE_NORMAL=1, + FILETYPE_DIRECTORY=2 +}; + + +class IHandleAllocator { +public: + virtual ~IHandleAllocator() {} + virtual u32 GetNewHandle() = 0; + virtual void FreeHandle(u32 handle) = 0; +}; + +class SequentialHandleAllocator : public IHandleAllocator { +public: + SequentialHandleAllocator() : handle_(1) {} + virtual u32 GetNewHandle() { return handle_++; } + virtual void FreeHandle(u32 handle) {} +private: + int handle_; +}; + +struct FileInfo { + FileInfo() + : size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0) {} + + void DoState(PointerWrap &p) { + auto s = p.Section("FileInfo", 1); + if (!s) + return; + + p.Do(name); + p.Do(size); + p.Do(access); + p.Do(exists); + p.Do(type); + p.Do(atime); + p.Do(ctime); + p.Do(mtime); + p.Do(isOnSectorSystem); + p.Do(startSector); + p.Do(numSectors); + p.Do(sectorSize); + } + + std::string name; + s64 size; + u32 access; //unix 777 + bool exists; + FileType type; + + tm atime; + tm ctime; + tm mtime; + + bool isOnSectorSystem; + u32 startSector; + u32 numSectors; + u32 sectorSize; +}; + + +class IFileSystem { +public: + virtual ~IFileSystem() {} + + virtual void DoState(PointerWrap &p) = 0; + virtual std::vector GetDirListing(std::string path) = 0; + virtual u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) = 0; + virtual void CloseFile(u32 handle) = 0; + virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size) = 0; + virtual size_t WriteFile(u32 handle, const u8 *pointer, s64 size) = 0; + virtual size_t SeekFile(u32 handle, s32 position, FileMove type) = 0; + virtual FileInfo GetFileInfo(std::string filename) = 0; + virtual bool OwnsHandle(u32 handle) = 0; + virtual bool MkDir(const std::string &dirname) = 0; + virtual bool RmDir(const std::string &dirname) = 0; + virtual int RenameFile(const std::string &from, const std::string &to) = 0; + virtual bool RemoveFile(const std::string &filename) = 0; + virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0; +}; + + +class EmptyFileSystem : public IFileSystem { +public: + virtual void DoState(PointerWrap &p) {} + std::vector GetDirListing(std::string path) {std::vector vec; return vec;} + u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) {return 0;} + void CloseFile(u32 handle) {} + size_t ReadFile(u32 handle, u8 *pointer, s64 size) {return 0;} + size_t WriteFile(u32 handle, const u8 *pointer, s64 size) {return 0;} + size_t SeekFile(u32 handle, s32 position, FileMove type) {return 0;} + FileInfo GetFileInfo(std::string filename) {FileInfo f; return f;} + bool OwnsHandle(u32 handle) {return false;} + virtual bool MkDir(const std::string &dirname) {return false;} + virtual bool RmDir(const std::string &dirname) {return false;} + virtual int RenameFile(const std::string &from, const std::string &to) {return -1;} + virtual bool RemoveFile(const std::string &filename) {return false;} + virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;} +}; + + diff --git a/src/core/file_sys/meta_file_system.cpp b/src/core/file_sys/meta_file_system.cpp new file mode 100644 index 00000000..f86c3cb1 --- /dev/null +++ b/src/core/file_sys/meta_file_system.cpp @@ -0,0 +1,520 @@ +// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include +#include "string_util.h" +#include "file_sys/meta_file_system.h" +//#include "Core/HLE/sceKernelThread.h" +//#include "Core/Reporting.h" + +static bool ApplyPathStringToComponentsVector(std::vector &vector, const std::string &pathString) +{ + size_t len = pathString.length(); + size_t start = 0; + + while (start < len) + { + size_t i = pathString.find('/', start); + if (i == std::string::npos) + i = len; + + if (i > start) + { + std::string component = pathString.substr(start, i - start); + if (component != ".") + { + if (component == "..") + { + if (vector.size() != 0) + { + vector.pop_back(); + } + else + { + // The PSP silently ignores attempts to .. to parent of root directory + WARN_LOG(FILESYS, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str()); + } + } + else + { + vector.push_back(component); + } + } + } + + start = i + 1; + } + + return true; +} + +/* + * Changes relative paths to absolute, removes ".", "..", and trailing "/" + * "drive:./blah" is absolute (ignore the dot) and "/blah" is relative (because it's missing "drive:") + * babel (and possibly other games) use "/directoryThatDoesNotExist/../directoryThatExists/filename" + */ +static bool RealPath(const std::string ¤tDirectory, const std::string &inPath, std::string &outPath) +{ + size_t inLen = inPath.length(); + if (inLen == 0) + { + WARN_LOG(FILESYS, "RealPath: inPath is empty"); + outPath = currentDirectory; + return true; + } + + size_t inColon = inPath.find(':'); + if (inColon + 1 == inLen) + { + // There's nothing after the colon, e.g. umd0: - this is perfectly valid. + outPath = inPath; + return true; + } + + bool relative = (inColon == std::string::npos); + + std::string prefix, inAfterColon; + std::vector cmpnts; // path components + size_t outPathCapacityGuess = inPath.length(); + + if (relative) + { + size_t curDirLen = currentDirectory.length(); + if (curDirLen == 0) + { + ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str()); + return false; + } + + size_t curDirColon = currentDirectory.find(':'); + if (curDirColon == std::string::npos) + { + ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str()); + return false; + } + if (curDirColon + 1 == curDirLen) + { + ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str()); + } + else + { + const std::string curDirAfter = currentDirectory.substr(curDirColon + 1); + if (! ApplyPathStringToComponentsVector(cmpnts, curDirAfter) ) + { + ERROR_LOG(FILESYS,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str()); + return false; + } + + outPathCapacityGuess += curDirLen; + } + + prefix = currentDirectory.substr(0, curDirColon + 1); + inAfterColon = inPath; + } + else + { + prefix = inPath.substr(0, inColon + 1); + inAfterColon = inPath.substr(inColon + 1); + } + + // Special case: "disc0:" is different from "disc0:/", so keep track of the single slash. + if (inAfterColon == "/") + { + outPath = prefix + inAfterColon; + return true; + } + + if (! ApplyPathStringToComponentsVector(cmpnts, inAfterColon) ) + { + WARN_LOG(FILESYS, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str()); + return false; + } + + outPath.clear(); + outPath.reserve(outPathCapacityGuess); + + outPath.append(prefix); + + size_t numCmpnts = cmpnts.size(); + for (size_t i = 0; i < numCmpnts; i++) + { + outPath.append(1, '/'); + outPath.append(cmpnts[i]); + } + + return true; +} + +IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) +{ + std::lock_guard guard(lock); + for (size_t i = 0; i < fileSystems.size(); i++) + { + if (fileSystems[i].system->OwnsHandle(handle)) + return fileSystems[i].system; //got it! + } + //none found? + return 0; +} + +bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) +{ + std::lock_guard guard(lock); + std::string realpath; + + // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) + // appears to mean the current directory on the UMD. Let's just assume the current directory. + std::string inpath = _inpath; + if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) { + INFO_LOG(FILESYS, "Host0 path detected, stripping: %s", inpath.c_str()); + inpath = inpath.substr(strlen("host0:")); + } + + const std::string *currentDirectory = &startingDirectory; + + _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread"); + + int currentThread = 0;//__KernelGetCurThread(); + currentDir_t::iterator it = currentDir.find(currentThread); + if (it == currentDir.end()) + { + //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere + if (inpath.find(':') == std::string::npos /* means path is relative */) + { + lastOpenError = -1;//SCE_KERNEL_ERROR_NOCWD; + WARN_LOG(FILESYS, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); + } + } + else + { + currentDirectory = &(it->second); + } + + if ( RealPath(*currentDirectory, inpath, realpath) ) + { + for (size_t i = 0; i < fileSystems.size(); i++) + { + size_t prefLen = fileSystems[i].prefix.size(); + if (strncasecmp(fileSystems[i].prefix.c_str(), realpath.c_str(), prefLen) == 0) + { + outpath = realpath.substr(prefLen); + *system = &(fileSystems[i]); + + INFO_LOG(FILESYS, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); + + return true; + } + } + } + + DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); + return false; +} + +void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) +{ + std::lock_guard guard(lock); + MountPoint x; + x.prefix = prefix; + x.system = system; + fileSystems.push_back(x); +} + +void MetaFileSystem::Unmount(std::string prefix, IFileSystem *system) +{ + std::lock_guard guard(lock); + MountPoint x; + x.prefix = prefix; + x.system = system; + fileSystems.erase(std::remove(fileSystems.begin(), fileSystems.end(), x), fileSystems.end()); +} + +void MetaFileSystem::Shutdown() +{ + std::lock_guard guard(lock); + current = 6; + + // Ownership is a bit convoluted. Let's just delete everything once. + + std::set toDelete; + for (size_t i = 0; i < fileSystems.size(); i++) { + toDelete.insert(fileSystems[i].system); + } + + for (auto iter = toDelete.begin(); iter != toDelete.end(); ++iter) + { + delete *iter; + } + + fileSystems.clear(); + currentDir.clear(); + startingDirectory = ""; +} + +u32 MetaFileSystem::OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename) +{ + std::lock_guard guard(lock); + u32 h = OpenFile(filename, access, devicename); + error = lastOpenError; + return h; +} + +u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) +{ + std::lock_guard guard(lock); + lastOpenError = 0; + std::string of; + MountPoint *mount; + if (MapFilePath(filename, of, &mount)) + { + return mount->system->OpenFile(of, access, mount->prefix.c_str()); + } + else + { + return 0; + } +} + +FileInfo MetaFileSystem::GetFileInfo(std::string filename) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(filename, of, &system)) + { + return system->GetFileInfo(of); + } + else + { + FileInfo bogus; // TODO + return bogus; + } +} + +bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(inpath, of, &system)) { + return system->GetHostPath(of, outpath); + } else { + return false; + } +} + +std::vector MetaFileSystem::GetDirListing(std::string path) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(path, of, &system)) + { + return system->GetDirListing(of); + } + else + { + std::vector empty; + return empty; + } +} + +void MetaFileSystem::ThreadEnded(int threadID) +{ + std::lock_guard guard(lock); + currentDir.erase(threadID); +} + +int MetaFileSystem::ChDir(const std::string &dir) +{ + std::lock_guard guard(lock); + // Retain the old path and fail if the arg is 1023 bytes or longer. + if (dir.size() >= 1023) + return -1;//SCE_KERNEL_ERROR_NAMETOOLONG; + + _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread"); + + int curThread = 0; //__KernelGetCurThread(); + + std::string of; + MountPoint *mountPoint; + if (MapFilePath(dir, of, &mountPoint)) + { + currentDir[curThread] = mountPoint->prefix + of; + return 0; + } + else + { + for (size_t i = 0; i < fileSystems.size(); i++) + { + const std::string &prefix = fileSystems[i].prefix; + if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0) + { + // The PSP is completely happy with invalid current dirs as long as they have a valid device. + WARN_LOG(FILESYS, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str()); + currentDir[curThread] = dir; + return 0; + } + } + + WARN_LOG(FILESYS, "ChDir failed to map device for \"%s\", failing", dir.c_str()); + return -1;//SCE_KERNEL_ERROR_NODEV; + } +} + +bool MetaFileSystem::MkDir(const std::string &dirname) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(dirname, of, &system)) + { + return system->MkDir(of); + } + else + { + return false; + } +} + +bool MetaFileSystem::RmDir(const std::string &dirname) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(dirname, of, &system)) + { + return system->RmDir(of); + } + else + { + return false; + } +} + +int MetaFileSystem::RenameFile(const std::string &from, const std::string &to) +{ + std::lock_guard guard(lock); + std::string of; + std::string rf; + IFileSystem *osystem; + IFileSystem *rsystem = NULL; + if (MapFilePath(from, of, &osystem)) + { + // If it's a relative path, it seems to always use from's filesystem. + if (to.find(":/") != to.npos) + { + if (!MapFilePath(to, rf, &rsystem)) + return -1; + } + else + { + rf = to; + rsystem = osystem; + } + + if (osystem != rsystem) + return -1;//SCE_KERNEL_ERROR_XDEV; + + return osystem->RenameFile(of, rf); + } + else + { + return -1; + } +} + +bool MetaFileSystem::RemoveFile(const std::string &filename) +{ + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + if (MapFilePath(filename, of, &system)) + { + return system->RemoveFile(of); + } + else + { + return false; + } +} + +void MetaFileSystem::CloseFile(u32 handle) +{ + std::lock_guard guard(lock); + IFileSystem *sys = GetHandleOwner(handle); + if (sys) + sys->CloseFile(handle); +} + +size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) +{ + std::lock_guard guard(lock); + IFileSystem *sys = GetHandleOwner(handle); + if (sys) + return sys->ReadFile(handle,pointer,size); + else + return 0; +} + +size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) +{ + std::lock_guard guard(lock); + IFileSystem *sys = GetHandleOwner(handle); + if (sys) + return sys->WriteFile(handle,pointer,size); + else + return 0; +} + +size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type) +{ + std::lock_guard guard(lock); + IFileSystem *sys = GetHandleOwner(handle); + if (sys) + return sys->SeekFile(handle,position,type); + else + return 0; +} + +void MetaFileSystem::DoState(PointerWrap &p) +{ + std::lock_guard guard(lock); + + auto s = p.Section("MetaFileSystem", 1); + if (!s) + return; + + p.Do(current); + + // Save/load per-thread current directory map + p.Do(currentDir); + + u32 n = (u32) fileSystems.size(); + p.Do(n); + if (n != (u32) fileSystems.size()) + { + p.SetError(p.ERROR_FAILURE); + ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match."); + return; + } + + for (u32 i = 0; i < n; ++i) + fileSystems[i].system->DoState(p); +} + diff --git a/src/core/file_sys/meta_file_system.h b/src/core/file_sys/meta_file_system.h new file mode 100644 index 00000000..0de23d49 --- /dev/null +++ b/src/core/file_sys/meta_file_system.h @@ -0,0 +1,109 @@ +// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "std_mutex.h" +#include "file_sys.h" + +class MetaFileSystem : public IHandleAllocator, public IFileSystem +{ +private: + u32 current; + struct MountPoint + { + std::string prefix; + IFileSystem *system; + + bool operator == (const MountPoint &other) const + { + return prefix == other.prefix && system == other.system; + } + }; + std::vector fileSystems; + + typedef std::map currentDir_t; + currentDir_t currentDir; + + std::string startingDirectory; + int lastOpenError; + std::recursive_mutex lock; + +public: + MetaFileSystem() + { + current = 6; // what? + } + + void Mount(std::string prefix, IFileSystem *system); + void Unmount(std::string prefix, IFileSystem *system); + + void ThreadEnded(int threadID); + + void Shutdown(); + + u32 GetNewHandle() {return current++;} + void FreeHandle(u32 handle) {} + + virtual void DoState(PointerWrap &p); + + IFileSystem *GetHandleOwner(u32 handle); + bool MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system); + + inline bool MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system) + { + MountPoint *mountPoint; + if (MapFilePath(_inpath, outpath, &mountPoint)) + { + *system = mountPoint->system; + return true; + } + + return false; + } + + // Only possible if a file system is a DirectoryFileSystem or similar. + bool GetHostPath(const std::string &inpath, std::string &outpath); + + std::vector GetDirListing(std::string path); + u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL); + u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL); + void CloseFile(u32 handle); + size_t ReadFile(u32 handle, u8 *pointer, s64 size); + size_t WriteFile(u32 handle, const u8 *pointer, s64 size); + size_t SeekFile(u32 handle, s32 position, FileMove type); + FileInfo GetFileInfo(std::string filename); + bool OwnsHandle(u32 handle) {return false;} + inline size_t GetSeekPos(u32 handle) + { + return SeekFile(handle, 0, FILEMOVE_CURRENT); + } + + virtual int ChDir(const std::string &dir); + + virtual bool MkDir(const std::string &dirname); + virtual bool RmDir(const std::string &dirname); + virtual int RenameFile(const std::string &from, const std::string &to); + virtual bool RemoveFile(const std::string &filename); + + // TODO: void IoCtl(...) + + void SetStartingDirectory(const std::string &dir) { + std::lock_guard guard(lock); + startingDirectory = dir; + } +}; diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp new file mode 100644 index 00000000..57be4d6a --- /dev/null +++ b/src/core/hw/hw.cpp @@ -0,0 +1,49 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "log.h" +#include "hw/hw.h" +#include "hw/hw_lcd.h" + +namespace HW { + +template +inline void Read(T &var, const u32 addr) { + NOTICE_LOG(HW, "Hardware read from address %08X", addr); +} + +template +inline void Write(u32 addr, const T data) { + NOTICE_LOG(HW, "Hardware write to address %08X", addr); +} + +// Explicitly instantiate template functions because we aren't defining this in the header: + +template void Read(u64 &var, const u32 addr); +template void Read(u32 &var, const u32 addr); +template void Read(u16 &var, const u32 addr); +template void Read(u8 &var, const u32 addr); + +template void Write(u32 addr, const u64 data); +template void Write(u32 addr, const u32 data); +template void Write(u32 addr, const u16 data); +template void Write(u32 addr, const u8 data); + +/// Update hardware +void Update() { + LCD::Update(); +} + +/// Initialize hardware +void Init() { + LCD::Init(); + NOTICE_LOG(HW, "Hardware initialized OK"); +} + +/// Shutdown hardware +void Shutdown() { + NOTICE_LOG(HW, "Hardware shutdown OK"); +} + +} \ No newline at end of file diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h new file mode 100644 index 00000000..5b0cc8c8 --- /dev/null +++ b/src/core/hw/hw.h @@ -0,0 +1,26 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common_types.h" + +namespace HW { + +template +inline void Read(T &var, const u32 addr); + +template +inline void Write(u32 addr, const T data); + +/// Update hardware +void Update(); + +/// Initialize hardware +void Init(); + +/// Shutdown hardware +void Shutdown(); + +} // namespace diff --git a/src/core/hw/hw_lcd.cpp b/src/core/hw/hw_lcd.cpp new file mode 100644 index 00000000..ad346c79 --- /dev/null +++ b/src/core/hw/hw_lcd.cpp @@ -0,0 +1,45 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "log.h" +#include "core.h" +#include "hw_lcd.h" +#include "video_core.h" + +namespace LCD { + +static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second + +u64 g_last_ticks = 0; ///< Last CPU ticks + +template +inline void Read(T &var, const u32 addr) { +} + +template +inline void Write(u32 addr, const T data) { +} + +/// Update hardware +void Update() { + u64 current_ticks = Core::g_app_core->GetTicks(); + + if ((current_ticks - g_last_ticks) >= kFrameTicks) { + g_last_ticks = current_ticks; + VideoCore::g_renderer->SwapBuffers(); + } +} + +/// Initialize hardware +void Init() { + g_last_ticks = Core::g_app_core->GetTicks(); + NOTICE_LOG(LCD, "LCD initialized OK"); +} + +/// Shutdown hardware +void Shutdown() { + NOTICE_LOG(LCD, "LCD shutdown OK"); +} + +} // namespace diff --git a/src/core/hw/hw_lcd.h b/src/core/hw/hw_lcd.h new file mode 100644 index 00000000..30e347cc --- /dev/null +++ b/src/core/hw/hw_lcd.h @@ -0,0 +1,44 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common_types.h" + +namespace LCD { + +enum { + TOP_ASPECT_X = 0x5, + TOP_ASPECT_Y = 0x3, + + TOP_HEIGHT = 240, + TOP_WIDTH = 400, + BOTTOM_WIDTH = 320, + + FRAMEBUFFER_SEL = 0x20184E59, + TOP_LEFT_FRAME1 = 0x20184E60, + TOP_LEFT_FRAME2 = 0x201CB370, + TOP_RIGHT_FRAME1 = 0x20282160, + TOP_RIGHT_FRAME2 = 0x202C8670, + SUB_FRAME1 = 0x202118E0, + SUB_FRAME2 = 0x20249CF0, +}; + +template +inline void Read(T &var, const u32 addr); + +template +inline void Write(u32 addr, const T data); + +/// Update hardware +void Update(); + +/// Initialize hardware +void Init(); + +/// Shutdown hardware +void Shutdown(); + + +} // namespace diff --git a/src/core/loader.cpp b/src/core/loader.cpp new file mode 100644 index 00000000..5d039dc9 --- /dev/null +++ b/src/core/loader.cpp @@ -0,0 +1,168 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "file_util.h" +#include "loader.h" +#include "system.h" +#include "core.h" +#include "file_sys/directory_file_system.h" +#include "elf/elf_reader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Loads an extracted CXI from a directory +bool LoadDirectory_CXI(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + DirectoryFileSystem *fs = new DirectoryFileSystem(&System::g_ctr_file_system, path); + System::g_ctr_file_system.Mount("fs:", fs); + + std::string final_name = "fs:/" + file + extension; + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + // TODO(ShizZy): read here to memory.... + } + ERROR_LOG(TIME, "Unimplemented function!"); + return true; +} + +/// Loads a CTR ELF file +bool Load_ELF(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + u64 size = f.GetSize(); + u8* buffer = new u8[size]; + ElfReader* elf_reader = NULL; + + f.ReadBytes(buffer, size); + + elf_reader = new ElfReader(buffer); + elf_reader->LoadInto(0x00100000); + + Core::g_app_core->SetPC(elf_reader->GetEntryPoint()); + + delete[] buffer; + delete elf_reader; + } else { + return false; + } + f.Close(); + + return true; +} + +namespace Loader { + +bool IsBootableDirectory() { + ERROR_LOG(TIME, "Unimplemented function!"); + return true; +} + +/** + * Identifies the type of a bootable file + * @param filename String filename of bootable file + * @todo (ShizZy) this function sucks... make it actually check file contents etc. + * @return FileType of file + */ +FileType IdentifyFile(std::string &filename) { + if (filename.size() == 0) { + ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); + return FILETYPE_ERROR; + } + std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; + + if (File::IsDirectory(filename)) { + if (IsBootableDirectory()) { + return FILETYPE_DIRECTORY_CXI; + } + else { + return FILETYPE_NORMAL_DIRECTORY; + } + } + else if (!strcasecmp(extension.c_str(), ".elf")) { + return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p + } + else if (!strcasecmp(extension.c_str(), ".zip")) { + return FILETYPE_ARCHIVE_ZIP; + } + else if (!strcasecmp(extension.c_str(), ".rar")) { + return FILETYPE_ARCHIVE_RAR; + } + else if (!strcasecmp(extension.c_str(), ".r00")) { + return FILETYPE_ARCHIVE_RAR; + } + else if (!strcasecmp(extension.c_str(), ".r01")) { + return FILETYPE_ARCHIVE_RAR; + } + return FILETYPE_UNKNOWN; +} + +/** + * Identifies and loads a bootable file + * @param filename String filename of bootable file + * @param error_string Point to string to put error message if an error has occurred + * @return True on success, otherwise false + */ +bool LoadFile(std::string &filename, std::string *error_string) { + INFO_LOG(LOADER, "Identifying file..."); + + // Note that this can modify filename! + switch (IdentifyFile(filename)) { + + case FILETYPE_CTR_ELF: + return Load_ELF(filename); + + case FILETYPE_DIRECTORY_CXI: + return LoadDirectory_CXI(filename); + + case FILETYPE_ERROR: + ERROR_LOG(LOADER, "Could not read file"); + *error_string = "Error reading file"; + break; + + case FILETYPE_ARCHIVE_RAR: +#ifdef WIN32 + *error_string = "RAR file detected (Require WINRAR)"; +#else + *error_string = "RAR file detected (Require UnRAR)"; +#endif + break; + + case FILETYPE_ARCHIVE_ZIP: +#ifdef WIN32 + *error_string = "ZIP file detected (Require WINRAR)"; +#else + *error_string = "ZIP file detected (Require UnRAR)"; +#endif + break; + + case FILETYPE_NORMAL_DIRECTORY: + ERROR_LOG(LOADER, "Just a directory."); + *error_string = "Just a directory."; + break; + + case FILETYPE_UNKNOWN_BIN: + case FILETYPE_UNKNOWN_ELF: + case FILETYPE_UNKNOWN: + default: + ERROR_LOG(LOADER, "Failed to identify file"); + *error_string = "Failed to identify file"; + break; + } + return false; +} + +} // namespace \ No newline at end of file diff --git a/src/core/loader.h b/src/core/loader.h new file mode 100644 index 00000000..46525fcf --- /dev/null +++ b/src/core/loader.h @@ -0,0 +1,51 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace Loader { + +enum FileType { + FILETYPE_ERROR, + + FILETYPE_CTR_CCI, + FILETYPE_CTR_CIA, + FILETYPE_CTR_CXI, + FILETYPE_CTR_ELF, + + FILETYPE_DIRECTORY_CXI, + + FILETYPE_UNKNOWN_BIN, + FILETYPE_UNKNOWN_ELF, + + FILETYPE_ARCHIVE_RAR, + FILETYPE_ARCHIVE_ZIP, + + FILETYPE_NORMAL_DIRECTORY, + + FILETYPE_UNKNOWN +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Identifies the type of a bootable file + * @param filename String filename of bootable file + * @return FileType of file + */ +FileType IdentifyFile(std::string &filename); + +/** + * Identifies and loads a bootable file + * @param filename String filename of bootable file + * @param error_string Point to string to put error message if an error has occurred + * @return True on success, otherwise false + */ +bool LoadFile(std::string &filename, std::string *error_string); + +} // namespace diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp new file mode 100644 index 00000000..96f77d32 --- /dev/null +++ b/src/core/mem_map.cpp @@ -0,0 +1,83 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "mem_arena.h" + +#include "mem_map.h" +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace Memory { + + +u8* g_base = NULL; ///< The base pointer to the auto-mirrored arena. + +MemArena g_arena; ///< The MemArena class + +u8* g_bootrom = NULL; ///< Bootrom physical memory +u8* g_fcram = NULL; ///< Main memory (FCRAM) pointer +u8* g_vram = NULL; ///< Video memory (VRAM) pointer +u8* g_scratchpad = NULL; ///< Scratchpad memory - Used for main thread stack + +u8* g_physical_bootrom = NULL; ///< Bootrom physical memory +u8* g_uncached_bootrom = NULL; + +u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM) +u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) +u8* g_physical_scratchpad = NULL; ///< Scratchpad memory used for main thread stack + +// We don't declare the IO region in here since its handled by other means. +static MemoryView g_views[] = { + { &g_vram, &g_physical_vram, MEM_VRAM_VADDR, MEM_VRAM_SIZE, 0 }, + { &g_fcram, &g_physical_fcram, MEM_FCRAM_VADDR, MEM_FCRAM_SIZE, MV_IS_PRIMARY_RAM }, +}; + +/*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}, + + // TODO: There are a few swizzled mirrors of VRAM, not sure about the best way to + // implement those. +};*/ + +static const int kNumMemViews = sizeof(g_views) / sizeof(MemoryView); ///< Number of mem views + +void Init() { + int flags = 0; + + for (size_t i = 0; i < ARRAY_SIZE(g_views); i++) { + if (g_views[i].flags & MV_IS_PRIMARY_RAM) + g_views[i].size = MEM_FCRAM_SIZE; + } + + g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena); + + g_scratchpad = new u8[MEM_SCRATCHPAD_SIZE]; + + NOTICE_LOG(MEMMAP, "Memory system initialized. RAM at %p (mirror at 0 @ %p)", g_fcram, + g_physical_fcram); +} + +void Shutdown() { + u32 flags = 0; + MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena); + + g_arena.ReleaseSpace(); + delete[] g_scratchpad; + + g_base = NULL; + g_scratchpad = NULL; + + NOTICE_LOG(MEMMAP, "Memory system shut down."); +} + +} // namespace diff --git a/src/core/mem_map.h b/src/core/mem_map.h new file mode 100644 index 00000000..ad5abd16 --- /dev/null +++ b/src/core/mem_map.h @@ -0,0 +1,73 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "common.h" +#include "common_types.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +enum { + MEM_BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size + MEM_MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size + MEM_VRAM_SIZE = 0x00600000, ///< VRAM size + MEM_DSP_SIZE = 0x00080000, ///< DSP memory size + MEM_AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size + MEM_FCRAM_SIZE = 0x08000000, ///< FCRAM size... Really 0x07E00000, but power of 2 + // works much better + MEM_SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader + + MEM_VRAM_MASK = 0x007FFFFF, + MEM_FCRAM_MASK = (MEM_FCRAM_SIZE - 1), ///< FCRAM mask + MEM_SCRATCHPAD_MASK = (MEM_SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask + + MEM_FCRAM_PADDR = 0x20000000, ///< FCRAM physical address + MEM_FCRAM_PADDR_END = (MEM_FCRAM_PADDR + MEM_FCRAM_SIZE), ///< FCRAM end of physical space + MEM_FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address + MEM_FCRAM_VADDR_END = (MEM_FCRAM_VADDR + MEM_FCRAM_SIZE), ///< FCRAM end of virtual space + + MEM_VRAM_VADDR = 0x1F000000, + MEM_SCRATCHPAD_VADDR = (0x10000000 - MEM_SCRATCHPAD_SIZE), ///< Scratchpad virtual address +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace Memory { + +// 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_fcram; ///< Main memory +extern u8* g_vram; ///< Video memory (VRAM) +extern u8* g_scratchpad; ///< Stack memory + +void Init(); +void Shutdown(); + +u8 Read8(const u32 addr); +u16 Read16(const u32 addr); +u32 Read32(const u32 addr); + +u32 Read8_ZX(const u32 addr); +u32 Read16_ZX(const u32 addr); + +void Write8(const u32 addr, const u8 data); +void Write16(const u32 addr, const u16 data); +void Write32(const u32 addr, const u32 data); + +u8* GetPointer(const u32 Address); + +} // namespace diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp new file mode 100644 index 00000000..7d8ae291 --- /dev/null +++ b/src/core/mem_map_funcs.cpp @@ -0,0 +1,198 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" + +#include "mem_map.h" +#include "hw/hw.h" + +namespace Memory { + +template +inline void _Read(T &var, const u32 addr) { + // 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 + + // Hardware I/O register reads + // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space + if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { + HW::Read(var, addr); + + // FCRAM virtual address reads + } else if ((addr & 0x3E000000) == 0x08000000) { + var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); + + // Scratchpad memory + } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { + var = *((const T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK]); + + /*else if ((addr & 0x3F800000) == 0x04000000) { + var = *((const T*)&m_pVRAM[addr & VRAM_MASK]); + }*/ + + // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. + // Until we progress far enough along, we'll accept all physical address reads here. I think + // that this is typically a corner-case from usermode software unless they are trying to do + // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. + } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { + var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); + + } else { + _assert_msg_(MEMMAP, false, "unknown memory read"); + } +} + +template +inline void _Write(u32 addr, const T data) { + + // Hardware I/O register writes + // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space + if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { + HW::Write(addr, data); + + // ExeFS:/.code is loaded here: + } else if ((addr & 0xFFF00000) == 0x00100000) { + // TODO(ShizZy): This is dumb... handle correctly. From 3DBrew: + // http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions + // The ExeFS:/.code is loaded here, executables must be loaded to the 0x00100000 region when + // the exheader "special memory" flag is clear. The 0x03F00000-byte size restriction only + // applies when this flag is clear. Executables are usually loaded to 0x14000000 when the + // exheader "special memory" flag is set, however this address can be arbitrary. + *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; + + // Scratchpad memory + } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { + *(T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK] = data; + + // Heap mapped by ControlMemory: + } else if ((addr & 0x3E000000) == 0x08000000) { + // TODO(ShizZy): Writes to this virtual address should be put in physical memory at FCRAM + GSP + // heap size... the following is writing to FCRAM + 0, which is actually supposed to be the + // application's GSP heap + *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; + + } else if ((addr & 0xFF000000) == 0x14000000) { + _assert_msg_(MEMMAP, false, "umimplemented write to GSP heap"); + } else if ((addr & 0xFFF00000) == 0x1EC00000) { + _assert_msg_(MEMMAP, false, "umimplemented write to IO registers"); + } else if ((addr & 0xFF000000) == 0x1F000000) { + _assert_msg_(MEMMAP, false, "umimplemented write to VRAM"); + } else if ((addr & 0xFFF00000) == 0x1FF00000) { + _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); + } else if ((addr & 0xFFFF0000) == 0x1FF80000) { + _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); + } else if ((addr & 0xFFFFF000) == 0x1FF81000) { + _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); + + // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. + // Until we progress far enough along, we'll accept all physical address writes here. I think + // that this is typically a corner-case from usermode software unless they are trying to do + // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. + } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { + *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; + + // Error out... + } else { + _assert_msg_(MEMMAP, false, "unknown memory write"); + } +} + +bool IsValidAddress(const u32 addr) { + if ((addr & 0x3E000000) == 0x08000000) { + return true; + } else if ((addr & 0x3F800000) == 0x04000000) { + return true; + } else if ((addr & 0xBFFF0000) == 0x00010000) { + return true; + } else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + MEM_FCRAM_MASK) { + return true; + } else { + return false; + } +} + +u8 *GetPointer(const u32 addr) { + // TODO(bunnei): Just a stub for now... ImplementMe! + if ((addr & 0x3E000000) == 0x08000000) { + return g_fcram + (addr & MEM_FCRAM_MASK); + + // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. + // Until we progress far enough along, we'll accept all physical address reads here. I think + // that this is typically a corner-case from usermode software unless they are trying to do + // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. + } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { + return g_fcram + (addr & MEM_FCRAM_MASK); + + //else if ((addr & 0x3F800000) == 0x04000000) { + // return g_vram + (addr & MEM_VRAM_MASK); + //} + //else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + g_MemorySize) { + // return m_pRAM + (addr & g_MemoryMask); + //} + } else { + //ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + ERROR_LOG(MEMMAP, "Unknown GetPointer %08x", addr); + static bool reported = false; + //if (!reported) { + // Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + // reported = true; + //} + //if (!g_Config.bIgnoreBadMemAccess) { + // Core_EnableStepping(true); + // host->SetDebugMode(true); + //} + return 0; + } +} + +u8 Read8(const u32 addr) { + u8 _var = 0; + _Read(_var, addr); + return (u8)_var; +} + +u16 Read16(const u32 addr) { + u16_le _var = 0; + _Read(_var, addr); + return (u16)_var; +} + +u32 Read32(const u32 addr) { + u32_le _var = 0; + _Read(_var, addr); + return _var; +} + +u64 Read64(const u32 addr) { + u64_le _var = 0; + _Read(_var, addr); + return _var; +} + +u32 Read8_ZX(const u32 addr) { + return (u32)Read8(addr); +} + +u32 Read16_ZX(const u32 addr) { + return (u32)Read16(addr); +} + +void Write8(const u32 addr, const u8 data) { + _Write(addr, data); +} + +void Write16(const u32 addr, const u16 data) { + _Write(addr, data); +} + +void Write32(const u32 addr, const u32 data) { + _Write(addr, data); +} + +void Write64(const u32 addr, const u64 data) { + _Write(addr, data); +} + +} // namespace diff --git a/src/core/src/arm/arm_interface.h b/src/core/src/arm/arm_interface.h deleted file mode 100644 index eee2f624..00000000 --- a/src/core/src/arm/arm_interface.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" -#include "common_types.h" - -/// Generic ARM11 CPU interface -class ARM_Interface { -public: - ARM_Interface() { - num_instructions_ = 0; - } - - ~ARM_Interface() { - } - - /// Step CPU by one instruction - void Step() { - ExecuteInstruction(); - num_instructions_++; - } - - /** - * Set the Program Counter to an address - * @param addr Address to set PC to - */ - virtual void SetPC(u32 addr) = 0; - - /* - * Get the current Program Counter - * @return Returns current PC - */ - virtual u32 PC() = 0; - - /** - * Get an ARM register - * @param index Register index (0-15) - * @return Returns the value in the register - */ - virtual u32 Reg(int index) = 0; - - /** - * Get the current CPSR register - * @return Returns the value of the CPSR register - */ - virtual u32 CPSR() = 0; - - /** - * Returns the number of clock ticks since the last rese - * @return Returns number of clock ticks - */ - virtual u64 GetTicks() = 0; - - /// Getter for num_instructions_ - u64 num_instructions() { return num_instructions_; } - -private: - - /// Execture next instruction - virtual void ExecuteInstruction() = 0; - - u64 num_instructions_; ///< Number of instructions executed - - DISALLOW_COPY_AND_ASSIGN(ARM_Interface); -}; diff --git a/src/core/src/arm/disassembler/arm_disasm.cpp b/src/core/src/arm/disassembler/arm_disasm.cpp deleted file mode 100644 index 82ca5ee8..00000000 --- a/src/core/src/arm/disassembler/arm_disasm.cpp +++ /dev/null @@ -1,1003 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#include -#include -#include "arm_disasm.h" - -static const char *cond_names[] = { - "eq", - "ne", - "cs", - "cc", - "mi", - "pl", - "vs", - "vc", - "hi", - "ls", - "ge", - "lt", - "gt", - "le", - "", - "RESERVED" -}; - -const char *opcode_names[] = { - "invalid", - "undefined", - "adc", - "add", - "and", - "b", - "bl", - "bic", - "bkpt", - "blx", - "bx", - "cdp", - "clz", - "cmn", - "cmp", - "eor", - "ldc", - "ldm", - "ldr", - "ldrb", - "ldrbt", - "ldrh", - "ldrsb", - "ldrsh", - "ldrt", - "mcr", - "mla", - "mov", - "mrc", - "mrs", - "msr", - "mul", - "mvn", - "orr", - "pld", - "rsb", - "rsc", - "sbc", - "smlal", - "smull", - "stc", - "stm", - "str", - "strb", - "strbt", - "strh", - "strt", - "sub", - "swi", - "swp", - "swpb", - "teq", - "tst", - "umlal", - "umull", - - "undefined", - "adc", - "add", - "and", - "asr", - "b", - "bic", - "bkpt", - "bl", - "blx", - "bx", - "cmn", - "cmp", - "eor", - "ldmia", - "ldr", - "ldrb", - "ldrh", - "ldrsb", - "ldrsh", - "lsl", - "lsr", - "mov", - "mul", - "mvn", - "neg", - "orr", - "pop", - "push", - "ror", - "sbc", - "stmia", - "str", - "strb", - "strh", - "sub", - "swi", - "tst", - - NULL -}; - -// Indexed by the shift type (bits 6-5) -static const char *shift_names[] = { - "LSL", - "LSR", - "ASR", - "ROR" -}; - -static const char* cond_to_str(int cond) { - return cond_names[cond]; -} - -char *ARM_Disasm::disasm(uint32_t addr, uint32_t insn, char *result) -{ - static char buf[80]; - char *ptr; - - ptr = result ? result : buf; - Opcode opcode = decode(insn); - switch (opcode) { - case OP_INVALID: - sprintf(ptr, "Invalid"); - return ptr; - case OP_UNDEFINED: - sprintf(ptr, "Undefined"); - return ptr; - case OP_ADC: - case OP_ADD: - case OP_AND: - case OP_BIC: - case OP_CMN: - case OP_CMP: - case OP_EOR: - case OP_MOV: - case OP_MVN: - case OP_ORR: - case OP_RSB: - case OP_RSC: - case OP_SBC: - case OP_SUB: - case OP_TEQ: - case OP_TST: - return disasm_alu(opcode, insn, ptr); - case OP_B: - case OP_BL: - return disasm_branch(addr, opcode, insn, ptr); - case OP_BKPT: - return disasm_bkpt(insn, ptr); - case OP_BLX: - // not supported yet - break; - case OP_BX: - return disasm_bx(insn, ptr); - case OP_CDP: - sprintf(ptr, "cdp"); - return ptr; - case OP_CLZ: - return disasm_clz(insn, ptr); - case OP_LDC: - sprintf(ptr, "ldc"); - return ptr; - case OP_LDM: - case OP_STM: - return disasm_memblock(opcode, insn, ptr); - case OP_LDR: - case OP_LDRB: - case OP_LDRBT: - case OP_LDRT: - case OP_STR: - case OP_STRB: - case OP_STRBT: - case OP_STRT: - return disasm_mem(insn, ptr); - case OP_LDRH: - case OP_LDRSB: - case OP_LDRSH: - case OP_STRH: - return disasm_memhalf(insn, ptr); - case OP_MCR: - case OP_MRC: - return disasm_mcr(opcode, insn, ptr); - case OP_MLA: - return disasm_mla(opcode, insn, ptr); - case OP_MRS: - return disasm_mrs(insn, ptr); - case OP_MSR: - return disasm_msr(insn, ptr); - case OP_MUL: - return disasm_mul(opcode, insn, ptr); - case OP_PLD: - return disasm_pld(insn, ptr); - case OP_STC: - sprintf(ptr, "stc"); - return ptr; - case OP_SWI: - return disasm_swi(insn, ptr); - case OP_SWP: - case OP_SWPB: - return disasm_swp(opcode, insn, ptr); - case OP_UMLAL: - case OP_UMULL: - case OP_SMLAL: - case OP_SMULL: - return disasm_umlal(opcode, insn, ptr); - default: - sprintf(ptr, "Error"); - return ptr; - } - return NULL; -} - -char *ARM_Disasm::disasm_alu(Opcode opcode, uint32_t insn, char *ptr) -{ - static const uint8_t kNoOperand1 = 1; - static const uint8_t kNoDest = 2; - static const uint8_t kNoSbit = 4; - - char rn_str[20]; - char rd_str[20]; - uint8_t flags = 0; - uint8_t cond = (insn >> 28) & 0xf; - uint8_t is_immed = (insn >> 25) & 0x1; - uint8_t bit_s = (insn >> 20) & 1; - uint8_t rn = (insn >> 16) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint8_t immed = insn & 0xff; - - const char *opname = opcode_names[opcode]; - switch (opcode) { - case OP_CMN: - case OP_CMP: - case OP_TEQ: - case OP_TST: - flags = kNoDest | kNoSbit; - break; - case OP_MOV: - case OP_MVN: - flags = kNoOperand1; - break; - default: - break; - } - - // The "mov" instruction ignores the first operand (rn). - rn_str[0] = 0; - if ((flags & kNoOperand1) == 0) { - sprintf(rn_str, "r%d, ", rn); - } - - // The following instructions do not write the result register (rd): - // tst, teq, cmp, cmn. - rd_str[0] = 0; - if ((flags & kNoDest) == 0) { - sprintf(rd_str, "r%d, ", rd); - } - - const char *sbit_str = ""; - if (bit_s && !(flags & kNoSbit)) - sbit_str = "s"; - - if (is_immed) { - sprintf(ptr, "%s%s%s\t%s%s#%u ; 0x%x", - opname, cond_to_str(cond), sbit_str, rd_str, rn_str, immed, immed); - return ptr; - } - - uint8_t shift_is_reg = (insn >> 4) & 1; - uint8_t rotate = (insn >> 8) & 0xf; - uint8_t rm = insn & 0xf; - uint8_t shift_type = (insn >> 5) & 0x3; - uint8_t rs = (insn >> 8) & 0xf; - uint8_t shift_amount = (insn >> 7) & 0x1f; - uint32_t rotated_val = immed; - uint8_t rotate2 = rotate << 1; - rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); - - if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { - sprintf(ptr, "%s%s%s\t%s%sr%d", - opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); - return ptr; - } - - const char *shift_name = shift_names[shift_type]; - if (shift_is_reg) { - sprintf(ptr, "%s%s%s\t%s%sr%d, %s r%d", - opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, - shift_name, rs); - return ptr; - } - if (shift_amount == 0) { - if (shift_type == 3) { - sprintf(ptr, "%s%s%s\t%s%sr%d, RRX", - opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); - return ptr; - } - shift_amount = 32; - } - sprintf(ptr, "%s%s%s\t%s%sr%d, %s #%u", - opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, - shift_name, shift_amount); - return ptr; -} - -char *ARM_Disasm::disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint32_t offset = insn & 0xffffff; - // Sign-extend the 24-bit offset - if ((offset >> 23) & 1) - offset |= 0xff000000; - - // Pre-compute the left-shift and the prefetch offset - offset <<= 2; - offset += 8; - addr += offset; - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s\t0x%x", opname, cond_to_str(cond), addr); - return ptr; -} - -char *ARM_Disasm::disasm_bx(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rn = insn & 0xf; - sprintf(ptr, "bx%s\tr%d", cond_to_str(cond), rn); - return ptr; -} - -char *ARM_Disasm::disasm_bkpt(uint32_t insn, char *ptr) -{ - uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); - sprintf(ptr, "bkpt\t#%d", immed); - return ptr; -} - -char *ARM_Disasm::disasm_clz(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint8_t rm = insn & 0xf; - sprintf(ptr, "clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); - return ptr; -} - -char *ARM_Disasm::disasm_memblock(Opcode opcode, uint32_t insn, char *ptr) -{ - char tmp_reg[10], tmp_list[80]; - - uint8_t cond = (insn >> 28) & 0xf; - uint8_t write_back = (insn >> 21) & 0x1; - uint8_t bit_s = (insn >> 22) & 0x1; - uint8_t is_up = (insn >> 23) & 0x1; - uint8_t is_pre = (insn >> 24) & 0x1; - uint8_t rn = (insn >> 16) & 0xf; - uint16_t reg_list = insn & 0xffff; - - const char *opname = opcode_names[opcode]; - - const char *bang = ""; - if (write_back) - bang = "!"; - - const char *carret = ""; - if (bit_s) - carret = "^"; - - const char *comma = ""; - tmp_list[0] = 0; - for (int ii = 0; ii < 16; ++ii) { - if (reg_list & (1 << ii)) { - sprintf(tmp_reg, "%sr%d", comma, ii); - strcat(tmp_list, tmp_reg); - comma = ","; - } - } - - const char *addr_mode = ""; - if (is_pre) { - if (is_up) { - addr_mode = "ib"; - } else { - addr_mode = "db"; - } - } else { - if (is_up) { - addr_mode = "ia"; - } else { - addr_mode = "da"; - } - } - - sprintf(ptr, "%s%s%s\tr%d%s, {%s}%s", - opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list, carret); - return ptr; -} - -char *ARM_Disasm::disasm_mem(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t is_reg = (insn >> 25) & 0x1; - uint8_t is_load = (insn >> 20) & 0x1; - uint8_t write_back = (insn >> 21) & 0x1; - uint8_t is_byte = (insn >> 22) & 0x1; - uint8_t is_up = (insn >> 23) & 0x1; - uint8_t is_pre = (insn >> 24) & 0x1; - uint8_t rn = (insn >> 16) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint16_t offset = insn & 0xfff; - - const char *opname = "ldr"; - if (!is_load) - opname = "str"; - - const char *bang = ""; - if (write_back) - bang = "!"; - - const char *minus = ""; - if (is_up == 0) - minus = "-"; - - const char *byte = ""; - if (is_byte) - byte = "b"; - - if (is_reg == 0) { - if (is_pre) { - if (offset == 0) { - sprintf(ptr, "%s%s%s\tr%d, [r%d]", - opname, cond_to_str(cond), byte, rd, rn); - } else { - sprintf(ptr, "%s%s%s\tr%d, [r%d, #%s%u]%s", - opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); - } - } else { - const char *transfer = ""; - if (write_back) - transfer = "t"; - sprintf(ptr, "%s%s%s%s\tr%d, [r%d], #%s%u", - opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); - } - return ptr; - } - - uint8_t rm = insn & 0xf; - uint8_t shift_type = (insn >> 5) & 0x3; - uint8_t shift_amount = (insn >> 7) & 0x1f; - - const char *shift_name = shift_names[shift_type]; - - if (is_pre) { - if (shift_amount == 0) { - if (shift_type == 0) { - sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d]%s", - opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); - return ptr; - } - if (shift_type == 3) { - sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", - opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); - return ptr; - } - shift_amount = 32; - } - sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", - opname, cond_to_str(cond), byte, rd, rn, minus, rm, - shift_name, shift_amount, bang); - return ptr; - } - - const char *transfer = ""; - if (write_back) - transfer = "t"; - - if (shift_amount == 0) { - if (shift_type == 0) { - sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d", - opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - return ptr; - } - if (shift_type == 3) { - sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, RRX", - opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - return ptr; - } - shift_amount = 32; - } - - sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", - opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, - shift_name, shift_amount); - return ptr; -} - -char *ARM_Disasm::disasm_memhalf(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t is_load = (insn >> 20) & 0x1; - uint8_t write_back = (insn >> 21) & 0x1; - uint8_t is_immed = (insn >> 22) & 0x1; - uint8_t is_up = (insn >> 23) & 0x1; - uint8_t is_pre = (insn >> 24) & 0x1; - uint8_t rn = (insn >> 16) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint8_t bits_65 = (insn >> 5) & 0x3; - uint8_t rm = insn & 0xf; - uint8_t offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); - - const char *opname = "ldr"; - if (is_load == 0) - opname = "str"; - - const char *width = ""; - if (bits_65 == 1) - width = "h"; - else if (bits_65 == 2) - width = "sb"; - else - width = "sh"; - - const char *bang = ""; - if (write_back) - bang = "!"; - const char *minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_immed) { - if (is_pre) { - if (offset == 0) { - sprintf(ptr, "%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); - } else { - sprintf(ptr, "%s%sh\tr%d, [r%d, #%s%u]%s", - opname, cond_to_str(cond), rd, rn, minus, offset, bang); - } - } else { - sprintf(ptr, "%s%sh\tr%d, [r%d], #%s%u", - opname, cond_to_str(cond), rd, rn, minus, offset); - } - return ptr; - } - - if (is_pre) { - sprintf(ptr, "%s%sh\tr%d, [r%d, %sr%d]%s", - opname, cond_to_str(cond), rd, rn, minus, rm, bang); - } else { - sprintf(ptr, "%s%sh\tr%d, [r%d], %sr%d", - opname, cond_to_str(cond), rd, rn, minus, rm); - } - return ptr; -} - -char *ARM_Disasm::disasm_mcr(Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t crn = (insn >> 16) & 0xf; - uint8_t crd = (insn >> 12) & 0xf; - uint8_t cpnum = (insn >> 8) & 0xf; - uint8_t opcode2 = (insn >> 5) & 0x7; - uint8_t crm = insn & 0xf; - - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", - opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); - return ptr; -} - -char *ARM_Disasm::disasm_mla(Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rd = (insn >> 16) & 0xf; - uint8_t rn = (insn >> 12) & 0xf; - uint8_t rs = (insn >> 8) & 0xf; - uint8_t rm = insn & 0xf; - uint8_t bit_s = (insn >> 20) & 1; - - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", - opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); - return ptr; -} - -char *ARM_Disasm::disasm_umlal(Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rdhi = (insn >> 16) & 0xf; - uint8_t rdlo = (insn >> 12) & 0xf; - uint8_t rs = (insn >> 8) & 0xf; - uint8_t rm = insn & 0xf; - uint8_t bit_s = (insn >> 20) & 1; - - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", - opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); - return ptr; -} - -char *ARM_Disasm::disasm_mul(Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rd = (insn >> 16) & 0xf; - uint8_t rs = (insn >> 8) & 0xf; - uint8_t rm = insn & 0xf; - uint8_t bit_s = (insn >> 20) & 1; - - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s%s\tr%d, r%d, r%d", - opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); - return ptr; -} - -char *ARM_Disasm::disasm_mrs(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint8_t ps = (insn >> 22) & 1; - - sprintf(ptr, "mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); - return ptr; -} - -char *ARM_Disasm::disasm_msr(uint32_t insn, char *ptr) -{ - char flags[8]; - int flag_index = 0; - uint8_t cond = (insn >> 28) & 0xf; - uint8_t is_immed = (insn >> 25) & 0x1; - uint8_t pd = (insn >> 22) & 1; - uint8_t mask = (insn >> 16) & 0xf; - - if (mask & 1) - flags[flag_index++] = 'c'; - if (mask & 2) - flags[flag_index++] = 'x'; - if (mask & 4) - flags[flag_index++] = 's'; - if (mask & 8) - flags[flag_index++] = 'f'; - flags[flag_index] = 0; - - if (is_immed) { - uint32_t immed = insn & 0xff; - uint8_t rotate = (insn >> 8) & 0xf; - uint8_t rotate2 = rotate << 1; - uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); - sprintf(ptr, "msr%s\t%s_%s, #0x%x", - cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); - return ptr; - } - - uint8_t rm = insn & 0xf; - - sprintf(ptr, "msr%s\t%s_%s, r%d", - cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); - return ptr; -} - -char *ARM_Disasm::disasm_pld(uint32_t insn, char *ptr) -{ - uint8_t is_reg = (insn >> 25) & 0x1; - uint8_t is_up = (insn >> 23) & 0x1; - uint8_t rn = (insn >> 16) & 0xf; - - const char *minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_reg) { - uint8_t rm = insn & 0xf; - sprintf(ptr, "pld\t[r%d, %sr%d]", rn, minus, rm); - return ptr; - } - - uint16_t offset = insn & 0xfff; - if (offset == 0) { - sprintf(ptr, "pld\t[r%d]", rn); - } else { - sprintf(ptr, "pld\t[r%d, #%s%u]", rn, minus, offset); - } - return ptr; -} - -char *ARM_Disasm::disasm_swi(uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint32_t sysnum = insn & 0x00ffffff; - - sprintf(ptr, "swi%s 0x%x", cond_to_str(cond), sysnum); - return ptr; -} - -char *ARM_Disasm::disasm_swp(Opcode opcode, uint32_t insn, char *ptr) -{ - uint8_t cond = (insn >> 28) & 0xf; - uint8_t rn = (insn >> 16) & 0xf; - uint8_t rd = (insn >> 12) & 0xf; - uint8_t rm = insn & 0xf; - - const char *opname = opcode_names[opcode]; - sprintf(ptr, "%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); - return ptr; -} - -Opcode ARM_Disasm::decode(uint32_t insn) { - uint32_t bits27_26 = (insn >> 26) & 0x3; - switch (bits27_26) { - case 0x0: - return decode00(insn); - case 0x1: - return decode01(insn); - case 0x2: - return decode10(insn); - case 0x3: - return decode11(insn); - } - return OP_INVALID; -} - -Opcode ARM_Disasm::decode00(uint32_t insn) { - uint8_t bit25 = (insn >> 25) & 0x1; - uint8_t bit4 = (insn >> 4) & 0x1; - if (bit25 == 0 && bit4 == 1) { - if ((insn & 0x0ffffff0) == 0x012fff10) { - // Bx instruction - return OP_BX; - } - if ((insn & 0x0ff000f0) == 0x01600010) { - // Clz instruction - return OP_CLZ; - } - if ((insn & 0xfff000f0) == 0xe1200070) { - // Bkpt instruction - return OP_BKPT; - } - uint32_t bits7_4 = (insn >> 4) & 0xf; - if (bits7_4 == 0x9) { - if ((insn & 0x0ff00ff0) == 0x01000090) { - // Swp instruction - uint8_t bit22 = (insn >> 22) & 0x1; - if (bit22) - return OP_SWPB; - return OP_SWP; - } - // One of the multiply instructions - return decode_mul(insn); - } - - uint8_t bit7 = (insn >> 7) & 0x1; - if (bit7 == 1) { - // One of the load/store halfword/byte instructions - return decode_ldrh(insn); - } - } - - // One of the data processing instructions - return decode_alu(insn); -} - -Opcode ARM_Disasm::decode01(uint32_t insn) { - uint8_t is_reg = (insn >> 25) & 0x1; - uint8_t bit4 = (insn >> 4) & 0x1; - if (is_reg == 1 && bit4 == 1) - return OP_UNDEFINED; - uint8_t is_load = (insn >> 20) & 0x1; - uint8_t is_byte = (insn >> 22) & 0x1; - if ((insn & 0xfd70f000) == 0xf550f000) { - // Pre-load - return OP_PLD; - } - if (is_load) { - if (is_byte) { - // Load byte - return OP_LDRB; - } - // Load word - return OP_LDR; - } - if (is_byte) { - // Store byte - return OP_STRB; - } - // Store word - return OP_STR; -} - -Opcode ARM_Disasm::decode10(uint32_t insn) { - uint8_t bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDM/STM - uint8_t is_load = (insn >> 20) & 0x1; - if (is_load) - return OP_LDM; - return OP_STM; - } - // Branch or Branch with link - uint8_t is_link = (insn >> 24) & 1; - uint32_t offset = insn & 0xffffff; - - // Sign-extend the 24-bit offset - if ((offset >> 23) & 1) - offset |= 0xff000000; - - // Pre-compute the left-shift and the prefetch offset - offset <<= 2; - offset += 8; - if (is_link == 0) - return OP_B; - return OP_BL; -} - -Opcode ARM_Disasm::decode11(uint32_t insn) { - uint8_t bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDC, SDC - uint8_t is_load = (insn >> 20) & 0x1; - if (is_load) { - // LDC - return OP_LDC; - } - // STC - return OP_STC; - } - - uint8_t bit24 = (insn >> 24) & 0x1; - if (bit24 == 0x1) { - // SWI - return OP_SWI; - } - - uint8_t bit4 = (insn >> 4) & 0x1; - uint8_t cpnum = (insn >> 8) & 0xf; - - if (cpnum == 15) { - // Special case for coprocessor 15 - uint8_t opcode = (insn >> 21) & 0x7; - if (bit4 == 0 || opcode != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - - // MRC, MCR - uint8_t is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; - } - - if (bit4 == 0) { - // CDP - return OP_CDP; - } - // MRC, MCR - uint8_t is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; -} - -Opcode ARM_Disasm::decode_mul(uint32_t insn) { - uint8_t bit24 = (insn >> 24) & 0x1; - if (bit24 != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - uint8_t bit23 = (insn >> 23) & 0x1; - uint8_t bit22_U = (insn >> 22) & 0x1; - uint8_t bit21_A = (insn >> 21) & 0x1; - if (bit23 == 0) { - // 32-bit multiply - if (bit22_U != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - if (bit21_A == 0) - return OP_MUL; - return OP_MLA; - } - // 64-bit multiply - if (bit22_U == 0) { - // Unsigned multiply long - if (bit21_A == 0) - return OP_UMULL; - return OP_UMLAL; - } - // Signed multiply long - if (bit21_A == 0) - return OP_SMULL; - return OP_SMLAL; -} - -Opcode ARM_Disasm::decode_ldrh(uint32_t insn) { - uint8_t is_load = (insn >> 20) & 0x1; - uint8_t bits_65 = (insn >> 5) & 0x3; - if (is_load) { - if (bits_65 == 0x1) { - // Load unsigned halfword - return OP_LDRH; - } else if (bits_65 == 0x2) { - // Load signed byte - return OP_LDRSB; - } - // Signed halfword - if (bits_65 != 0x3) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Load signed halfword - return OP_LDRSH; - } - // Store halfword - if (bits_65 != 0x1) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Store halfword - return OP_STRH; -} - -Opcode ARM_Disasm::decode_alu(uint32_t insn) { - uint8_t is_immed = (insn >> 25) & 0x1; - uint8_t opcode = (insn >> 21) & 0xf; - uint8_t bit_s = (insn >> 20) & 1; - uint8_t shift_is_reg = (insn >> 4) & 1; - uint8_t bit7 = (insn >> 7) & 1; - if (!is_immed && shift_is_reg && (bit7 != 0)) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - switch (opcode) { - case 0x0: - return OP_AND; - case 0x1: - return OP_EOR; - case 0x2: - return OP_SUB; - case 0x3: - return OP_RSB; - case 0x4: - return OP_ADD; - case 0x5: - return OP_ADC; - case 0x6: - return OP_SBC; - case 0x7: - return OP_RSC; - case 0x8: - if (bit_s) - return OP_TST; - return OP_MRS; - case 0x9: - if (bit_s) - return OP_TEQ; - return OP_MSR; - case 0xa: - if (bit_s) - return OP_CMP; - return OP_MRS; - case 0xb: - if (bit_s) - return OP_CMN; - return OP_MSR; - case 0xc: - return OP_ORR; - case 0xd: - return OP_MOV; - case 0xe: - return OP_BIC; - case 0xf: - return OP_MVN; - } - // Unreachable - return OP_INVALID; -} \ No newline at end of file diff --git a/src/core/src/arm/disassembler/arm_disasm.h b/src/core/src/arm/disassembler/arm_disasm.h deleted file mode 100644 index 9600e2ad..00000000 --- a/src/core/src/arm/disassembler/arm_disasm.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#ifndef ARMDIS_H -#define ARMDIS_H - -#include - -// Note: this list of opcodes must match the list used to initialize -// the opflags[] array in opcode.cpp. -enum Opcode { - OP_INVALID, - OP_UNDEFINED, - OP_ADC, - OP_ADD, - OP_AND, - OP_B, - OP_BL, - OP_BIC, - OP_BKPT, - OP_BLX, - OP_BX, - OP_CDP, - OP_CLZ, - OP_CMN, - OP_CMP, - OP_EOR, - OP_LDC, - OP_LDM, - OP_LDR, - OP_LDRB, - OP_LDRBT, - OP_LDRH, - OP_LDRSB, - OP_LDRSH, - OP_LDRT, - OP_MCR, - OP_MLA, - OP_MOV, - OP_MRC, - OP_MRS, - OP_MSR, - OP_MUL, - OP_MVN, - OP_ORR, - OP_PLD, - OP_RSB, - OP_RSC, - OP_SBC, - OP_SMLAL, - OP_SMULL, - OP_STC, - OP_STM, - OP_STR, - OP_STRB, - OP_STRBT, - OP_STRH, - OP_STRT, - OP_SUB, - OP_SWI, - OP_SWP, - OP_SWPB, - OP_TEQ, - OP_TST, - OP_UMLAL, - OP_UMULL, - - // Define thumb opcodes - OP_THUMB_UNDEFINED, - OP_THUMB_ADC, - OP_THUMB_ADD, - OP_THUMB_AND, - OP_THUMB_ASR, - OP_THUMB_B, - OP_THUMB_BIC, - OP_THUMB_BKPT, - OP_THUMB_BL, - OP_THUMB_BLX, - OP_THUMB_BX, - OP_THUMB_CMN, - OP_THUMB_CMP, - OP_THUMB_EOR, - OP_THUMB_LDMIA, - OP_THUMB_LDR, - OP_THUMB_LDRB, - OP_THUMB_LDRH, - OP_THUMB_LDRSB, - OP_THUMB_LDRSH, - OP_THUMB_LSL, - OP_THUMB_LSR, - OP_THUMB_MOV, - OP_THUMB_MUL, - OP_THUMB_MVN, - OP_THUMB_NEG, - OP_THUMB_ORR, - OP_THUMB_POP, - OP_THUMB_PUSH, - OP_THUMB_ROR, - OP_THUMB_SBC, - OP_THUMB_STMIA, - OP_THUMB_STR, - OP_THUMB_STRB, - OP_THUMB_STRH, - OP_THUMB_SUB, - OP_THUMB_SWI, - OP_THUMB_TST, - - OP_END // must be last -}; - -class ARM_Disasm { - public: - static char *disasm(uint32_t addr, uint32_t insn, char *buffer); - static Opcode decode(uint32_t insn); - - private: - static Opcode decode00(uint32_t insn); - static Opcode decode01(uint32_t insn); - static Opcode decode10(uint32_t insn); - static Opcode decode11(uint32_t insn); - static Opcode decode_mul(uint32_t insn); - static Opcode decode_ldrh(uint32_t insn); - static Opcode decode_alu(uint32_t insn); - - static char *disasm_alu(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_bx(uint32_t insn, char *ptr); - static char *disasm_bkpt(uint32_t insn, char *ptr); - static char *disasm_clz(uint32_t insn, char *ptr); - static char *disasm_memblock(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_mem(uint32_t insn, char *ptr); - static char *disasm_memhalf(uint32_t insn, char *ptr); - static char *disasm_mcr(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_mla(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_umlal(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_mul(Opcode opcode, uint32_t insn, char *ptr); - static char *disasm_mrs(uint32_t insn, char *ptr); - static char *disasm_msr(uint32_t insn, char *ptr); - static char *disasm_pld(uint32_t insn, char *ptr); - static char *disasm_swi(uint32_t insn, char *ptr); - static char *disasm_swp(Opcode opcode, uint32_t insn, char *ptr); -}; - -extern char *disasm_insn_thumb(uint32_t pc, uint32_t insn1, uint32_t insn2, char *result); -extern Opcode decode_insn_thumb(uint32_t given); - -#endif /* ARMDIS_H */ diff --git a/src/core/src/arm/interpreter/arm_interpreter.cpp b/src/core/src/arm/interpreter/arm_interpreter.cpp deleted file mode 100644 index a74aa26c..00000000 --- a/src/core/src/arm/interpreter/arm_interpreter.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (C) 2013 Citrus Emulator - * - * @file arm_interpreter.h - * @author bunnei - * @date 2014-04-04 - * @brief ARM interface instance for SkyEye interprerer - * - * @section LICENSE - * 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 at - * http://www.gnu.org/copyleft/gpl.html - * - * Official project repository can be found at: - * http://code.google.com/p/gekko-gc-emu/ - */ - -#include "arm_interpreter.h" - -const static cpu_config_t s_arm11_cpu_info = { - "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE -}; - -ARM_Interpreter::ARM_Interpreter() { - - state = new ARMul_State; - - ARMul_EmulateInit(); - ARMul_NewState(state); - - state->abort_model = 0; - state->cpu = (cpu_config_t*)&s_arm11_cpu_info; - state->bigendSig = LOW; - - ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); - state->lateabtSig = LOW; - mmu_init(state); - - // Reset the core to initial state - ARMul_Reset(state); - state->NextInstr = 0; - state->Emulate = 3; - - state->pc = state->Reg[15] = 0x00000000; - state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack -} - -void ARM_Interpreter::SetPC(u32 pc) { - state->pc = state->Reg[15] = pc; -} - -u32 ARM_Interpreter::PC() { - return state->pc; -} - -u32 ARM_Interpreter::Reg(int index){ - return state->Reg[index]; -} - -u32 ARM_Interpreter::CPSR() { - return state->Cpsr; -} - -ARM_Interpreter::~ARM_Interpreter() { - delete state; -} - -void ARM_Interpreter::ExecuteInstruction() { - state->step++; - state->cycle++; - state->EndCondition = 0; - state->stop_simulator = 0; - state->NextInstr = RESUME; - state->last_pc = state->Reg[15]; - state->Reg[15] = ARMul_DoInstr(state); - state->Cpsr = ((state->Cpsr & 0x0fffffdf) | (state->NFlag << 31) | (state->ZFlag << 30) | - (state->CFlag << 29) | (state->VFlag << 28) | (state->TFlag << 5)); - FLUSHPIPE; -} diff --git a/src/core/src/arm/interpreter/arm_interpreter.h b/src/core/src/arm/interpreter/arm_interpreter.h deleted file mode 100644 index 074149f1..00000000 --- a/src/core/src/arm/interpreter/arm_interpreter.h +++ /dev/null @@ -1,57 +0,0 @@ -/** -* Copyright (C) 2013 Citrus Emulator -* -* @file arm_interpreter.h -* @author bunnei -* @date 2014-04-04 -* @brief ARM interface instance for SkyEye interprerer -* -* @section LICENSE -* 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 at -* http://www.gnu.org/copyleft/gpl.html -* -* Official project repository can be found at: -* http://code.google.com/p/gekko-gc-emu/ -*/ - -#pragma once - -#include "common.h" -#include "common_types.h" -#include "arm/arm_interface.h" - -#include "arm/interpreter/armdefs.h" -#include "arm/interpreter/armemu.h" - -class ARM_Interpreter : virtual public ARM_Interface { -public: - ARM_Interpreter(); - ~ARM_Interpreter(); - - void ExecuteInstruction(); - - void SetPC(u32 pc); - - u32 PC(); - - u32 Reg(int index); - - u32 CPSR(); - - u64 GetTicks() { - return ARMul_Time(state); - } - -private: - ARMul_State* state; - - DISALLOW_COPY_AND_ASSIGN(ARM_Interpreter); -}; diff --git a/src/core/src/arm/interpreter/arm_regformat.h b/src/core/src/arm/interpreter/arm_regformat.h deleted file mode 100644 index 0ca62780..00000000 --- a/src/core/src/arm/interpreter/arm_regformat.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef __ARM_REGFORMAT_H__ -#define __ARM_REGFORMAT_H__ - -enum arm_regno{ - R0 = 0, - R1, - R2, - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R10, - R11, - R12, - R13, - LR, - R15, //PC, - CPSR_REG, - SPSR_REG, -#if 1 - PHYS_PC, - R13_USR, - R14_USR, - R13_SVC, - R14_SVC, - R13_ABORT, - R14_ABORT, - R13_UNDEF, - R14_UNDEF, - R13_IRQ, - R14_IRQ, - R8_FIRQ, - R9_FIRQ, - R10_FIRQ, - R11_FIRQ, - R12_FIRQ, - R13_FIRQ, - R14_FIRQ, - SPSR_INVALID1, - SPSR_INVALID2, - SPSR_SVC, - SPSR_ABORT, - SPSR_UNDEF, - SPSR_IRQ, - SPSR_FIRQ, - MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */ - BANK_REG, - EXCLUSIVE_TAG, - EXCLUSIVE_STATE, - EXCLUSIVE_RESULT, - CP15_BASE, - CP15_C0 = CP15_BASE, - CP15_C0_C0 = CP15_C0, - CP15_MAIN_ID = CP15_C0_C0, - CP15_CACHE_TYPE, - CP15_TCM_STATUS, - CP15_TLB_TYPE, - CP15_C0_C1, - CP15_PROCESSOR_FEATURE_0 = CP15_C0_C1, - CP15_PROCESSOR_FEATURE_1, - CP15_DEBUG_FEATURE_0, - CP15_AUXILIARY_FEATURE_0, - CP15_C1_C0, - CP15_CONTROL = CP15_C1_C0, - 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, - CP15_TRANSLATION_BASE_TABLE_1, - CP15_TRANSLATION_BASE_CONTROL, - CP15_DOMAIN_ACCESS_CONTROL, - CP15_RESERVED, - /* Fault status */ - CP15_FAULT_STATUS, - CP15_INSTR_FAULT_STATUS, - CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, - CP15_INST_FSR, - /* Fault Address register */ - CP15_FAULT_ADDRESS, - CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, - CP15_WFAR, - CP15_IFAR, - CP15_PID, - CP15_CONTEXT_ID, - CP15_THREAD_URO, - 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, -#endif - MAX_REG_NUM, -}; - -#define VFP_OFFSET(x) (x - VFP_BASE) -#endif diff --git a/src/core/src/arm/interpreter/armcpu.h b/src/core/src/arm/interpreter/armcpu.h deleted file mode 100644 index d7e336b9..00000000 --- a/src/core/src/arm/interpreter/armcpu.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * arm - * armcpu.h - * - * Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ARM_CPU_H__ -#define __ARM_CPU_H__ -//#include -//#include -//#include -//#include - -#include -#include - -#include "thread.h" - - -typedef struct ARM_CPU_State_s { - ARMul_State * core; - uint32_t core_num; - /* The core id that boot from - */ - uint32_t boot_core_id; -}ARM_CPU_State; - -//static ARM_CPU_State* get_current_cpu(){ -// machine_config_t* mach = get_current_mach(); -// /* Casting a conf_obj_t to ARM_CPU_State type */ -// ARM_CPU_State* cpu = (ARM_CPU_State*)mach->cpu_data->obj; -// -// return cpu; -//} - -/** -* @brief Get the core instance boot from -* -* @return -*/ -//static ARMul_State* get_boot_core(){ -// ARM_CPU_State* cpu = get_current_cpu(); -// return &cpu->core[cpu->boot_core_id]; -//} -/** -* @brief Get the instance of running core -* -* @return the core instance -*/ -//static ARMul_State* get_current_core(){ -// /* Casting a conf_obj_t to ARM_CPU_State type */ -// int id = Common::CurrentThreadId(); -// /* If thread is not in running mode, we should give the boot core */ -// if(get_thread_state(id) != Running_state){ -// return get_boot_core(); -// } -// /* Judge if we are running in paralell or sequenial */ -// if(thread_exist(id)){ -// conf_object_t* conf_obj = get_current_exec_priv(id); -// return (ARMul_State*)get_cast_conf_obj(conf_obj, "arm_core_t"); -// } -// -// return NULL; -//} - -#define CURRENT_CORE get_current_core() - -#endif - diff --git a/src/core/src/arm/interpreter/armdefs.h b/src/core/src/arm/interpreter/armdefs.h deleted file mode 100644 index 0136a52d..00000000 --- a/src/core/src/arm/interpreter/armdefs.h +++ /dev/null @@ -1,934 +0,0 @@ -/* armdefs.h -- ARMulator common 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. */ - -#ifndef _ARMDEFS_H_ -#define _ARMDEFS_H_ - -#include -#include -#include - -#if EMU_PLATFORM == PLATFORM_WINDOWS -#include -#endif - -//teawater add for arm2x86 2005.02.14------------------------------------------- -// koodailar remove it for mingw 2005.12.18---------------- -//anthonylee modify it for portable 2007.01.30 -//#include "portable/mman.h" - -#include "arm_regformat.h" -#include "platform.h" -#include "skyeye_defs.h" - -//AJ2D-------------------------------------------------------------------------- - -//teawater add for arm2x86 2005.07.03------------------------------------------- - -#include -#include -#include -#include -#if EMU_PLATFORM == PLATFORM_LINUX -#include -#endif -#include -#include -#include - -//#include -//AJ2D-------------------------------------------------------------------------- -#if 0 -#if 0 -#define DIFF_STATE 1 -#define __FOLLOW_MODE__ 0 -#else -#define DIFF_STATE 0 -#define __FOLLOW_MODE__ 1 -#endif -#endif - -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif - -#define LOW 0 -#define HIGH 1 -#define LOWHIGH 1 -#define HIGHLOW 2 - -#ifndef u8 -#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned int -#define u64 unsigned long long -#endif /*u8 */ - -//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- -#include - -#include "platform.h" - -#if EMU_PLATFORM == PLATFORM_LINUX -#include -#endif - -//#define DBCT_TEST_SPEED -#define DBCT_TEST_SPEED_SEC 10 -//AJ2D-------------------------------------------------------------------------- - -//teawater add compile switch for DBCT GDB RSP function 2005.10.21-------------- -//#define DBCT_GDBRSP -//AJ2D-------------------------------------------------------------------------- - -//#include -//#include - -#define ARM_BYTE_TYPE 0 -#define ARM_HALFWORD_TYPE 1 -#define ARM_WORD_TYPE 2 - -//the define of cachetype -#define NONCACHE 0 -#define DATACACHE 1 -#define INSTCACHE 2 - -#ifndef __STDC__ -typedef char *VoidStar; -#endif - -typedef unsigned long long ARMdword; /* must be 64 bits wide */ -typedef unsigned int ARMword; /* must be 32 bits wide */ -typedef unsigned char ARMbyte; /* must be 8 bits wide */ -typedef unsigned short ARMhword; /* must be 16 bits wide */ -typedef struct ARMul_State ARMul_State; -typedef struct ARMul_io ARMul_io; -typedef struct ARMul_Energy ARMul_Energy; - -//teawater add for arm2x86 2005.06.24------------------------------------------- -#include -//AJ2D-------------------------------------------------------------------------- -/* -//chy 2005-05-11 -#ifndef __CYGWIN__ -//teawater add for arm2x86 2005.02.14------------------------------------------- -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int u32; -#if defined (__x86_64__) -typedef unsigned long uint64_t; -#else -typedef unsigned long long uint64_t; -#endif -////AJ2D-------------------------------------------------------------------------- -#endif -*/ - -#include "armmmu.h" -//#include "lcd/skyeye_lcd.h" - - -//#include "skyeye.h" -//#include "skyeye_device.h" -//#include "net/skyeye_net.h" -//#include "skyeye_config.h" - - -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); - - -//added by ksh,2004-3-5 -struct ARMul_io -{ - ARMword *instr; //to display the current interrupt state - ARMword *net_flag; //to judge if network is enabled - ARMword *net_int; //netcard interrupt - - //ywc,2004-04-01 - ARMword *ts_int; - ARMword *ts_is_enable; - ARMword *ts_addr_begin; - ARMword *ts_addr_end; - ARMword *ts_buffer; -}; - -/* added by ksh,2004-11-26,some energy profiling */ -struct ARMul_Energy -{ - int energy_prof; /* BUG200103282109 : for energy profiling */ - int enable_func_energy; /* BUG200105181702 */ - char *func_energy; - int func_display; /* BUG200103311509 : for function call display */ - int func_disp_start; /* BUG200104191428 : to start func profiling */ - char *start_func; /* BUG200104191428 */ - - FILE *outfile; /* BUG200105201531 : direct console to file */ - long long tcycle, pcycle; - float t_energy; - void *cur_task; /* BUG200103291737 */ - long long t_mem_cycle, t_idle_cycle, t_uart_cycle; - long long p_mem_cycle, p_idle_cycle, p_uart_cycle; - long long p_io_update_tcycle; - /*record CCCR,to get current core frequency */ - ARMword cccr; -}; -#if 0 -#define MAX_BANK 8 -#define MAX_STR 1024 - -typedef struct mem_bank -{ - ARMword (*read_byte) (ARMul_State * state, ARMword addr); - void (*write_byte) (ARMul_State * state, ARMword addr, ARMword data); - ARMword (*read_halfword) (ARMul_State * state, ARMword addr); - void (*write_halfword) (ARMul_State * state, ARMword addr, - ARMword data); - ARMword (*read_word) (ARMul_State * state, ARMword addr); - void (*write_word) (ARMul_State * state, ARMword addr, ARMword data); - unsigned int addr, len; - char filename[MAX_STR]; - unsigned type; //chy 2003-09-21: maybe io,ram,rom -} mem_bank_t; -typedef struct -{ - int bank_num; - int current_num; /*current num of bank */ - mem_bank_t mem_banks[MAX_BANK]; -} mem_config_t; -#endif -#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 */ - ARMword Cpsr; /* the current psr */ - ARMword Spsr_copy; - ARMword phys_pc; - ARMword Reg_usr[2]; - ARMword Reg_svc[2]; /* R13_SVC R14_SVC */ - ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */ - ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */ - ARMword Reg_irq[2]; /* R13_IRQ R14_IRQ */ - ARMword Reg_firq[7]; /* R8---R14 FIRQ */ - ARMword Spsr[7]; /* the exception psr's */ - ARMword Mode; /* the current mode */ - ARMword Bank; /* the current register bank */ - ARMword exclusive_tag; - ARMword exclusive_state; - ARMword exclusive_result; - ARMword CP15[VFP_BASE - CP15_BASE]; - ARMword VFP[3]; /* FPSID, FPSCR, and FPEXC */ - /* 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 */ - //chy:2003-08-19, used in arm xscale - /* 40 bit accumulator. We always keep this 64 bits wide, - and move only 40 bits out of it in an MRA insn. */ - ARMdword Accumulator; - - ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; /* dummy flags for speed */ - unsigned long long int icounter, debug_icounter, kernel_icounter; - unsigned int shifter_carry_out; - //ARMword translate_pc; - - /* add armv6 flags dyf:2010-08-09 */ - ARMword GEFlag, EFlag, AFlag, QFlags; - //chy:2003-08-19, used in arm v5e|xscale - ARMword SFlag; -#ifdef MODET - ARMword TFlag; /* Thumb state */ -#endif - ARMword instr, pc, temp; /* saved register state */ - ARMword loaded, decoded; /* saved pipeline state */ - //chy 2006-04-12 for ICE breakpoint - ARMword loaded_addr, decoded_addr; /* saved pipeline state addr*/ - unsigned int NumScycles, NumNcycles, NumIcycles, NumCcycles, NumFcycles; /* emulated cycles used */ - unsigned long long NumInstrs; /* the number of instructions executed */ - unsigned NextInstr; - unsigned VectorCatch; /* caught exception mask */ - unsigned CallDebug; /* set to call the debugger */ - unsigned CanWatch; /* set by memory interface if its willing to suffer the - overhead of checking for watchpoints on each memory - access */ - unsigned int StopHandle; - - char *CommandLine; /* Command Line from ARMsd */ - - 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 EventSet; /* the number of events in the queue */ - unsigned int Now; /* time to the nearest cycle */ - struct EventNode **EventPtr; /* the event list */ - - unsigned Debug; /* show instructions as they are executed */ - unsigned NresetSig; /* reset the processor */ - unsigned NfiqSig; - unsigned NirqSig; - - unsigned abortSig; - unsigned NtransSig; - unsigned bigendSig; - unsigned prog32Sig; - unsigned data32Sig; - unsigned syscallSig; - -/* 2004-05-09 chy ----------------------------------------------------------- -read ARM Architecture Reference Manual -2.6.5 Data Abort -There are three Abort Model in ARM arch. - -Early Abort Model: used in some ARMv3 and earlier implementations. In this -model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and -the base register was unchanged for all other instructions. (oldest) - -Base Restored Abort Model: If a Data Abort occurs in an instruction which -specifies base register writeback, the value in the base register is -unchanged. (strongarm, xscale) - -Base Updated Abort Model: If a Data Abort occurs in an instruction which -specifies base register writeback, the base register writeback still occurs. -(arm720T) - -read PART B -chap2 The System Control Coprocessor CP15 -2.4 Register1:control register -L(bit 6): in some ARMv3 and earlier implementations, the abort model of the -processor could be configured: -0=early Abort Model Selected(now obsolete) -1=Late Abort Model selceted(same as Base Updated Abort Model) - -on later processors, this bit reads as 1 and ignores writes. -------------------------------------------------------------- -So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) - if lateabtSig=0, then it means Base Restored Abort Model -*/ - unsigned lateabtSig; - - ARMword Vector; /* synthesize aborts in cycle modes */ - ARMword Aborted; /* sticky flag for aborts */ - ARMword 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 */ - - const struct Dbg_HostosInterface *hostif; - - int verbose; /* non-zero means print various messages like the banner */ - - mmu_state_t mmu; - int mmu_inited; - //mem_state_t mem; - /*remove io_state to skyeye_mach_*.c files */ - //io_state_t io; - /* point to a interrupt pending register. now for skyeye-ne2k.c - * later should move somewhere. e.g machine_config_t*/ - - - //chy: 2003-08-11, for different arm core type - unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */ - unsigned is_v5; /* Are we emulating a v5 architecture ? */ - unsigned is_v5e; /* Are we emulating a v5e architecture ? */ - unsigned is_v6; /* Are we emulating a v6 architecture ? */ - unsigned is_v7; /* Are we emulating a v7 architecture ? */ - unsigned is_XScale; /* Are we emulating an XScale architecture ? */ - unsigned is_iWMMXt; /* Are we emulating an iWMMXt co-processor ? */ - unsigned is_ep9312; /* Are we emulating a Cirrus Maverick co-processor ? */ - //chy 2005-09-19 - unsigned is_pxa27x; /* Are we emulating a Intel PXA27x co-processor ? */ - //chy: seems only used in xscale's CP14 - unsigned int LastTime; /* Value of last call to ARMul_Time() */ - ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit 3 set */ - - -//added by ksh:for handle different machs io 2004-3-5 - ARMul_io mach_io; - -/*added by ksh,2004-11-26,some energy profiling*/ - ARMul_Energy energy; - -//teawater add for next_dis 2004.10.27----------------------- - int disassemble; -//AJ2D------------------------------------------ - -//teawater add for arm2x86 2005.02.15------------------------------------------- - u32 trap; - u32 tea_break_addr; - u32 tea_break_ok; - int tea_pc; -//AJ2D-------------------------------------------------------------------------- -//teawater add for arm2x86 2005.07.03------------------------------------------- - - /* - * 2007-01-24 removed the term-io functions by Anthony Lee, - * moved to "device/uart/skyeye_uart_stdio.c". - */ - -//AJ2D-------------------------------------------------------------------------- -//teawater add for arm2x86 2005.07.05------------------------------------------- - //arm_arm A2-18 - int abort_model; //0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model -//AJ2D-------------------------------------------------------------------------- -//teawater change for return if running tb dirty 2005.07.09--------------------- - void *tb_now; -//AJ2D-------------------------------------------------------------------------- - -//teawater add for record reg value to ./reg.txt 2005.07.10--------------------- - FILE *tea_reg_fd; -//AJ2D-------------------------------------------------------------------------- - -/*added by ksh in 2005-10-1*/ - cpu_config_t *cpu; - //mem_config_t *mem_bank; - -/* added LPC remap function */ - int vector_remap_flag; - u32 vector_remap_addr; - u32 vector_remap_size; - - u32 step; - u32 cycle; - int stop_simulator; - conf_object_t *dyncom_cpu; -//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- -#ifdef DBCT_TEST_SPEED - uint64_t instr_count; -#endif //DBCT_TEST_SPEED -// FILE * state_log; -//diff log -//#if DIFF_STATE - FILE * state_log; -//#endif - /* monitored memory for exclusice access */ - ARMword exclusive_tag_array[128]; - /* 1 means exclusive access and 0 means open access */ - ARMword exclusive_access_state; - - memory_space_intf space; - u32 CurrInstr; - u32 last_pc; /* the last pc executed */ - u32 last_instr; /* the last inst executed */ - u32 WriteAddr[17]; - u32 WriteData[17]; - u32 WritePc[17]; - u32 CurrWrite; -}; -#define DIFF_WRITE 0 - -typedef ARMul_State arm_core_t; -#define ResetPin NresetSig -#define FIQPin NfiqSig -#define IRQPin NirqSig -#define AbortPin abortSig -#define TransPin NtransSig -#define BigEndPin bigendSig -#define Prog32Pin prog32Sig -#define Data32Pin data32Sig -#define LateAbortPin lateabtSig - -/***************************************************************************\ -* Types of ARM we know about * -\***************************************************************************/ - -/* The bitflags */ -#define ARM_Fix26_Prop 0x01 -#define ARM_Nexec_Prop 0x02 -#define ARM_Debug_Prop 0x10 -#define ARM_Isync_Prop ARM_Debug_Prop -#define ARM_Lock_Prop 0x20 -//chy 2003-08-11 -#define ARM_v4_Prop 0x40 -#define ARM_v5_Prop 0x80 -/*jeff.du 2010-08-05 */ -#define ARM_v6_Prop 0xc0 - -#define ARM_v5e_Prop 0x100 -#define ARM_XScale_Prop 0x200 -#define ARM_ep9312_Prop 0x400 -#define ARM_iWMMXt_Prop 0x800 -//chy 2005-09-19 -#define ARM_PXA27X_Prop 0x1000 -#define ARM_v7_Prop 0x2000 - -/* ARM2 family */ -#define ARM2 (ARM_Fix26_Prop) -#define ARM2as ARM2 -#define ARM61 ARM2 -#define ARM3 ARM2 - -#ifdef ARM60 /* previous definition in armopts.h */ -#undef ARM60 -#endif - -/* ARM6 family */ -#define ARM6 (ARM_Lock_Prop) -#define ARM60 ARM6 -#define ARM600 ARM6 -#define ARM610 ARM6 -#define ARM620 ARM6 - - -/***************************************************************************\ -* Macros to extract instruction fields * -\***************************************************************************/ - -#define BIT(n) ( (ARMword)(instr>>(n))&1) /* bit n of instruction */ -#define BITS(m,n) ( (ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) ) /* bits m to n of instr */ -#define TOPBITS(n) (instr >> (n)) /* bits 31 to n of instr */ - -/***************************************************************************\ -* The hardware vector addresses * -\***************************************************************************/ - -#define ARMResetV 0L -#define ARMUndefinedInstrV 4L -#define ARMSWIV 8L -#define ARMPrefetchAbortV 12L -#define ARMDataAbortV 16L -#define ARMAddrExceptnV 20L -#define ARMIRQV 24L -#define ARMFIQV 28L -#define ARMErrorV 32L /* This is an offset, not an address ! */ - -#define ARMul_ResetV ARMResetV -#define ARMul_UndefinedInstrV ARMUndefinedInstrV -#define ARMul_SWIV ARMSWIV -#define ARMul_PrefetchAbortV ARMPrefetchAbortV -#define ARMul_DataAbortV ARMDataAbortV -#define ARMul_AddrExceptnV ARMAddrExceptnV -#define ARMul_IRQV ARMIRQV -#define ARMul_FIQV ARMFIQV - -/***************************************************************************\ -* Mode and Bank Constants * -\***************************************************************************/ - -#define USER26MODE 0L -#define FIQ26MODE 1L -#define IRQ26MODE 2L -#define SVC26MODE 3L -#define USER32MODE 16L -#define FIQ32MODE 17L -#define IRQ32MODE 18L -#define SVC32MODE 19L -#define ABORT32MODE 23L -#define UNDEF32MODE 27L -//chy 2006-02-15 add system32 mode -#define SYSTEM32MODE 31L - -#define ARM32BITMODE (state->Mode > 3) -#define ARM26BITMODE (state->Mode <= 3) -#define ARMMODE (state->Mode) -#define ARMul_MODEBITS 0x1fL -#define ARMul_MODE32BIT ARM32BITMODE -#define ARMul_MODE26BIT ARM26BITMODE - -#define USERBANK 0 -#define FIQBANK 1 -#define IRQBANK 2 -#define SVCBANK 3 -#define ABORTBANK 4 -#define UNDEFBANK 5 -#define DUMMYBANK 6 -#define SYSTEMBANK USERBANK -#define BANK_CAN_ACCESS_SPSR(bank) \ - ((bank) != USERBANK && (bank) != SYSTEMBANK && (bank) != DUMMYBANK) - - -/***************************************************************************\ -* Definitons of things in the emulator * -\***************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif -extern void ARMul_EmulateInit (void); -extern void ARMul_Reset (ARMul_State * state); -#ifdef __cplusplus - } -#endif -extern ARMul_State *ARMul_NewState (ARMul_State * state); -extern ARMword ARMul_DoProg (ARMul_State * state); -extern ARMword ARMul_DoInstr (ARMul_State * state); -/***************************************************************************\ -* Definitons of things for event handling * -\***************************************************************************/ - -extern void ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, - unsigned (*func) ()); -extern void ARMul_EnvokeEvent (ARMul_State * state); -extern unsigned int ARMul_Time (ARMul_State * state); - -/***************************************************************************\ -* Useful support routines * -\***************************************************************************/ - -extern ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, - unsigned reg); -extern void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, - ARMword value); -extern ARMword ARMul_GetPC (ARMul_State * state); -extern ARMword ARMul_GetNextPC (ARMul_State * state); -extern void ARMul_SetPC (ARMul_State * state, ARMword value); -extern ARMword ARMul_GetR15 (ARMul_State * state); -extern void ARMul_SetR15 (ARMul_State * state, ARMword value); - -extern ARMword ARMul_GetCPSR (ARMul_State * state); -extern void ARMul_SetCPSR (ARMul_State * state, ARMword value); -extern ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode); -extern void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value); - -/***************************************************************************\ -* Definitons of things to handle aborts * -\***************************************************************************/ - -extern void ARMul_Abort (ARMul_State * state, ARMword address); -#ifdef MODET -#define ARMul_ABORTWORD (state->TFlag ? 0xefffdfff : 0xefffffff) /* SWI -1 */ -#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ - state->AbortAddr = (address & (state->TFlag ? ~1L : ~3L)) -#else -#define ARMul_ABORTWORD 0xefffffff /* SWI -1 */ -#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ - state->AbortAddr = (address & ~3L) -#endif -#define ARMul_DATAABORT(address) state->abortSig = HIGH ; \ - state->Aborted = ARMul_DataAbortV ; -#define ARMul_CLEARABORT state->abortSig = LOW - -/***************************************************************************\ -* Definitons of things in the memory interface * -\***************************************************************************/ - -extern unsigned ARMul_MemoryInit (ARMul_State * state, - unsigned int initmemsize); -extern void ARMul_MemoryExit (ARMul_State * state); - -extern ARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, - ARMword isize); -extern ARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, - ARMword isize); -#ifdef __cplusplus -extern "C" { -#endif -extern ARMword ARMul_ReLoadInstr (ARMul_State * state, ARMword address, - ARMword isize); -#ifdef __cplusplus - } -#endif -extern ARMword ARMul_LoadWordS (ARMul_State * state, ARMword address); -extern ARMword ARMul_LoadWordN (ARMul_State * state, ARMword address); -extern ARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address); -extern ARMword ARMul_LoadByte (ARMul_State * state, ARMword address); - -extern void ARMul_StoreWordS (ARMul_State * state, ARMword address, - ARMword data); -extern void ARMul_StoreWordN (ARMul_State * state, ARMword address, - ARMword data); -extern void ARMul_StoreHalfWord (ARMul_State * state, ARMword address, - ARMword data); -extern void ARMul_StoreByte (ARMul_State * state, ARMword address, - ARMword data); - -extern ARMword ARMul_SwapWord (ARMul_State * state, ARMword address, - ARMword data); -extern ARMword ARMul_SwapByte (ARMul_State * state, ARMword address, - ARMword data); - -extern void ARMul_Icycles (ARMul_State * state, unsigned number, - ARMword address); -extern void ARMul_Ccycles (ARMul_State * state, unsigned number, - ARMword address); - -extern ARMword ARMul_ReadWord (ARMul_State * state, ARMword address); -extern ARMword ARMul_ReadByte (ARMul_State * state, ARMword address); -extern void ARMul_WriteWord (ARMul_State * state, ARMword address, - ARMword data); -extern void ARMul_WriteByte (ARMul_State * state, ARMword address, - ARMword data); - -extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword, - ARMword, ARMword, ARMword, ARMword, ARMword, - ARMword, ARMword, ARMword); - -/***************************************************************************\ -* Definitons of things in the co-processor interface * -\***************************************************************************/ - -#define ARMul_FIRST 0 -#define ARMul_TRANSFER 1 -#define ARMul_BUSY 2 -#define ARMul_DATA 3 -#define ARMul_INTERRUPT 4 -#define ARMul_DONE 0 -#define ARMul_CANT 1 -#define ARMul_INC 3 - -#define ARMul_CP13_R0_FIQ 0x1 -#define ARMul_CP13_R0_IRQ 0x2 -#define ARMul_CP13_R8_PMUS 0x1 - -#define ARMul_CP14_R0_ENABLE 0x0001 -#define ARMul_CP14_R0_CLKRST 0x0004 -#define ARMul_CP14_R0_CCD 0x0008 -#define ARMul_CP14_R0_INTEN0 0x0010 -#define ARMul_CP14_R0_INTEN1 0x0020 -#define ARMul_CP14_R0_INTEN2 0x0040 -#define ARMul_CP14_R0_FLAG0 0x0100 -#define ARMul_CP14_R0_FLAG1 0x0200 -#define ARMul_CP14_R0_FLAG2 0x0400 -#define ARMul_CP14_R10_MOE_IB 0x0004 -#define ARMul_CP14_R10_MOE_DB 0x0008 -#define ARMul_CP14_R10_MOE_BT 0x000c -#define ARMul_CP15_R1_ENDIAN 0x0080 -#define ARMul_CP15_R1_ALIGN 0x0002 -#define ARMul_CP15_R5_X 0x0400 -#define ARMul_CP15_R5_ST_ALIGN 0x0001 -#define ARMul_CP15_R5_IMPRE 0x0406 -#define ARMul_CP15_R5_MMU_EXCPT 0x0400 -#define ARMul_CP15_DBCON_M 0x0100 -#define ARMul_CP15_DBCON_E1 0x000c -#define ARMul_CP15_DBCON_E0 0x0003 - -extern unsigned ARMul_CoProInit (ARMul_State * state); -extern void ARMul_CoProExit (ARMul_State * state); -extern 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); -extern void ARMul_CoProDetach (ARMul_State * state, unsigned number); - -/***************************************************************************\ -* Definitons of things in the host environment * -\***************************************************************************/ - -extern unsigned ARMul_OSInit (ARMul_State * state); -extern void ARMul_OSExit (ARMul_State * state); - -#ifdef __cplusplus - extern "C" { -#endif - -extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); -#ifdef __cplusplus -} -#endif - - -extern ARMword ARMul_OSLastErrorP (ARMul_State * state); - -extern ARMword ARMul_Debug (ARMul_State * state, ARMword pc, ARMword instr); -extern unsigned ARMul_OSException (ARMul_State * state, ARMword vector, - ARMword pc); -extern int rdi_log; - -/***************************************************************************\ -* Host-dependent stuff * -\***************************************************************************/ - -#ifdef macintosh -pascal void SpinCursor (short increment); /* copied from CursorCtl.h */ -# define HOURGLASS SpinCursor( 1 ) -# define HOURGLASS_RATE 1023 /* 2^n - 1 */ -#endif - -//teawater add for arm2x86 2005.02.14------------------------------------------- -/*ywc 2005-03-31*/ -/* -#include "arm2x86.h" -#include "arm2x86_dp.h" -#include "arm2x86_movl.h" -#include "arm2x86_psr.h" -#include "arm2x86_shift.h" -#include "arm2x86_mem.h" -#include "arm2x86_mul.h" -#include "arm2x86_test.h" -#include "arm2x86_other.h" -#include "list.h" -#include "tb.h" -*/ -#define EQ 0 -#define NE 1 -#define CS 2 -#define CC 3 -#define MI 4 -#define PL 5 -#define VS 6 -#define VC 7 -#define HI 8 -#define LS 9 -#define GE 10 -#define LT 11 -#define GT 12 -#define LE 13 -#define AL 14 -#define NV 15 - -#ifndef NFLAG -#define NFLAG state->NFlag -#endif //NFLAG - -#ifndef ZFLAG -#define ZFLAG state->ZFlag -#endif //ZFLAG - -#ifndef CFLAG -#define CFLAG state->CFlag -#endif //CFLAG - -#ifndef VFLAG -#define VFLAG state->VFlag -#endif //VFLAG - -#ifndef IFLAG -#define IFLAG (state->IFFlags >> 1) -#endif //IFLAG - -#ifndef FFLAG -#define FFLAG (state->IFFlags & 1) -#endif //FFLAG - -#ifndef IFFLAGS -#define IFFLAGS state->IFFlags -#endif //VFLAG - -#define FLAG_MASK 0xf0000000 -#define NBIT_SHIFT 31 -#define ZBIT_SHIFT 30 -#define CBIT_SHIFT 29 -#define VBIT_SHIFT 28 -#ifdef DBCT -//teawater change for local tb branch directly jump 2005.10.18------------------ -#include "dbct/list.h" -#include "dbct/arm2x86.h" -#include "dbct/arm2x86_dp.h" -#include "dbct/arm2x86_movl.h" -#include "dbct/arm2x86_psr.h" -#include "dbct/arm2x86_shift.h" -#include "dbct/arm2x86_mem.h" -#include "dbct/arm2x86_mul.h" -#include "dbct/arm2x86_test.h" -#include "dbct/arm2x86_other.h" -#include "dbct/arm2x86_coproc.h" -#include "dbct/tb.h" -#endif -//AJ2D-------------------------------------------------------------------------- -//AJ2D-------------------------------------------------------------------------- -#define SKYEYE_OUTREGS(fd) { fprintf ((fd), "R %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,C %x,S %x,%x,%x,%x,%x,%x,%x,M %x,B %x,E %x,I %x,P %x,T %x,L %x,D %x,",\ - state->Reg[0],state->Reg[1],state->Reg[2],state->Reg[3], \ - state->Reg[4],state->Reg[5],state->Reg[6],state->Reg[7], \ - state->Reg[8],state->Reg[9],state->Reg[10],state->Reg[11], \ - state->Reg[12],state->Reg[13],state->Reg[14],state->Reg[15], \ - state->Cpsr, state->Spsr[0], state->Spsr[1], state->Spsr[2],\ - state->Spsr[3],state->Spsr[4], state->Spsr[5], state->Spsr[6],\ - state->Mode,state->Bank,state->ErrorCode,state->instr,state->pc,\ - state->temp,state->loaded,state->decoded);} - -#define SKYEYE_OUTMOREREGS(fd) { fprintf ((fd),"\ -RUs %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ -RF %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ -RI %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ -RS %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ -RA %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ -RUn %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",\ - state->RegBank[0][0],state->RegBank[0][1],state->RegBank[0][2],state->RegBank[0][3], \ - state->RegBank[0][4],state->RegBank[0][5],state->RegBank[0][6],state->RegBank[0][7], \ - state->RegBank[0][8],state->RegBank[0][9],state->RegBank[0][10],state->RegBank[0][11], \ - state->RegBank[0][12],state->RegBank[0][13],state->RegBank[0][14],state->RegBank[0][15], \ - state->RegBank[1][0],state->RegBank[1][1],state->RegBank[1][2],state->RegBank[1][3], \ - state->RegBank[1][4],state->RegBank[1][5],state->RegBank[1][6],state->RegBank[1][7], \ - state->RegBank[1][8],state->RegBank[1][9],state->RegBank[1][10],state->RegBank[1][11], \ - state->RegBank[1][12],state->RegBank[1][13],state->RegBank[1][14],state->RegBank[1][15], \ - state->RegBank[2][0],state->RegBank[2][1],state->RegBank[2][2],state->RegBank[2][3], \ - state->RegBank[2][4],state->RegBank[2][5],state->RegBank[2][6],state->RegBank[2][7], \ - state->RegBank[2][8],state->RegBank[2][9],state->RegBank[2][10],state->RegBank[2][11], \ - state->RegBank[2][12],state->RegBank[2][13],state->RegBank[2][14],state->RegBank[2][15], \ - state->RegBank[3][0],state->RegBank[3][1],state->RegBank[3][2],state->RegBank[3][3], \ - state->RegBank[3][4],state->RegBank[3][5],state->RegBank[3][6],state->RegBank[3][7], \ - state->RegBank[3][8],state->RegBank[3][9],state->RegBank[3][10],state->RegBank[3][11], \ - state->RegBank[3][12],state->RegBank[3][13],state->RegBank[3][14],state->RegBank[3][15], \ - state->RegBank[4][0],state->RegBank[4][1],state->RegBank[4][2],state->RegBank[4][3], \ - state->RegBank[4][4],state->RegBank[4][5],state->RegBank[4][6],state->RegBank[4][7], \ - state->RegBank[4][8],state->RegBank[4][9],state->RegBank[4][10],state->RegBank[4][11], \ - state->RegBank[4][12],state->RegBank[4][13],state->RegBank[4][14],state->RegBank[4][15], \ - state->RegBank[5][0],state->RegBank[5][1],state->RegBank[5][2],state->RegBank[5][3], \ - state->RegBank[5][4],state->RegBank[5][5],state->RegBank[5][6],state->RegBank[5][7], \ - state->RegBank[5][8],state->RegBank[5][9],state->RegBank[5][10],state->RegBank[5][11], \ - state->RegBank[5][12],state->RegBank[5][13],state->RegBank[5][14],state->RegBank[5][15] \ - );} - - -#define SA1110 0x6901b110 -#define SA1100 0x4401a100 -#define PXA250 0x69052100 -#define PXA270 0x69054110 -//#define PXA250 0x69052903 -// 0x69052903; //PXA250 B1 from intel 278522-001.pdf - - -extern void ARMul_UndefInstr (ARMul_State *, ARMword); -extern void ARMul_FixCPSR (ARMul_State *, ARMword, ARMword); -extern void ARMul_FixSPSR (ARMul_State *, ARMword, ARMword); -extern void ARMul_ConsolePrint (ARMul_State *, const char *, ...); -extern void ARMul_SelectProcessor (ARMul_State *, unsigned); - -#define DIFF_LOG 0 -#define SAVE_LOG 0 - -#endif /* _ARMDEFS_H_ */ diff --git a/src/core/src/arm/interpreter/armemu.cpp b/src/core/src/arm/interpreter/armemu.cpp deleted file mode 100644 index 46c51fbe..00000000 --- a/src/core/src/arm/interpreter/armemu.cpp +++ /dev/null @@ -1,6631 +0,0 @@ -/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - Modifications to add arch. v4 support by . - - 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 "arm_regformat.h" -#include "armdefs.h" -#include "armemu.h" -#include "armos.h" - -void -XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword _far) -{ - _dbg_assert_msg_(ARM11, false, "ImplementMe: XScale_set_fsr_far!"); - //if (!state->is_XScale || (read_cp14_reg(10) & (1UL << 31)) == 0) - // return; - // - //write_cp15_reg(state, 5, 0, 0, fsr); - //write_cp15_reg(state, 6, 0, 0, _far); -} - -#define ARMul_Debug(x,y,z) 0 // Disabling this /bunnei - -//#include "skyeye_callback.h" -//#include "skyeye_bus.h" -//#include "sim_control.h" -//#include "skyeye_pref.h" -//#include "skyeye.h" -//#include "skyeye2gdb.h" -//#include "code_cov.h" - -//#include "iwmmxt.h" -//chy 2003-07-11: for debug instrs -//extern int skyeye_instr_debug; -extern FILE *skyeye_logfd; - -static ARMword GetDPRegRHS (ARMul_State *, ARMword); -static ARMword GetDPSRegRHS (ARMul_State *, ARMword); -static void WriteR15 (ARMul_State *, ARMword); -static void WriteSR15 (ARMul_State *, ARMword); -static void WriteR15Branch (ARMul_State *, ARMword); -static ARMword GetLSRegRHS (ARMul_State *, ARMword); -static ARMword GetLS7RHS (ARMul_State *, ARMword); -static unsigned LoadWord (ARMul_State *, ARMword, ARMword); -static unsigned LoadHalfWord (ARMul_State *, ARMword, ARMword, int); -static unsigned LoadByte (ARMul_State *, ARMword, ARMword, int); -static unsigned StoreWord (ARMul_State *, ARMword, ARMword); -static unsigned StoreHalfWord (ARMul_State *, ARMword, ARMword); -static unsigned StoreByte (ARMul_State *, ARMword, ARMword); -static void LoadMult (ARMul_State *, ARMword, ARMword, ARMword); -static void StoreMult (ARMul_State *, ARMword, ARMword, ARMword); -static void LoadSMult (ARMul_State *, ARMword, ARMword, ARMword); -static void StoreSMult (ARMul_State *, ARMword, ARMword, ARMword); -static unsigned Multiply64 (ARMul_State *, ARMword, int, int); -static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); -static void Handle_Load_Double (ARMul_State *, ARMword); -static void Handle_Store_Double (ARMul_State *, ARMword); -void -XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far); -int -XScale_debug_moe (ARMul_State * state, int moe); -unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum); - -static int -handle_v6_insn (ARMul_State * state, ARMword instr); - -#define LUNSIGNED (0) /* unsigned operation */ -#define LSIGNED (1) /* signed operation */ -#define LDEFAULT (0) /* default : do nothing */ -#define LSCC (1) /* set condition codes on result */ - -#ifdef NEED_UI_LOOP_HOOK -/* How often to run the ui_loop update, when in use. */ -#define UI_LOOP_POLL_INTERVAL 0x32000 - -/* Counter for the ui_loop_hook update. */ -static int ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; - -/* Actual hook to call to run through gdb's gui event loop. */ -extern int (*ui_loop_hook) (int); -#endif /* NEED_UI_LOOP_HOOK */ - -/* Short-hand macros for LDR/STR. */ - -/* Store post decrement writeback. */ -#define SHDOWNWB() \ - lhs = LHS ; \ - if (StoreHalfWord (state, instr, lhs)) \ - LSBase = lhs - GetLS7RHS (state, instr); - -/* Store post increment writeback. */ -#define SHUPWB() \ - lhs = LHS ; \ - if (StoreHalfWord (state, instr, lhs)) \ - LSBase = lhs + GetLS7RHS (state, instr); - -/* Store pre decrement. */ -#define SHPREDOWN() \ - (void)StoreHalfWord (state, instr, LHS - GetLS7RHS (state, instr)); - -/* Store pre decrement writeback. */ -#define SHPREDOWNWB() \ - temp = LHS - GetLS7RHS (state, instr); \ - if (StoreHalfWord (state, instr, temp)) \ - LSBase = temp; - -/* Store pre increment. */ -#define SHPREUP() \ - (void)StoreHalfWord (state, instr, LHS + GetLS7RHS (state, instr)); - -/* Store pre increment writeback. */ -#define SHPREUPWB() \ - temp = LHS + GetLS7RHS (state, instr); \ - if (StoreHalfWord (state, instr, temp)) \ - LSBase = temp; - -/* Load post decrement writeback. */ -#define LHPOSTDOWN() \ -{ \ - int done = 1; \ - lhs = LHS; \ - temp = lhs - GetLS7RHS (state, instr); \ - \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load post increment writeback. */ -#define LHPOSTUP() \ -{ \ - int done = 1; \ - lhs = LHS; \ - temp = lhs + GetLS7RHS (state, instr); \ - \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre decrement. */ -#define LHPREDOWN() \ -{ \ - int done = 1; \ - \ - temp = LHS - GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ - break; \ - case 2: /* SB */ \ - (void) LoadByte (state, instr, temp, LSIGNED); \ - break; \ - case 3: /* SH */ \ - (void) LoadHalfWord (state, instr, temp, LSIGNED); \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre decrement writeback. */ -#define LHPREDOWNWB() \ -{ \ - int done = 1; \ - \ - temp = LHS - GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre increment. */ -#define LHPREUP() \ -{ \ - int done = 1; \ - \ - temp = LHS + GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ - break; \ - case 2: /* SB */ \ - (void) LoadByte (state, instr, temp, LSIGNED); \ - break; \ - case 3: /* SH */ \ - (void) LoadHalfWord (state, instr, temp, LSIGNED); \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre increment writeback. */ -#define LHPREUPWB() \ -{ \ - int done = 1; \ - \ - temp = LHS + GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/*ywc 2005-03-31*/ -//teawater add for arm2x86 2005.02.17------------------------------------------- -#ifdef DBCT -#include "dbct/tb.h" -#include "dbct/arm2x86_self.h" -#endif -//AJ2D-------------------------------------------------------------------------- - -//Diff register -unsigned int mirror_register_file[39]; - -/* EMULATION of ARM6. */ - -/* The PC pipeline value depends on whether ARM - or Thumb instructions are being executed. */ -ARMword isize; - -extern int debugmode; -int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr); -#ifdef MODE32 -//chy 2006-04-12, for ICE debug -int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr) -{ - int i; -#if 0 - if (debugmode) { - if (instr == ARMul_ABORTWORD) return 0; - for (i = 0; i < skyeye_ice.num_bps; i++) { - if (skyeye_ice.bps[i] == addr) { - //for test - //printf("SKYEYE: ICE_debug bps [%d]== 0x%x\n", i,addr); - state->EndCondition = 0; - state->Emulate = STOP; - return 1; - } - } - if (skyeye_ice.tps_status==TRACE_STARTED) - { - for (i = 0; i < skyeye_ice.num_tps; i++) - { - if (((skyeye_ice.tps[i].tp_address==addr)&&(skyeye_ice.tps[i].status==TRACEPOINT_ENABLED))||(skyeye_ice.tps[i].status==TRACEPOINT_STEPPING)) - { - handle_tracepoint(i); - } - } - } - } - /* do profiling for code coverage */ - if (skyeye_config.code_cov.prof_on) - cov_prof(EXEC_FLAG, addr); -#endif - /* chech if we need to run some callback functions at this time */ - //generic_arch_t* arch_instance = get_arch_instance(""); - //exec_callback(Step_callback, arch_instance); - //if (!SIM_is_running()) { - // if (instr == ARMul_ABORTWORD) return 0; - // state->EndCondition = 0; - // state->Emulate = STOP; - // return 1; - //} - return 0; -} - -/* -void chy_debug() -{ - printf("SkyEye chy_deubeg begin\n"); -} -*/ -ARMword -ARMul_Emulate32 (ARMul_State * state) -#else -ARMword -ARMul_Emulate26 (ARMul_State * state) -#endif -{ - ARMword instr; /* The current instruction. */ - ARMword dest = 0; /* Almost the DestBus. */ - ARMword temp; /* Ubiquitous third hand. */ - ARMword pc = 0; /* The address of the current instruction. */ - ARMword lhs; /* Almost the ABus and BBus. */ - ARMword rhs; - ARMword decoded = 0; /* Instruction pipeline. */ - ARMword loaded = 0; - ARMword decoded_addr=0; - ARMword loaded_addr=0; - ARMword have_bp=0; - - /* shenoubang */ - static int instr_sum = 0; - int reg_index = 0; -#if DIFF_STATE -//initialize all mirror register for follow mode - for (reg_index = 0; reg_index < 16; reg_index ++) { - mirror_register_file[reg_index] = state->Reg[reg_index]; - } - mirror_register_file[CPSR_REG] = state->Cpsr; - mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; - mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; - mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; - mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; - mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; - mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; - mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; - mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; - mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; - mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; - mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; - mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; - mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; - mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; - mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; - mirror_register_file[SPSR_SVC] = state->Spsr[SVCBANK]; - mirror_register_file[SPSR_ABORT] = state->Spsr[ABORTBANK]; - mirror_register_file[SPSR_UNDEF] = state->Spsr[UNDEFBANK]; - mirror_register_file[SPSR_IRQ] = state->Spsr[IRQBANK]; - mirror_register_file[SPSR_FIRQ] = state->Spsr[FIQBANK]; -#endif - /* Execute the next instruction. */ - if (state->NextInstr < PRIMEPIPE) { - decoded = state->decoded; - loaded = state->loaded; - pc = state->pc; - //chy 2006-04-12, for ICE debug - decoded_addr=state->decoded_addr; - loaded_addr=state->loaded_addr; - } - - do { - //print_func_name(state->pc); - /* Just keep going. */ - isize = INSN_SIZE; - - switch (state->NextInstr) { - case SEQ: - /* Advance the pipeline, and an S cycle. */ - state->Reg[15] += isize; - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp = ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - if (have_bp) goto TEST_EMULATE; - break; - - case NONSEQ: - /* Advance the pipeline, and an N cycle. */ - state->Reg[15] += isize; - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case PCINCEDSEQ: - /* Program counter advanced, and an S cycle. */ - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case PCINCEDNONSEQ: - /* Program counter advanced, and an N cycle. */ - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case RESUME: - /* The program counter has been changed. */ - pc = state->Reg[15]; -#ifndef MODE32 - pc = pc & R15PCBITS; -#endif - state->Reg[15] = pc + (isize * 2); - state->Aborted = 0; - //chy 2004-05-25, fix bug provided by Carl van Schaik - state->AbortAddr = 1; - - instr = ARMul_LoadInstrN (state, pc, isize); - //instr = ARMul_ReLoadInstr (state, pc, isize); - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,pc); - //decoded = - // ARMul_ReLoadInstr (state, pc + isize, isize); - decoded_addr=pc+isize; - //loaded = ARMul_ReLoadInstr (state, pc + isize * 2, - // isize); - loaded_addr=pc + isize * 2; - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - default: - /* The program counter has been changed. */ - pc = state->Reg[15]; -#ifndef MODE32 - pc = pc & R15PCBITS; -#endif - state->Reg[15] = pc + (isize * 2); - state->Aborted = 0; - //chy 2004-05-25, fix bug provided by Carl van Schaik - state->AbortAddr = 1; - - instr = ARMul_LoadInstrN (state, pc, isize); - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,pc); - #if 0 - decoded = - ARMul_LoadInstrS (state, pc + (isize), isize); - #endif - decoded_addr=pc+isize; - #if 0 - loaded = ARMul_LoadInstrS (state, pc + (isize * 2), - isize); - #endif - loaded_addr=pc + isize * 2; - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - } -#if 0 - int idx = 0; - printf("pc:%x\n", pc); - for (;idx < 17; idx ++) { - printf("R%d:%x\t", idx, state->Reg[idx]); - } - printf("\n"); -#endif - instr = ARMul_LoadInstrN (state, pc, isize); - state->last_instr = state->CurrInstr; - state->CurrInstr = instr; -#if 0 - if((state->NumInstrs % 10000000) == 0) - printf("---|%p|--- %lld\n", pc, state->NumInstrs); - if(state->NumInstrs > (3000000000)){ - static int flag = 0; - if(pc == 0x8032ccc4){ - flag = 300; - } - if(flag){ - int idx = 0; - printf("------------------------------------\n"); - printf("pc:%x\n", pc); - for (;idx < 17; idx ++) { - printf("R%d:%x\t", idx, state->Reg[idx]); - } - printf("\nN:%d\t Z:%d\t C:%d\t V:%d\n", state->NFlag, state->ZFlag, state->CFlag, state->VFlag); - printf("\n"); - printf("------------------------------------\n"); - flag--; - } - } -#endif -#if DIFF_STATE - fprintf(state->state_log, "PC:0x%x\n", pc); - if (pc && (pc + 8) != state->Reg[15]) { - printf("lucky dog\n"); - printf("pc is %x, R15 is %x\n", pc, state->Reg[15]); - //exit(-1); - } - for (reg_index = 0; reg_index < 16; reg_index ++) { - if (state->Reg[reg_index] != mirror_register_file[reg_index]) { - fprintf(state->state_log, "R%d:0x%x\n", reg_index, state->Reg[reg_index]); - mirror_register_file[reg_index] = state->Reg[reg_index]; - } - } - if (state->Cpsr != mirror_register_file[CPSR_REG]) { - fprintf(state->state_log, "Cpsr:0x%x\n", state->Cpsr); - mirror_register_file[CPSR_REG] = state->Cpsr; - } - if (state->RegBank[SVCBANK][13] != mirror_register_file[R13_SVC]) { - fprintf(state->state_log, "R13_SVC:0x%x\n", state->RegBank[SVCBANK][13]); - mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; - } - if (state->RegBank[SVCBANK][14] != mirror_register_file[R14_SVC]) { - fprintf(state->state_log, "R14_SVC:0x%x\n", state->RegBank[SVCBANK][14]); - mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; - } - if (state->RegBank[ABORTBANK][13] != mirror_register_file[R13_ABORT]) { - fprintf(state->state_log, "R13_ABORT:0x%x\n", state->RegBank[ABORTBANK][13]); - mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; - } - if (state->RegBank[ABORTBANK][14] != mirror_register_file[R14_ABORT]) { - fprintf(state->state_log, "R14_ABORT:0x%x\n", state->RegBank[ABORTBANK][14]); - mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; - } - if (state->RegBank[UNDEFBANK][13] != mirror_register_file[R13_UNDEF]) { - fprintf(state->state_log, "R13_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][13]); - mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; - } - if (state->RegBank[UNDEFBANK][14] != mirror_register_file[R14_UNDEF]) { - fprintf(state->state_log, "R14_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][14]); - mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; - } - if (state->RegBank[IRQBANK][13] != mirror_register_file[R13_IRQ]) { - fprintf(state->state_log, "R13_IRQ:0x%x\n", state->RegBank[IRQBANK][13]); - mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; - } - if (state->RegBank[IRQBANK][14] != mirror_register_file[R14_IRQ]) { - fprintf(state->state_log, "R14_IRQ:0x%x\n", state->RegBank[IRQBANK][14]); - mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; - } - if (state->RegBank[FIQBANK][8] != mirror_register_file[R8_FIRQ]) { - fprintf(state->state_log, "R8_FIRQ:0x%x\n", state->RegBank[FIQBANK][8]); - mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; - } - if (state->RegBank[FIQBANK][9] != mirror_register_file[R9_FIRQ]) { - fprintf(state->state_log, "R9_FIRQ:0x%x\n", state->RegBank[FIQBANK][9]); - mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; - } - if (state->RegBank[FIQBANK][10] != mirror_register_file[R10_FIRQ]) { - fprintf(state->state_log, "R10_FIRQ:0x%x\n", state->RegBank[FIQBANK][10]); - mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; - } - if (state->RegBank[FIQBANK][11] != mirror_register_file[R11_FIRQ]) { - fprintf(state->state_log, "R11_FIRQ:0x%x\n", state->RegBank[FIQBANK][11]); - mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; - } - if (state->RegBank[FIQBANK][12] != mirror_register_file[R12_FIRQ]) { - fprintf(state->state_log, "R12_FIRQ:0x%x\n", state->RegBank[FIQBANK][12]); - mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; - } - if (state->RegBank[FIQBANK][13] != mirror_register_file[R13_FIRQ]) { - fprintf(state->state_log, "R13_FIRQ:0x%x\n", state->RegBank[FIQBANK][13]); - mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; - } - if (state->RegBank[FIQBANK][14] != mirror_register_file[R14_FIRQ]) { - fprintf(state->state_log, "R14_FIRQ:0x%x\n", state->RegBank[FIQBANK][14]); - mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; - } - if (state->Spsr[SVCBANK] != mirror_register_file[SPSR_SVC]) { - fprintf(state->state_log, "SPSR_SVC:0x%x\n", state->Spsr[SVCBANK]); - mirror_register_file[SPSR_SVC] = state->RegBank[SVCBANK]; - } - if (state->Spsr[ABORTBANK] != mirror_register_file[SPSR_ABORT]) { - fprintf(state->state_log, "SPSR_ABORT:0x%x\n", state->Spsr[ABORTBANK]); - mirror_register_file[SPSR_ABORT] = state->RegBank[ABORTBANK]; - } - if (state->Spsr[UNDEFBANK] != mirror_register_file[SPSR_UNDEF]) { - fprintf(state->state_log, "SPSR_UNDEF:0x%x\n", state->Spsr[UNDEFBANK]); - mirror_register_file[SPSR_UNDEF] = state->RegBank[UNDEFBANK]; - } - if (state->Spsr[IRQBANK] != mirror_register_file[SPSR_IRQ]) { - fprintf(state->state_log, "SPSR_IRQ:0x%x\n", state->Spsr[IRQBANK]); - mirror_register_file[SPSR_IRQ] = state->RegBank[IRQBANK]; - } - if (state->Spsr[FIQBANK] != mirror_register_file[SPSR_FIRQ]) { - fprintf(state->state_log, "SPSR_FIRQ:0x%x\n", state->Spsr[FIQBANK]); - mirror_register_file[SPSR_FIRQ] = state->RegBank[FIQBANK]; - } -#endif - -#if 0 - uint32_t alex = 0; - static int flagged = 0; - if ((flagged == 0) && (pc == 0xb224)) - { - flagged++; - } - if ((flagged == 1) && (pc == 0x1a800)) - { - flagged++; - } - if (flagged == 3) { - printf("---|%p|--- %x\n", pc, state->NumInstrs); - for (alex = 0; alex < 15; alex++) - { - printf("R%02d % 8x\n", alex, state->Reg[alex]); - } - printf("R%02d % 8x\n", alex, state->Reg[alex] - 8); - printf("CPS %x%07x\n", (state->NFlag<<3 | state->ZFlag<<2 | state->CFlag<<1 | state->VFlag), state->Cpsr & 0xfffffff); - } else { - if (state->NumInstrs < 0x400000) - { - //exit(-1); - } - } -#endif - - if (state->EventSet) - ARMul_EnvokeEvent (state); - -#if 0 - /* do profiling for code coverage */ - if (skyeye_config.code_cov.prof_on) - cov_prof(EXEC_FLAG, pc); -#endif -//2003-07-11 chy: for test -#if 0 - if (skyeye_config.log.logon >= 1) { - if (state->NumInstrs >= skyeye_config.log.start && - state->NumInstrs <= skyeye_config.log.end) { - static int mybegin = 0; - static int myinstrnum = 0; - if (mybegin == 0) - mybegin = 1; -#if 0 - if (state->NumInstrs == 3695) { - printf ("***********SKYEYE: numinstr = 3695\n"); - } - static int mybeg2 = 0; - static int mybeg3 = 0; - static int mybeg4 = 0; - static int mybeg5 = 0; - - if (pc == 0xa0008000) { - //mybegin=1; - printf ("************SKYEYE: real vmlinux begin now numinstr is %llu ****************\n", state->NumInstrs); - } - - //chy 2003-09-02 test fiq - if (state->NumInstrs == 67347000) { - printf ("***********SKYEYE: numinstr = 67347000, begin log\n"); - mybegin = 1; - } - if (pc == 0xc00087b4) { //numinstr=67348714 - mybegin = 1; - printf ("************SKYEYE: test irq now numinstr is %llu ****************\n", state->NumInstrs); - } - if (pc == 0xc00087b8) { //in start_kernel::sti() - mybeg4 = 1; - printf ("************SKYEYE: startkerenl: sti now numinstr is %llu ********\n", state->NumInstrs); - } - /*if (pc==0xc001e4f4||pc==0xc001e4f8||pc==0xc001e4fc||pc==0xc001e500||pc==0xffff0004) { //MRA instr */ - if (pc == 0xc001e500) { //MRA instr - mybeg5 = 1; - printf ("************SKYEYE: MRA instr now numinstr is %llu ********\n", state->NumInstrs); - } - if (pc >= 0xc0000000 && mybeg2 == 0) { - mybeg2 = 1; - printf ("************SKYEYE: enable mmu&cache, now numinstr is %llu **************\n", state->NumInstrs); - SKYEYE_OUTREGS (stderr); - printf ("************************************************************************\n"); - } - //chy 2003-09-01 test after tlb-flush - if (pc == 0xc00261ac) { - //sleep(2); - mybeg3 = 1; - printf ("************SKYEYE: after tlb-flush numinstr is %llu ****************\n", state->NumInstrs); - } - if (mybeg3 == 1) { - SKYEYE_OUTREGS (skyeye_logfd); - SKYEYE_OUTMOREREGS (skyeye_logfd); - fprintf (skyeye_logfd, "\n"); - } -#endif - if (mybegin == 1) { - //fprintf(skyeye_logfd,"p %x,i %x,d %x,l %x,",pc,instr,decoded,loaded); - //chy for test 20050729 - /*if (state->NumInstrs>=3302294) { - if (pc==0x100c9d4 && instr==0xe1b0f00e){ - chy_debug(); - printf("*********************************************\n"); - printf("******SKYEYE N %llx :p %x,i %x\n SKYEYE******\n",state->NumInstrs,pc,instr); - printf("*********************************************\n"); - } - */ - if (skyeye_config.log.logon >= 1) - /* - fprintf (skyeye_logfd, - "N %llx :p %x,i %x,", - state->NumInstrs, pc, -#ifdef MODET - TFLAG ? instr & 0xffff : instr -#else - instr -#endif - ); - */ - fprintf(skyeye_logfd, "pc=0x%x,r3=0x%x\n", pc, state->Reg[3]); - if (skyeye_config.log.logon >= 2) - SKYEYE_OUTREGS (skyeye_logfd); - if (skyeye_config.log.logon >= 3) - SKYEYE_OUTMOREREGS - (skyeye_logfd); - //fprintf (skyeye_logfd, "\n"); - if (skyeye_config.log.length > 0) { - myinstrnum++; - if (myinstrnum >= - skyeye_config.log. - length) { - myinstrnum = 0; - fflush (skyeye_logfd); - fseek (skyeye_logfd, - 0L, SEEK_SET); - } - } - } - //SKYEYE_OUTREGS(skyeye_logfd); - //SKYEYE_OUTMOREREGS(skyeye_logfd); - } - } -#endif -#if 0 /* Enable this for a helpful bit of debugging when tracing is needed. */ - fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr); - if (instr == 0) - abort (); -#endif -#if 0 /* Enable this code to help track down stack alignment bugs. */ - { - static ARMword old_sp = -1; - - if (old_sp != state->Reg[13]) { - old_sp = state->Reg[13]; - fprintf (stderr, - "pc: %08x: SP set to %08x%s\n", - pc & ~1, old_sp, - (old_sp % 8) ? " [UNALIGNED!]" : ""); - } - } -#endif - /* Any exceptions ? */ - if (state->NresetSig == LOW) { - ARMul_Abort (state, ARMul_ResetV); - - /*added energy_prof statement by ksh in 2004-11-26 */ - //chy 2005-07-28 for standalone - //ARMul_do_energy(state,instr,pc); - break; - } - else if (!state->NfiqSig && !FFLAG) { - ARMul_Abort (state, ARMul_FIQV); - /*added energy_prof statement by ksh in 2004-11-26 */ - //chy 2005-07-28 for standalone - //ARMul_do_energy(state,instr,pc); - break; - } - else if (!state->NirqSig && !IFLAG) { - ARMul_Abort (state, ARMul_IRQV); - /*added energy_prof statement by ksh in 2004-11-26 */ - //chy 2005-07-28 for standalone - //ARMul_do_energy(state,instr,pc); - break; - } - -//teawater add for arm2x86 2005.04.26------------------------------------------- -#if 0 -// if (state->pc == 0xc011a868 || state->pc == 0xc011a86c) { - if (state->NumInstrs == 1671574 || state->NumInstrs == 1671573 || state->NumInstrs == 1671572 - || state->NumInstrs == 1671575) { - for (reg_index = 0; reg_index < 16; reg_index ++) { - printf("R%d:%x\t", reg_index, state->Reg[reg_index]); - } - printf("\n"); - } -#endif - if (state->tea_pc) { - int i; - - if (state->tea_reg_fd) { - fprintf (state->tea_reg_fd, "\n"); - for (i = 0; i < 15; i++) { - fprintf (state->tea_reg_fd, "%x,", - state->Reg[i]); - } - fprintf (state->tea_reg_fd, "%x,", pc); - state->Cpsr = ARMul_GetCPSR (state); - fprintf (state->tea_reg_fd, "%x\n", - state->Cpsr); - } - else { - printf ("\n"); - for (i = 0; i < 15; i++) { - printf ("%x,", state->Reg[i]); - } - printf ("%x,", pc); - state->Cpsr = ARMul_GetCPSR (state); - printf ("%x\n", state->Cpsr); - } - } -//AJ2D-------------------------------------------------------------------------- - - if (state->CallDebug > 0) { - instr = ARMul_Debug (state, pc, instr); - if (state->Emulate < ONCE) { - state->NextInstr = RESUME; - break; - } - if (state->Debug) { - fprintf (stderr, - "sim: At %08lx Instr %08lx Mode %02lx\n", - pc, instr, state->Mode); - (void) fgetc (stdin); - } - } - else if (state->Emulate < ONCE) { - state->NextInstr = RESUME; - break; - } - //io_do_cycle (state); - state->NumInstrs++; - #if 0 - if (state->NumInstrs % 10000000 == 0) { - printf("10 MIPS instr have been executed\n"); - } - #endif - -#ifdef MODET - /* Provide Thumb instruction decoding. If the processor is in Thumb - mode, then we can simply decode the Thumb instruction, and map it - to the corresponding ARM instruction (by directly loading the - instr variable, and letting the normal ARM simulator - execute). There are some caveats to ensure that the correct - pipelined PC value is used when executing Thumb code, and also for - dealing with the BL instruction. */ - if (TFLAG) { - ARMword new_instr; - - /* Check if in Thumb mode. */ - switch (ARMul_ThumbDecode(state, pc, instr, &new_instr)) { - case t_undefined: - /* This is a Thumb instruction. */ - ARMul_UndefInstr (state, instr); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - - case t_branch: - /* Already processed. */ - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - - case t_decoded: - /* ARM instruction available. */ - //printf("t decode %04lx -> %08lx\n", instr & 0xffff, new); - instr = new_instr; - /* So continue instruction decoding. */ - break; - default: - break; - } - } -#endif - - /* Check the condition codes. */ - if ((temp = TOPBITS (28)) == AL) { - /* Vile deed in the need for speed. */ - goto mainswitch; - } - - /* Check the condition code. */ - switch ((int) TOPBITS (28)) { - case AL: - temp = TRUE; - break; - case NV: - - /* shenoubang add for armv7 instr dmb 2012-3-11 */ - if (state->is_v7) { - if ((instr & 0x0fffff00) == 0x057ff000) { - switch((instr >> 4) & 0xf) { - case 4: /* dsb */ - case 5: /* dmb */ - case 6: /* isb */ - // TODO: do no implemented thes instr - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - } - } - /* dyf add for armv6 instruct CPS 2010.9.17 */ - if (state->is_v6) { - /* clrex do nothing here temporary */ - if (instr == 0xf57ff01f) { - //printf("clrex \n"); - ERROR_LOG(ARM11, "Instr = 0x%x, pc = 0x%x, clrex instr!!\n", instr, pc); -#if 0 - int i; - for(i = 0; i < 128; i++){ - state->exclusive_tag_array[i] = 0xffffffff; - } -#endif - /* shenoubang 2012-3-14 refer the dyncom_interpreter */ - state->exclusive_tag_array[0] = 0xFFFFFFFF; - state->exclusive_access_state = 0; - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - - if (BITS(20, 27) == 0x10) { - if (BIT(19)) { - if (BIT(8)) { - if (BIT(18)) - state->Cpsr |= 1<<8; - else - state->Cpsr &= ~(1<<8); - } - if (BIT(7)) { - if (BIT(18)) - state->Cpsr |= 1<<7; - else - state->Cpsr &= ~(1<<7); - ASSIGNINT (state->Cpsr & INTBITS); - } - if (BIT(6)) { - if (BIT(18)) - state->Cpsr |= 1<<6; - else - state->Cpsr &= ~(1<<6); - ASSIGNINT (state->Cpsr & INTBITS); - } - } - if (BIT(17)) { - state->Cpsr |= BITS(0, 4); - printf("skyeye test state->Mode\n"); - if (state->Mode != (state->Cpsr & MODEBITS)) { - state->Mode = - ARMul_SwitchMode (state, state->Mode, - state->Cpsr & MODEBITS); - - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - } - } - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - } - if (state->is_v5) { - if (BITS (25, 27) == 5) { /* BLX(1) */ - ARMword dest; - - state->Reg[14] = pc + 4; - - /* Force entry into Thumb mode. */ - dest = pc + 8 + 1; - if (BIT (23)) - dest += (NEGBRANCH + - (BIT (24) << 1)); - else - dest += POSBRANCH + - (BIT (24) << 1); - - WriteR15Branch (state, dest); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - else if ((instr & 0xFC70F000) == 0xF450F000) { - /* The PLD instruction. Ignored. */ - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - else if (((instr & 0xfe500f00) == 0xfc100100) - || ((instr & 0xfe500f00) == - 0xfc000100)) { - /* wldrw and wstrw are unconditional. */ - goto mainswitch; - } - else { - /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2. */ - ARMul_UndefInstr (state, instr); - } - } - temp = FALSE; - break; - case EQ: - temp = ZFLAG; - break; - case NE: - temp = !ZFLAG; - break; - case VS: - temp = VFLAG; - break; - case VC: - temp = !VFLAG; - break; - case MI: - temp = NFLAG; - break; - case PL: - temp = !NFLAG; - break; - case CS: - temp = CFLAG; - break; - case CC: - temp = !CFLAG; - break; - case HI: - temp = (CFLAG && !ZFLAG); - break; - case LS: - temp = (!CFLAG || ZFLAG); - break; - case GE: - temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); - break; - case LT: - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); - break; - case GT: - temp = ((!NFLAG && !VFLAG && !ZFLAG) - || (NFLAG && VFLAG && !ZFLAG)); - break; - case LE: - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) - || ZFLAG; - break; - } /* cc check */ - -//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... -#if 0 - /* Handle the Clock counter here. */ - if (state->is_XScale) { - ARMword cp14r0; - int ok; - - ok = state->CPRead[14] (state, 0, &cp14r0); - - if (ok && (cp14r0 & ARMul_CP14_R0_ENABLE)) { - unsigned int newcycles, nowtime = - ARMul_Time (state); - - newcycles = nowtime - state->LastTime; - state->LastTime = nowtime; - - if (cp14r0 & ARMul_CP14_R0_CCD) { - if (state->CP14R0_CCD == -1) - state->CP14R0_CCD = newcycles; - else - state->CP14R0_CCD += - newcycles; - - if (state->CP14R0_CCD >= 64) { - newcycles = 0; - - while (state->CP14R0_CCD >= - 64) - state->CP14R0_CCD -= - 64, - newcycles++; - - goto check_PMUintr; - } - } - else { - ARMword cp14r1; - int do_int = 0; - - state->CP14R0_CCD = -1; - check_PMUintr: - cp14r0 |= ARMul_CP14_R0_FLAG2; - (void) state->CPWrite[14] (state, 0, - cp14r0); - - ok = state->CPRead[14] (state, 1, - &cp14r1); - - /* Coded like this for portability. */ - while (ok && newcycles) { - if (cp14r1 == 0xffffffff) { - cp14r1 = 0; - do_int = 1; - } - else - cp14r1++; - - newcycles--; - } - - (void) state->CPWrite[14] (state, 1, - cp14r1); - - if (do_int - && (cp14r0 & - ARMul_CP14_R0_INTEN2)) { - ARMword temp; - - if (state-> - CPRead[13] (state, 8, - &temp) - && (temp & - ARMul_CP13_R8_PMUS)) - ARMul_Abort (state, - ARMul_FIQV); - else - ARMul_Abort (state, - ARMul_IRQV); - } - } - } - } - - /* Handle hardware instructions breakpoints here. */ - if (state->is_XScale) { - if ((pc | 3) == (read_cp15_reg (14, 0, 8) | 2) - || (pc | 3) == (read_cp15_reg (14, 0, 9) | 2)) { - if (XScale_debug_moe - (state, ARMul_CP14_R10_MOE_IB)) - ARMul_OSHandleSWI (state, - SWI_Breakpoint); - } - } -#endif - - /* Actual execution of instructions begins here. */ - /* If the condition codes don't match, stop here. */ - if (temp) { - mainswitch: - - if (state->is_XScale) { - if (BIT (20) == 0 && BITS (25, 27) == 0) { - if (BITS (4, 7) == 0xD) { - /* XScale Load Consecutive insn. */ - ARMword temp = - GetLS7RHS (state, - instr); - ARMword temp2 = - BIT (23) ? LHS + - temp : LHS - temp; - ARMword addr = - BIT (24) ? temp2 : - LHS; - - if (BIT (12)) - ARMul_UndefInstr - (state, - instr); - else if (addr & 7) - /* Alignment violation. */ - ARMul_Abort (state, - ARMul_DataAbortV); - else { - int wb = BIT (21) - || - (!BIT (24)); - - state->Reg[BITS - (12, 15)] = - ARMul_LoadWordN - (state, addr); - state->Reg[BITS - (12, - 15) + 1] = - ARMul_LoadWordN - (state, - addr + 4); - if (wb) - LSBase = temp2; - } - - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - else if (BITS (4, 7) == 0xF) { - /* XScale Store Consecutive insn. */ - ARMword temp = - GetLS7RHS (state, - instr); - ARMword temp2 = - BIT (23) ? LHS + - temp : LHS - temp; - ARMword addr = - BIT (24) ? temp2 : - LHS; - - if (BIT (12)) - ARMul_UndefInstr - (state, - instr); - else if (addr & 7) - /* Alignment violation. */ - ARMul_Abort (state, - ARMul_DataAbortV); - else { - ARMul_StoreWordN - (state, addr, - state-> - Reg[BITS - (12, - 15)]); - ARMul_StoreWordN - (state, - addr + 4, - state-> - Reg[BITS - (12, - 15) + - 1]); - - if (BIT (21) - || !BIT (24)) - LSBase = temp2; - } - - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - } - //chy 2003-09-03 TMRRC(iwmmxt.c) and MRA has the same decoded instr???? - //Now, I commit iwmmxt process, may be future, I will change it!!!! - //if (ARMul_HandleIwmmxt (state, instr)) - // _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - - /* shenoubang sbfx and ubfx instr 2012-3-16 */ - if (state->is_v6) { - unsigned int m, lsb, width, Rd, Rn, data; - Rd = Rn = lsb = width = data = m = 0; - - //printf("helloworld\n"); - if ((((int) BITS (21, 27)) == 0x3f) && (((int) BITS (4, 6)) == 0x5)) { - m = (unsigned)BITS(7, 11); - width = (unsigned)BITS(16, 20); - Rd = (unsigned)BITS(12, 15); - Rn = (unsigned)BITS(0, 3); - if ((Rd == 15) || (Rn == 15)) { - ARMul_UndefInstr (state, instr); - } - else if ((m + width) < 32) { - data = state->Reg[Rn]; - state->Reg[Rd] ^= state->Reg[Rd]; - state->Reg[Rd] = - ((ARMword)(data << (31 -(m + width))) >> ((31 - (m + width)) + (m))); - //SKYEYE_LOG_IN_CLR(RED, "UBFX: In %s, line = %d, Reg_src[%d] = 0x%x, Reg_d[%d] = 0x%x, m = %d, width = %d, Rd = %d, Rn = %d\n", - // __FUNCTION__, __LINE__, Rn, data, Rd, state->Reg[Rd], m, width + 1, Rd, Rn); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - } // ubfx instr - else if ((((int) BITS (21, 27)) == 0x3d) && (((int) BITS (4, 6)) == 0x5)) { - int tmp = 0; - Rd = BITS(12, 15); Rn = BITS(0, 3); - lsb = BITS(7, 11); width = BITS(16, 20); - if ((Rd == 15) || (Rn == 15)) { - ARMul_UndefInstr (state, instr); - } - else if ((lsb + width) < 32) { - state->Reg[Rd] ^= state->Reg[Rd]; - data = state->Reg[Rn]; - tmp = (data << (32 - (lsb + width + 1))); - state->Reg[Rd] = (tmp >> (32 - (lsb + width + 1))); - //SKYEYE_LOG_IN_CLR(RED, "sbfx: In %s, line = %d, pc = 0x%x, instr = 0x%x,Rd = 0x%x, \ - Rn = 0x%x, lsb = %d, width = %d, Rs[%d] = 0x%x, Rd[%d] = 0x%x\n", - // __func__, __LINE__, pc, instr, Rd, Rn, lsb, width + 1, Rn, state->Reg[Rn], Rd, state->Reg[Rd]); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - } // sbfx instr - else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) { - //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) - unsigned msb ,tmp_rn, tmp_rd, dst; - msb = tmp_rd = tmp_rn = dst = 0; - Rd = BITS(12, 15); Rn = BITS(0, 3); - lsb = BITS(7, 11); msb = BITS(16, 20); - if ((Rd == 15)) { - ARMul_UndefInstr (state, instr); - } - else if ((Rn == 15)) { - data = state->Reg[Rd]; - tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); - dst = ((data >> msb) << (msb - lsb)); - dst = (dst << lsb) | tmp_rd; - DEBUG_LOG(ARM11, "BFC instr: msb = %d, lsb = %d, Rd[%d] : 0x%x, dst = 0x%x\n", - msb, lsb, Rd, state->Reg[Rd], dst); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } // bfc instr - else if (((msb >= lsb) && (msb < 32))) { - data = state->Reg[Rn]; - tmp_rn = ((ARMword)(data << (31 - (msb - lsb))) >> (31 - (msb - lsb))); - data = state->Reg[Rd]; - tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); - dst = ((data >> msb) << (msb - lsb)) | tmp_rn; - dst = (dst << lsb) | tmp_rd; - DEBUG_LOG(ARM11, "BFI instr:msb = %d, lsb = %d, Rd[%d] : 0x%x, Rn[%d]: 0x%x, dst = 0x%x\n", - msb, lsb, Rd, state->Reg[Rd], Rn, state->Reg[Rn], dst); - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } // bfi instr - } - } - - switch ((int) BITS (20, 27)) { - /* Data Processing Register RHS Instructions. */ - - case 0x00: /* AND reg and MUL */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, down, post indexed. */ - SHDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 7) == 9) { - /* MUL */ - rhs = state->Reg[MULRHSReg]; - //if (MULLHSReg == MULDESTReg) { - if(0){ /* For armv6, the restriction is removed */ - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = 0; - } - else if (MULDESTReg != 15) - state->Reg[MULDESTReg] = - state-> - Reg[MULLHSReg] * rhs; - else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, - ARMul_MultTable[temp], - 0L); - } - else { - /* AND reg. */ - rhs = DPRegRHS; - dest = LHS & rhs; - WRITEDEST (dest); - } - break; - - case 0x01: /* ANDS reg and MULS */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to rest of decoding. */ -#endif - if (BITS (4, 7) == 9) { - /* MULS */ - rhs = state->Reg[MULRHSReg]; - - //if (MULLHSReg == MULDESTReg) { - if(0){ - printf("Something in %d line\n", __LINE__); - UNDEF_WARNING; - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = 0; - CLEARN; - SETZ; - } - else if (MULDESTReg != 15) { - dest = state->Reg[MULLHSReg] * - rhs; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } - else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, - ARMul_MultTable[temp], - 0L); - } - else { - /* ANDS reg. */ - rhs = DPSRegRHS; - dest = LHS & rhs; - WRITESDEST (dest); - } - break; - - case 0x02: /* EOR reg and MLA */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, down, post indexed. */ - SHDOWNWB (); - break; - } -#endif - if (BITS (4, 7) == 9) { /* MLA */ - rhs = state->Reg[MULRHSReg]; - #if 0 - if (MULLHSReg == MULDESTReg) { - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = - state->Reg[MULACCReg]; - } - else if (MULDESTReg != 15){ - #endif - if (MULDESTReg != 15){ - state->Reg[MULDESTReg] = - state-> - Reg[MULLHSReg] * rhs + - state->Reg[MULACCReg]; - } - else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, - ARMul_MultTable[temp], - 0L); - } - else { - rhs = DPRegRHS; - dest = LHS ^ rhs; - WRITEDEST (dest); - } - break; - - case 0x03: /* EORS reg and MLAS */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, down, post-indexed. */ - LHPOSTDOWN (); - /* Fall through to rest of the decoding. */ -#endif - if (BITS (4, 7) == 9) { - /* MLAS */ - rhs = state->Reg[MULRHSReg]; - //if (MULLHSReg == MULDESTReg) { - if (0) { - UNDEF_MULDestEQOp1; - dest = state->Reg[MULACCReg]; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } - else if (MULDESTReg != 15) { - dest = state->Reg[MULLHSReg] * - rhs + - state->Reg[MULACCReg]; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } - else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, - ARMul_MultTable[temp], - 0L); - } - else { - /* EORS Reg. */ - rhs = DPSRegRHS; - dest = LHS ^ rhs; - WRITESDEST (dest); - } - break; - - case 0x04: /* SUB reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, down, post indexed. */ - SHDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS - rhs; - WRITEDEST (dest); - break; - - case 0x05: /* SUBS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to the rest of the instruction decoding. */ -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs; - - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, - dest); - ARMul_SubOverflow (state, lhs, rhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x06: /* RSB reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, down, post indexed. */ - SHDOWNWB (); - break; - } -#endif - rhs = DPRegRHS; - dest = rhs - LHS; - WRITEDEST (dest); - break; - - case 0x07: /* RSBS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to remainder of instruction decoding. */ -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = rhs - lhs; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, - dest); - ARMul_SubOverflow (state, rhs, lhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x08: /* ADD reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, up, post indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif -#ifdef MODET - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32 = 64 */ - ARMul_Icycles (state, - Multiply64 (state, - instr, - LUNSIGNED, - LDEFAULT), - 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS + rhs; - WRITEDEST (dest); - break; - - case 0x09: /* ADDS reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ -#endif -#ifdef MODET - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - Multiply64 (state, - instr, - LUNSIGNED, - LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, - dest); - ARMul_AddOverflow (state, lhs, rhs, - dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0a: /* ADC reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, up, post-indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - MultiplyAdd64 (state, - instr, - LUNSIGNED, - LDEFAULT), - 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS + rhs + CFLAG; - WRITEDEST (dest); - break; - - case 0x0b: /* ADCS reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - MultiplyAdd64 (state, - instr, - LUNSIGNED, - LSCC), - 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs + CFLAG; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, - dest); - ARMul_AddOverflow (state, lhs, rhs, - dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0c: /* SBC reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, up post indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - Multiply64 (state, - instr, - LSIGNED, - LDEFAULT), - 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS - rhs - !CFLAG; - WRITEDEST (dest); - break; - - case 0x0d: /* SBCS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, up, post indexed. */ - LHPOSTUP (); - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - Multiply64 (state, - instr, - LSIGNED, - LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs - !CFLAG; - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, - dest); - ARMul_SubOverflow (state, lhs, rhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0e: /* RSC reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, up, post indexed. */ - SHUPWB (); - break; - } - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - MultiplyAdd64 (state, - instr, - LSIGNED, - LDEFAULT), - 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = rhs - LHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x0f: /* RSCS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, - MultiplyAdd64 (state, - instr, - LSIGNED, - LSCC), - 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = rhs - lhs - !CFLAG; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, - dest); - ARMul_SubOverflow (state, rhs, lhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x10: /* TST reg and MRS CPSR and SWP word. */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1) { - /* ElSegundo SMLAxy insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (8, 11)]; - ARMword Rn = - state-> - Reg[BITS (12, 15)]; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - op2 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - if (op2 & 0x8000) - op2 -= 65536; - op1 *= op2; - //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn); - if (AddOverflow - (op1, Rn, op1 + Rn)) - SETS; - state->Reg[BITS (16, 19)] = - op1 + Rn; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QADD insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (16, 19)]; - ARMword result = op1 + op2; - if (AddOverflow - (op1, op2, result)) { - result = POS (result) - ? 0x80000000 : - 0x7fffffff; - SETS; - } - state->Reg[BITS (12, 15)] = - result; - break; - } - } -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, down, pre indexed. */ - SHPREDOWN (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 11) == 9) { - /* SWP */ - UNDEF_SWPPC; - temp = LHS; - BUSUSEDINCPCS; -#ifndef MODE32 - if (VECTORACCESS (temp) - || ADDREXCEPT (temp)) { - INTERNALABORT (temp); - (void) ARMul_LoadWordN (state, - temp); - (void) ARMul_LoadWordN (state, - temp); - } - else -#endif - dest = ARMul_SwapWord (state, - temp, - state-> - Reg - [RHSReg]); - if (temp & 3) - DEST = ARMul_Align (state, - temp, - dest); - else - DEST = dest; - if (state->abortSig || state->Aborted) - TAKEABORT; - } - else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */ - UNDEF_MRSPC; - DEST = ECC | EINT | EMODE; - } - else { - UNDEF_Test; - } - break; - - case 0x11: /* TSTP reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, down, pre indexed. */ - LHPREDOWN (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* TSTP reg */ -#ifdef MODE32 - //chy 2006-02-15 if in user mode, can not set cpsr 0:23 - //from p165 of ARMARM book - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS & rhs; - SETR15PSR (temp); -#endif - } - else { - /* TST reg */ - rhs = DPSRegRHS; - dest = LHS & rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x12: /* TEQ reg and MSR reg to CPSR (ARM6). */ - - if (state->is_v5) { - if (BITS (4, 7) == 3) { - /* BLX(2) */ - ARMword temp; - - if (TFLAG) - temp = (pc + 2) | 1; - else - temp = pc + 4; - - WriteR15Branch (state, - state-> - Reg[RHSReg]); - state->Reg[14] = temp; - break; - } - } - - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1 - && (BIT (5) == 0 - || BITS (12, 15) == 0)) { - /* ElSegundo SMLAWy/SMULWy insn. */ - unsigned long long op1 = - state-> - Reg[BITS (0, 3)]; - unsigned long long op2 = - state-> - Reg[BITS (8, 11)]; - unsigned long long result; - - if (BIT (6)) - op2 >>= 16; - if (op1 & 0x80000000) - op1 -= 1ULL << 32; - op2 &= 0xFFFF; - if (op2 & 0x8000) - op2 -= 65536; - result = (op1 * op2) >> 16; - - if (BIT (5) == 0) { - ARMword Rn = - state-> - Reg[BITS - (12, 15)]; - - if (AddOverflow - (result, Rn, - result + Rn)) - SETS; - result += Rn; - } - state->Reg[BITS (16, 19)] = - result; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QSUB insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (16, 19)]; - ARMword result = op1 - op2; - - if (SubOverflow - (op1, op2, result)) { - result = POS (result) - ? 0x80000000 : - 0x7fffffff; - SETS; - } - - state->Reg[BITS (12, 15)] = - result; - break; - } - } -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, down, pre indexed. */ - SHPREDOWNWB (); - break; - } - if (BITS (4, 27) == 0x12FFF1) { - /* BX */ - WriteR15Branch (state, - state->Reg[RHSReg]); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (state->is_v5) { - if (BITS (4, 7) == 0x7) { - ARMword value; - extern int - SWI_vector_installed; - - /* Hardware is allowed to optionally override this - instruction and treat it as a breakpoint. Since - this is a simulator not hardware, we take the position - that if a SWI vector was not installed, then an Abort - vector was probably not installed either, and so - normally this instruction would be ignored, even if an - Abort is generated. This is a bad thing, since GDB - uses this instruction for its breakpoints (at least in - Thumb mode it does). So intercept the instruction here - and generate a breakpoint SWI instead. */ - if (!SWI_vector_installed) - ARMul_OSHandleSWI - (state, - SWI_Breakpoint); - else { - /* BKPT - normally this will cause an abort, but on the - XScale we must check the DCSR. */ - XScale_set_fsr_far - (state, - ARMul_CP15_R5_MMU_EXCPT, - pc); - //if (!XScale_debug_moe - // (state, - // ARMul_CP14_R10_MOE_BT)) - // break; // Disabled /bunnei - } - - /* Force the next instruction to be refetched. */ - state->NextInstr = RESUME; - break; - } - } - if (DESTReg == 15) { - /* MSR reg to CPSR. */ - UNDEF_MSRPC; - temp = DPRegRHS; -#ifdef MODET - /* Don't allow TBIT to be set by MSR. */ - temp &= ~TBIT; -#endif - ARMul_FixCPSR (state, instr, temp); - } - else - UNDEF_Test; - - break; - - case 0x13: /* TEQP reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, down, pre indexed. */ - LHPREDOWNWB (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* TEQP reg */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS ^ rhs; - SETR15PSR (temp); -#endif - } - else { - /* TEQ Reg. */ - rhs = DPSRegRHS; - dest = LHS ^ rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x14: /* CMP reg and MRS SPSR and SWP byte. */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1) { - /* ElSegundo SMLALxy insn. */ - unsigned long long op1 = - state-> - Reg[BITS (0, 3)]; - unsigned long long op2 = - state-> - Reg[BITS (8, 11)]; - unsigned long long dest; - unsigned long long result; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - op2 &= 0xFFFF; - if (op2 & 0x8000) - op2 -= 65536; - - dest = (unsigned long long) - state-> - Reg[BITS (16, 19)] << - 32; - dest |= state-> - Reg[BITS (12, 15)]; - dest += op1 * op2; - state->Reg[BITS (12, 15)] = - dest; - state->Reg[BITS (16, 19)] = - dest >> 32; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QDADD insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (16, 19)]; - ARMword op2d = op2 + op2; - ARMword result; - - if (AddOverflow - (op2, op2, op2d)) { - SETS; - op2d = POS (op2d) ? - 0x80000000 : - 0x7fffffff; - } - - result = op1 + op2d; - if (AddOverflow - (op1, op2d, result)) { - SETS; - result = POS (result) - ? 0x80000000 : - 0x7fffffff; - } - - state->Reg[BITS (12, 15)] = - result; - break; - } - } -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, down, pre indexed. */ - SHPREDOWN (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 11) == 9) { - /* SWP */ - UNDEF_SWPPC; - temp = LHS; - BUSUSEDINCPCS; -#ifndef MODE32 - if (VECTORACCESS (temp) - || ADDREXCEPT (temp)) { - INTERNALABORT (temp); - (void) ARMul_LoadByte (state, - temp); - (void) ARMul_LoadByte (state, - temp); - } - else -#endif - DEST = ARMul_SwapByte (state, - temp, - state-> - Reg - [RHSReg]); - if (state->abortSig || state->Aborted) - TAKEABORT; - } - else if ((BITS (0, 11) == 0) - && (LHSReg == 15)) { - /* MRS SPSR */ - UNDEF_MRSPC; - DEST = GETSPSR (state->Bank); - } - else - UNDEF_Test; - - break; - - case 0x15: /* CMPP reg. */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, down, pre indexed. */ - LHPREDOWN (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* CMPP reg. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS - rhs; - SETR15PSR (temp); -#endif - } - else { - /* CMP reg. */ - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs; - ARMul_NegZero (state, dest); - if ((lhs >= rhs) - || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, - rhs, dest); - ARMul_SubOverflow (state, lhs, - rhs, dest); - } - else { - CLEARC; - CLEARV; - } - } - break; - - case 0x16: /* CMN reg and MSR reg to SPSR */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1 - && BITS (12, 15) == 0) { - /* ElSegundo SMULxy insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (8, 11)]; - ARMword Rn = - state-> - Reg[BITS (12, 15)]; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - op2 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - if (op2 & 0x8000) - op2 -= 65536; - - state->Reg[BITS (16, 19)] = - op1 * op2; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QDSUB insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - ARMword op2 = - state-> - Reg[BITS (16, 19)]; - ARMword op2d = op2 + op2; - ARMword result; - - if (AddOverflow - (op2, op2, op2d)) { - SETS; - op2d = POS (op2d) ? - 0x80000000 : - 0x7fffffff; - } - - result = op1 - op2d; - if (SubOverflow - (op1, op2d, result)) { - SETS; - result = POS (result) - ? 0x80000000 : - 0x7fffffff; - } - - state->Reg[BITS (12, 15)] = - result; - break; - } - } - - if (state->is_v5) { - if (BITS (4, 11) == 0xF1 - && BITS (16, 19) == 0xF) { - /* ARM5 CLZ insn. */ - ARMword op1 = - state-> - Reg[BITS (0, 3)]; - int result = 32; - - if (op1) - for (result = 0; - (op1 & - 0x80000000) == - 0; op1 <<= 1) - result++; - state->Reg[BITS (12, 15)] = - result; - break; - } - } - -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, down, pre indexed. */ - SHPREDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (DESTReg == 15) { - /* MSR */ - UNDEF_MSRPC; - ARMul_FixSPSR (state, instr, - DPRegRHS); - } - else { - UNDEF_Test; - } - break; - - case 0x17: /* CMNP reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, down, pre indexed. */ - LHPREDOWNWB (); - /* Continue with remaining instruction decoding. */ -#endif - if (DESTReg == 15) { -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS + rhs; - SETR15PSR (temp); -#endif - break; - } - else { - /* CMN reg. */ - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, - rhs, dest); - ARMul_AddOverflow (state, lhs, - rhs, dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - } - break; - - case 0x18: /* ORR reg */ -#ifdef MODET - /* dyf add armv6 instr strex 2010.9.17 */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) - if (handle_v6_insn (state, instr)) - break; - } - - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, up, pre indexed. */ - SHPREUP (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS | rhs; - WRITEDEST (dest); - break; - - case 0x19: /* ORRS reg */ -#ifdef MODET - /* dyf add armv6 instr ldrex */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) { - if (handle_v6_insn (state, instr)) - break; - } - } - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, up, pre indexed. */ - LHPREUP (); - /* Continue with remaining instruction decoding. */ -#endif - rhs = DPSRegRHS; - dest = LHS | rhs; - WRITESDEST (dest); - break; - - case 0x1a: /* MOV reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, up, pre indexed. */ - SHPREUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - dest = DPRegRHS; - WRITEDEST (dest); - break; - - case 0x1b: /* MOVS reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, up, pre indexed. */ - LHPREUPWB (); - /* Continue with remaining instruction decoding. */ -#endif - dest = DPSRegRHS; - WRITESDEST (dest); - break; - - case 0x1c: /* BIC reg */ -#ifdef MODET - /* dyf add for STREXB */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) { - if (handle_v6_insn (state, instr)) - break; - } - } - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, up, pre indexed. */ - SHPREUP (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - else if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS & ~rhs; - WRITEDEST (dest); - break; - - case 0x1d: /* BICS reg */ -#ifdef MODET - /* ladsh P=1 U=1 W=0 L=1 S=1 H=1 */ - if (BITS(4, 7) == 0xF) { - temp = LHS + GetLS7RHS (state, instr); - LoadHalfWord (state, instr, temp, LSIGNED); - break; - - } - if (BITS (4, 7) == 0xb) { - /* LDRH immediate offset, no write-back, up, pre indexed. */ - temp = LHS + GetLS7RHS (state, instr); - LoadHalfWord (state, instr, temp, LUNSIGNED); - break; - } - if (BITS (4, 7) == 0xd) { - // alex-ykl fix: 2011-07-20 missing ldrsb instruction - temp = LHS + GetLS7RHS (state, instr); - LoadByte (state, instr, temp, LSIGNED); - break; - } - - /* Continue with instruction decoding. */ - /*if ((BITS (4, 7) & 0x9) == 0x9) */ - if ((BITS (4, 7)) == 0x9) { - /* ldrexb */ - if (state->is_v6) { - if (handle_v6_insn (state, instr)) - break; - } - /* LDR immediate offset, no write-back, up, pre indexed. */ - LHPREUP (); - - } - -#endif - rhs = DPSRegRHS; - dest = LHS & ~rhs; - WRITESDEST (dest); - break; - - case 0x1e: /* MVN reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, up, pre indexed. */ - SHPREUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - dest = ~DPRegRHS; - WRITEDEST (dest); - break; - - case 0x1f: /* MVNS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, up, pre indexed. */ - LHPREUPWB (); - /* Continue instruction decoding. */ -#endif - dest = ~DPSRegRHS; - WRITESDEST (dest); - break; - - - /* Data Processing Immediate RHS Instructions. */ - - case 0x20: /* AND immed */ - dest = LHS & DPImmRHS; - WRITEDEST (dest); - break; - - case 0x21: /* ANDS immed */ - DPSImmRHS; - dest = LHS & rhs; - WRITESDEST (dest); - break; - - case 0x22: /* EOR immed */ - dest = LHS ^ DPImmRHS; - WRITEDEST (dest); - break; - - case 0x23: /* EORS immed */ - DPSImmRHS; - dest = LHS ^ rhs; - WRITESDEST (dest); - break; - - case 0x24: /* SUB immed */ - dest = LHS - DPImmRHS; - WRITEDEST (dest); - break; - - case 0x25: /* SUBS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs; - - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, - dest); - ARMul_SubOverflow (state, lhs, rhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x26: /* RSB immed */ - dest = DPImmRHS - LHS; - WRITEDEST (dest); - break; - - case 0x27: /* RSBS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = rhs - lhs; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, - dest); - ARMul_SubOverflow (state, rhs, lhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x28: /* ADD immed */ - dest = LHS + DPImmRHS; - WRITEDEST (dest); - break; - - case 0x29: /* ADDS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, - dest); - ARMul_AddOverflow (state, lhs, rhs, - dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2a: /* ADC immed */ - dest = LHS + DPImmRHS + CFLAG; - WRITEDEST (dest); - break; - - case 0x2b: /* ADCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs + CFLAG; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, - dest); - ARMul_AddOverflow (state, lhs, rhs, - dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2c: /* SBC immed */ - dest = LHS - DPImmRHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x2d: /* SBCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs - !CFLAG; - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, - dest); - ARMul_SubOverflow (state, lhs, rhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2e: /* RSC immed */ - dest = DPImmRHS - LHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x2f: /* RSCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = rhs - lhs - !CFLAG; - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, - dest); - ARMul_SubOverflow (state, rhs, lhs, - dest); - } - else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x30: /* TST immed */ - /* shenoubang 2012-3-14*/ - if (state->is_v6) { /* movw, ARMV6, ARMv7 */ - dest ^= dest; - dest = BITS(16, 19); - dest = ((dest<<12) | BITS(0, 11)); - WRITEDEST(dest); - //SKYEYE_DBG("In %s, line = %d, pc = 0x%x, instr = 0x%x, R[0:11]: 0x%x, R[16:19]: 0x%x, R[%d]:0x%x\n", - // __func__, __LINE__, pc, instr, BITS(0, 11), BITS(16, 19), DESTReg, state->Reg[DESTReg]); - break; - } - else { - UNDEF_Test; - break; - } - - case 0x31: /* TSTP immed */ - if (DESTReg == 15) { - /* TSTP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS & DPImmRHS; - SETR15PSR (temp); -#endif - } - else { - /* TST immed. */ - DPSImmRHS; - dest = LHS & rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x32: /* TEQ immed and MSR immed to CPSR */ - if (DESTReg == 15) - /* MSR immed to CPSR. */ - ARMul_FixCPSR (state, instr, - DPImmRHS); - else - UNDEF_Test; - break; - - case 0x33: /* TEQP immed */ - if (DESTReg == 15) { - /* TEQP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS ^ DPImmRHS; - SETR15PSR (temp); -#endif - } - else { - DPSImmRHS; /* TEQ immed */ - dest = LHS ^ rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x34: /* CMP immed */ - UNDEF_Test; - break; - - case 0x35: /* CMPP immed */ - if (DESTReg == 15) { - /* CMPP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS - DPImmRHS; - SETR15PSR (temp); -#endif - break; - } - else { - /* CMP immed. */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs; - ARMul_NegZero (state, dest); - - if ((lhs >= rhs) - || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, - rhs, dest); - ARMul_SubOverflow (state, lhs, - rhs, dest); - } - else { - CLEARC; - CLEARV; - } - } - break; - - case 0x36: /* CMN immed and MSR immed to SPSR */ - if (DESTReg == 15) - ARMul_FixSPSR (state, instr, - DPImmRHS); - else - UNDEF_Test; - break; - - case 0x37: /* CMNP immed. */ - if (DESTReg == 15) { - /* CMNP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS + DPImmRHS; - SETR15PSR (temp); -#endif - break; - } - else { - /* CMN immed. */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, - rhs, dest); - ARMul_AddOverflow (state, lhs, - rhs, dest); - } - else { - CLEARN; - CLEARC; - CLEARV; - } - } - break; - - case 0x38: /* ORR immed. */ - dest = LHS | DPImmRHS; - WRITEDEST (dest); - break; - - case 0x39: /* ORRS immed. */ - DPSImmRHS; - dest = LHS | rhs; - WRITESDEST (dest); - break; - - case 0x3a: /* MOV immed. */ - dest = DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3b: /* MOVS immed. */ - DPSImmRHS; - WRITESDEST (rhs); - break; - - case 0x3c: /* BIC immed. */ - dest = LHS & ~DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3d: /* BICS immed. */ - DPSImmRHS; - dest = LHS & ~rhs; - WRITESDEST (dest); - break; - - case 0x3e: /* MVN immed. */ - dest = ~DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3f: /* MVNS immed. */ - DPSImmRHS; - WRITESDEST (~rhs); - break; - - - /* Single Data Transfer Immediate RHS Instructions. */ - - case 0x40: /* Store Word, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x41: /* Load Word, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (LoadWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x42: /* Store Word, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - temp = lhs - LSImmRHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x43: /* Load Word, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x44: /* Store Byte, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x45: /* Load Byte, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs - LSImmRHS; - break; - - case 0x46: /* Store Byte, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x47: /* Load Byte, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs - LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x48: /* Store Word, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x49: /* Load Word, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (LoadWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4a: /* Store Word, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4b: /* Load Word, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4c: /* Store Byte, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4d: /* Load Byte, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4e: /* Store Byte, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4f: /* Load Byte, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs + LSImmRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - - case 0x50: /* Store Word, No WriteBack, Pre Dec, Immed. */ - (void) StoreWord (state, instr, - LHS - LSImmRHS); - break; - - case 0x51: /* Load Word, No WriteBack, Pre Dec, Immed. */ - (void) LoadWord (state, instr, - LHS - LSImmRHS); - break; - - case 0x52: /* Store Word, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x53: /* Load Word, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x54: /* Store Byte, No WriteBack, Pre Dec, Immed. */ - (void) StoreByte (state, instr, - LHS - LSImmRHS); - break; - - case 0x55: /* Load Byte, No WriteBack, Pre Dec, Immed. */ - (void) LoadByte (state, instr, LHS - LSImmRHS, - LUNSIGNED); - break; - - case 0x56: /* Store Byte, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x57: /* Load Byte, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - case 0x58: /* Store Word, No WriteBack, Pre Inc, Immed. */ - (void) StoreWord (state, instr, - LHS + LSImmRHS); - break; - - case 0x59: /* Load Word, No WriteBack, Pre Inc, Immed. */ - (void) LoadWord (state, instr, - LHS + LSImmRHS); - break; - - case 0x5a: /* Store Word, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x5b: /* Load Word, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x5c: /* Store Byte, No WriteBack, Pre Inc, Immed. */ - (void) StoreByte (state, instr, - LHS + LSImmRHS); - break; - - case 0x5d: /* Load Byte, No WriteBack, Pre Inc, Immed. */ - (void) LoadByte (state, instr, LHS + LSImmRHS, - LUNSIGNED); - break; - - case 0x5e: /* Store Byte, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x5f: /* Load Byte, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - - /* Single Data Transfer Register RHS Instructions. */ - - case 0x60: /* Store Word, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - break; - - case 0x61: /* Load Word, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - break; - - case 0x62: /* Store Word, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x63: /* Load Word, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x64: /* Store Byte, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - break; - - case 0x65: /* Load Byte, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - break; - - case 0x66: /* Store Byte, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x67: /* Load Byte, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - break; - - case 0x69: /* Load Word, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - break; - - case 0x6a: /* Store Word, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6b: /* Load Word, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6c: /* Store Byte, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - break; - - case 0x6d: /* Load Byte, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - break; - - case 0x6e: /* Store Byte, WriteBack, Post Inc, Reg. */ -#if 0 - if (state->is_v6) { - int Rm = 0; - /* utxb */ - if (BITS(15, 19) == 0xf && BITS(4, 7) == 0x7) { - - Rm = (RHS >> (8 * BITS(10, 11))) & 0xff; - DEST = Rm; - } - - } -#endif - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6f: /* Load Byte, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - state->NtransSig = - (state->Mode & 3) ? HIGH : LOW; - break; - - - case 0x70: /* Store Word, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreWord (state, instr, - LHS - LSRegRHS); - break; - - case 0x71: /* Load Word, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadWord (state, instr, - LHS - LSRegRHS); - break; - - case 0x72: /* Store Word, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x73: /* Load Word, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x74: /* Store Byte, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreByte (state, instr, - LHS - LSRegRHS); - break; - - case 0x75: /* Load Byte, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadByte (state, instr, LHS - LSRegRHS, - LUNSIGNED); - break; - - case 0x76: /* Store Byte, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x77: /* Load Byte, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - case 0x78: /* Store Word, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreWord (state, instr, - LHS + LSRegRHS); - break; - - case 0x79: /* Load Word, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadWord (state, instr, - LHS + LSRegRHS); - break; - - case 0x7a: /* Store Word, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x7b: /* Load Word, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x7c: /* Store Byte, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreByte (state, instr, - LHS + LSRegRHS); - break; - - case 0x7d: /* Load Byte, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadByte (state, instr, LHS + LSRegRHS, - LUNSIGNED); - break; - - case 0x7e: /* Store Byte, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - /* Check for the special breakpoint opcode. - This value should correspond to the value defined - as ARM_BE_BREAKPOINT in gdb/arm/tm-arm.h. */ - if (BITS (0, 19) == 0xfdefe) { - if (!ARMul_OSHandleSWI - (state, SWI_Breakpoint)) - ARMul_Abort (state, - ARMul_SWIV); - } - else - ARMul_UndefInstr (state, - instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - - /* Multiple Data Transfer Instructions. */ - - case 0x80: /* Store, No WriteBack, Post Dec. */ - STOREMULT (instr, LSBase - LSMNumRegs + 4L, - 0L); - break; - - case 0x81: /* Load, No WriteBack, Post Dec. */ - LOADMULT (instr, LSBase - LSMNumRegs + 4L, - 0L); - break; - - case 0x82: /* Store, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - STOREMULT (instr, temp + 4L, temp); - break; - - case 0x83: /* Load, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - LOADMULT (instr, temp + 4L, temp); - break; - - case 0x84: /* Store, Flags, No WriteBack, Post Dec. */ - STORESMULT (instr, LSBase - LSMNumRegs + 4L, - 0L); - break; - - case 0x85: /* Load, Flags, No WriteBack, Post Dec. */ - LOADSMULT (instr, LSBase - LSMNumRegs + 4L, - 0L); - break; - - case 0x86: /* Store, Flags, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - STORESMULT (instr, temp + 4L, temp); - break; - - case 0x87: /* Load, Flags, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - LOADSMULT (instr, temp + 4L, temp); - break; - - case 0x88: /* Store, No WriteBack, Post Inc. */ - STOREMULT (instr, LSBase, 0L); - break; - - case 0x89: /* Load, No WriteBack, Post Inc. */ - LOADMULT (instr, LSBase, 0L); - break; - - case 0x8a: /* Store, WriteBack, Post Inc. */ - temp = LSBase; - STOREMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8b: /* Load, WriteBack, Post Inc. */ - temp = LSBase; - LOADMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8c: /* Store, Flags, No WriteBack, Post Inc. */ - STORESMULT (instr, LSBase, 0L); - break; - - case 0x8d: /* Load, Flags, No WriteBack, Post Inc. */ - LOADSMULT (instr, LSBase, 0L); - break; - - case 0x8e: /* Store, Flags, WriteBack, Post Inc. */ - temp = LSBase; - STORESMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8f: /* Load, Flags, WriteBack, Post Inc. */ - temp = LSBase; - LOADSMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x90: /* Store, No WriteBack, Pre Dec. */ - STOREMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x91: /* Load, No WriteBack, Pre Dec. */ - LOADMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x92: /* Store, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - STOREMULT (instr, temp, temp); - break; - - case 0x93: /* Load, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - LOADMULT (instr, temp, temp); - break; - - case 0x94: /* Store, Flags, No WriteBack, Pre Dec. */ - STORESMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x95: /* Load, Flags, No WriteBack, Pre Dec. */ - LOADSMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x96: /* Store, Flags, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - STORESMULT (instr, temp, temp); - break; - - case 0x97: /* Load, Flags, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - LOADSMULT (instr, temp, temp); - break; - - case 0x98: /* Store, No WriteBack, Pre Inc. */ - STOREMULT (instr, LSBase + 4L, 0L); - break; - - case 0x99: /* Load, No WriteBack, Pre Inc. */ - LOADMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9a: /* Store, WriteBack, Pre Inc. */ - temp = LSBase; - STOREMULT (instr, temp + 4L, - temp + LSMNumRegs); - break; - - case 0x9b: /* Load, WriteBack, Pre Inc. */ - temp = LSBase; - LOADMULT (instr, temp + 4L, - temp + LSMNumRegs); - break; - - case 0x9c: /* Store, Flags, No WriteBack, Pre Inc. */ - STORESMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9d: /* Load, Flags, No WriteBack, Pre Inc. */ - LOADSMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9e: /* Store, Flags, WriteBack, Pre Inc. */ - temp = LSBase; - STORESMULT (instr, temp + 4L, - temp + LSMNumRegs); - break; - - case 0x9f: /* Load, Flags, WriteBack, Pre Inc. */ - temp = LSBase; - LOADSMULT (instr, temp + 4L, - temp + LSMNumRegs); - break; - - - /* Branch forward. */ - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - state->Reg[15] = pc + 8 + POSBRANCH; - FLUSHPIPE; - break; - - - /* Branch backward. */ - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - state->Reg[15] = pc + 8 + NEGBRANCH; - FLUSHPIPE; - break; - - - /* Branch and Link forward. */ - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - /* Put PC into Link. */ -#ifdef MODE32 - state->Reg[14] = pc + 4; -#else - state->Reg[14] = - (pc + 4) | ECC | ER15INT | EMODE; -#endif - state->Reg[15] = pc + 8 + POSBRANCH; - FLUSHPIPE; - break; - - - /* Branch and Link backward. */ - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - /* Put PC into Link. */ -#ifdef MODE32 - state->Reg[14] = pc + 4; -#else - state->Reg[14] = - (pc + 4) | ECC | ER15INT | EMODE; -#endif - state->Reg[15] = pc + 8 + NEGBRANCH; - FLUSHPIPE; - break; - - - /* Co-Processor Data Transfers. */ - case 0xc4: - if (state->is_v5) { - /* Reading from R15 is UNPREDICTABLE. */ - if (BITS (12, 15) == 15 - || BITS (16, 19) == 15) - ARMul_UndefInstr (state, - instr); - /* Is access to coprocessor 0 allowed ? */ - else if (!CP_ACCESS_ALLOWED - (state, CPNum)) - ARMul_UndefInstr (state, - instr); - /* Special treatment for XScale coprocessors. */ - else if (state->is_XScale) { - /* Only opcode 0 is supported. */ - if (BITS (4, 7) != 0x00) - ARMul_UndefInstr - (state, - instr); - /* Only coporcessor 0 is supported. */ - else if (CPNum != 0x00) - ARMul_UndefInstr - (state, - instr); - /* Only accumulator 0 is supported. */ - else if (BITS (0, 3) != 0x00) - ARMul_UndefInstr - (state, - instr); - else { - /* XScale MAR insn. Move two registers into accumulator. */ - state->Accumulator = - state-> - Reg[BITS - (12, 15)]; - state->Accumulator += - (ARMdword) - state-> - Reg[BITS - (16, - 19)] << - 32; - } - } - else - { - /* MCRR, ARMv5TE and up */ - ARMul_MCRR (state, instr, DEST, state->Reg[LHSReg]); - break; - } - } - /* Drop through. */ - - case 0xc0: /* Store , No WriteBack , Post Dec. */ - ARMul_STC (state, instr, LHS); - break; - - case 0xc5: - if (state->is_v5) { - /* Writes to R15 are UNPREDICATABLE. */ - if (DESTReg == 15 || LHSReg == 15) - ARMul_UndefInstr (state, - instr); - /* Is access to the coprocessor allowed ? */ - else if (!CP_ACCESS_ALLOWED - (state, CPNum)) - ARMul_UndefInstr (state, - instr); - /* Special handling for XScale coprcoessors. */ - else if (state->is_XScale) { - /* Only opcode 0 is supported. */ - if (BITS (4, 7) != 0x00) - ARMul_UndefInstr - (state, - instr); - /* Only coprocessor 0 is supported. */ - else if (CPNum != 0x00) - ARMul_UndefInstr - (state, - instr); - /* Only accumulator 0 is supported. */ - else if (BITS (0, 3) != 0x00) - ARMul_UndefInstr - (state, - instr); - else { - /* XScale MRA insn. Move accumulator into two registers. */ - ARMword t1 = - (state-> - Accumulator - >> 32) & 255; - - if (t1 & 128) - t1 -= 256; - - state->Reg[BITS - (12, 15)] = - state-> - Accumulator; - state->Reg[BITS - (16, 19)] = - t1; - break; - } - } - else - { - /* MRRC, ARMv5TE and up */ - ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); - break; - } - } - /* Drop through. */ - - case 0xc1: /* Load , No WriteBack , Post Dec. */ - ARMul_LDC (state, instr, LHS); - break; - - case 0xc2: - case 0xc6: /* Store , WriteBack , Post Dec. */ - lhs = LHS; - state->Base = lhs - LSCOff; - ARMul_STC (state, instr, lhs); - break; - - case 0xc3: - case 0xc7: /* Load , WriteBack , Post Dec. */ - lhs = LHS; - state->Base = lhs - LSCOff; - ARMul_LDC (state, instr, lhs); - break; - - case 0xc8: - case 0xcc: /* Store , No WriteBack , Post Inc. */ - ARMul_STC (state, instr, LHS); - break; - - case 0xc9: - case 0xcd: /* Load , No WriteBack , Post Inc. */ - ARMul_LDC (state, instr, LHS); - break; - - case 0xca: - case 0xce: /* Store , WriteBack , Post Inc. */ - lhs = LHS; - state->Base = lhs + LSCOff; - ARMul_STC (state, instr, LHS); - break; - - case 0xcb: - case 0xcf: /* Load , WriteBack , Post Inc. */ - lhs = LHS; - state->Base = lhs + LSCOff; - ARMul_LDC (state, instr, LHS); - break; - - case 0xd0: - case 0xd4: /* Store , No WriteBack , Pre Dec. */ - ARMul_STC (state, instr, LHS - LSCOff); - break; - - case 0xd1: - case 0xd5: /* Load , No WriteBack , Pre Dec. */ - ARMul_LDC (state, instr, LHS - LSCOff); - break; - - case 0xd2: - case 0xd6: /* Store , WriteBack , Pre Dec. */ - lhs = LHS - LSCOff; - state->Base = lhs; - ARMul_STC (state, instr, lhs); - break; - - case 0xd3: - case 0xd7: /* Load , WriteBack , Pre Dec. */ - lhs = LHS - LSCOff; - state->Base = lhs; - ARMul_LDC (state, instr, lhs); - break; - - case 0xd8: - case 0xdc: /* Store , No WriteBack , Pre Inc. */ - ARMul_STC (state, instr, LHS + LSCOff); - break; - - case 0xd9: - case 0xdd: /* Load , No WriteBack , Pre Inc. */ - ARMul_LDC (state, instr, LHS + LSCOff); - break; - - case 0xda: - case 0xde: /* Store , WriteBack , Pre Inc. */ - lhs = LHS + LSCOff; - state->Base = lhs; - ARMul_STC (state, instr, lhs); - break; - - case 0xdb: - case 0xdf: /* Load , WriteBack , Pre Inc. */ - lhs = LHS + LSCOff; - state->Base = lhs; - ARMul_LDC (state, instr, lhs); - break; - - - /* Co-Processor Register Transfers (MCR) and Data Ops. */ - - case 0xe2: - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - ARMul_UndefInstr (state, instr); - break; - } - if (state->is_XScale) - switch (BITS (18, 19)) { - case 0x0: - if (BITS (4, 11) == 1 - && BITS (16, 17) == 0) { - /* XScale MIA instruction. Signed multiplication of - two 32 bit values and addition to 40 bit accumulator. */ - long long Rm = - state-> - Reg - [MULLHSReg]; - long long Rs = - state-> - Reg - [MULACCReg]; - - if (Rm & (1 << 31)) - Rm -= 1ULL << - 32; - if (Rs & (1 << 31)) - Rs -= 1ULL << - 32; - state->Accumulator += - Rm * Rs; - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - break; - - case 0x2: - if (BITS (4, 11) == 1 - && BITS (16, 17) == 0) { - /* XScale MIAPH instruction. */ - ARMword t1 = - state-> - Reg[MULLHSReg] - >> 16; - ARMword t2 = - state-> - Reg[MULACCReg] - >> 16; - ARMword t3 = - state-> - Reg[MULLHSReg] - & 0xffff; - ARMword t4 = - state-> - Reg[MULACCReg] - & 0xffff; - long long t5; - - if (t1 & (1 << 15)) - t1 -= 1 << 16; - if (t2 & (1 << 15)) - t2 -= 1 << 16; - if (t3 & (1 << 15)) - t3 -= 1 << 16; - if (t4 & (1 << 15)) - t4 -= 1 << 16; - t1 *= t2; - t5 = t1; - if (t5 & (1 << 31)) - t5 -= 1ULL << - 32; - state->Accumulator += - t5; - t3 *= t4; - t5 = t3; - if (t5 & (1 << 31)) - t5 -= 1ULL << - 32; - state->Accumulator += - t5; - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - break; - - case 0x3: - if (BITS (4, 11) == 1) { - /* XScale MIAxy instruction. */ - ARMword t1; - ARMword t2; - long long t5; - - if (BIT (17)) - t1 = state-> - Reg - [MULLHSReg] - >> 16; - else - t1 = state-> - Reg - [MULLHSReg] - & - 0xffff; - - if (BIT (16)) - t2 = state-> - Reg - [MULACCReg] - >> 16; - else - t2 = state-> - Reg - [MULACCReg] - & - 0xffff; - - if (t1 & (1 << 15)) - t1 -= 1 << 16; - if (t2 & (1 << 15)) - t2 -= 1 << 16; - t1 *= t2; - t5 = t1; - if (t5 & (1 << 31)) - t5 -= 1ULL << - 32; - state->Accumulator += - t5; - _assert_msg_(ARM11, false, "disabled skyeye code 'goto donext'"); //goto donext; - } - break; - - default: - break; - } - /* Drop through. */ - - case 0xe0: - case 0xe4: - case 0xe6: - case 0xe8: - case 0xea: - case 0xec: - case 0xee: - if (BIT (4)) { - /* MCR. */ - if (DESTReg == 15) { - UNDEF_MCRPC; -#ifdef MODE32 - ARMul_MCR (state, instr, - state->Reg[15] + - isize); -#else - ARMul_MCR (state, instr, - ECC | ER15INT | - EMODE | - ((state->Reg[15] + - isize) & - R15PCBITS)); -#endif - } - else - ARMul_MCR (state, instr, - DEST); - } - else - /* CDP Part 1. */ - ARMul_CDP (state, instr); - break; - - - /* Co-Processor Register Transfers (MRC) and Data Ops. */ - case 0xe1: - case 0xe3: - case 0xe5: - case 0xe7: - case 0xe9: - case 0xeb: - case 0xed: - case 0xef: - if (BIT (4)) { - /* MRC */ - temp = ARMul_MRC (state, instr); - if (DESTReg == 15) { - ASSIGNN ((temp & NBIT) != 0); - ASSIGNZ ((temp & ZBIT) != 0); - ASSIGNC ((temp & CBIT) != 0); - ASSIGNV ((temp & VBIT) != 0); - } - else - DEST = temp; - } - else - /* CDP Part 2. */ - ARMul_CDP (state, instr); - break; - - - /* SWI instruction. */ - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - case 0xf8: - case 0xf9: - case 0xfa: - case 0xfb: - case 0xfc: - case 0xfd: - case 0xfe: - case 0xff: - if (instr == ARMul_ABORTWORD - && state->AbortAddr == pc) { - /* A prefetch abort. */ - XScale_set_fsr_far (state, - ARMul_CP15_R5_MMU_EXCPT, - pc); - ARMul_Abort (state, - ARMul_PrefetchAbortV); - break; - } - //sky_pref_t* pref = get_skyeye_pref(); - //if(pref->user_mode_sim){ - // ARMul_OSHandleSWI (state, BITS (0, 23)); - // break; - //} - ARMul_Abort (state, ARMul_SWIV); - break; - } - } - -#ifdef MODET - donext: -#endif - state->pc = pc; -#if 0 - /* shenoubang */ - instr_sum++; - int i, j; - i = j = 0; - if (instr_sum >= 7388648) { - //if (pc == 0xc0008ab4) { - // printf("instr_sum: %d\n", instr_sum); - // start_kernel : 0xc000895c - printf("--------------------------------------------------\n"); - for (i = 0; i < 16; i++) { - printf("[R%02d]:[0x%08x]\t", i, state->Reg[i]); - if ((i % 3) == 2) { - printf("\n"); - } - } - printf("[cpr]:[0x%08x]\t[spr0]:[0x%08x]\n", state->Cpsr, state->Spsr[0]); - for (j = 1; j < 7; j++) { - printf("[spr%d]:[0x%08x]\t", j, state->Spsr[j]); - if ((j % 4) == 3) { - printf("\n"); - } - } - printf("\n[PC]:[0x%08x]\t[INST]:[0x%08x]\t[COUNT]:[%d]\n", pc, instr, instr_sum); - printf("--------------------------------------------------\n"); - } -#endif - -#if 0 - fprintf(state->state_log, "PC:0x%x\n", pc); - for (reg_index = 0; reg_index < 16; reg_index ++) { - if (state->Reg[reg_index] != mirror_register_file[reg_index]) { - fprintf(state->state_log, "R%d:0x%x\n", reg_index, state->Reg[reg_index]); - mirror_register_file[reg_index] = state->Reg[reg_index]; - } - } - if (state->Cpsr != mirror_register_file[CPSR_REG]) { - fprintf(state->state_log, "Cpsr:0x%x\n", state->Cpsr); - mirror_register_file[CPSR_REG] = state->Cpsr; - } - if (state->RegBank[SVCBANK][13] != mirror_register_file[R13_SVC]) { - fprintf(state->state_log, "R13_SVC:0x%x\n", state->RegBank[SVCBANK][13]); - mirror_register_file[R13_SVC] = state->RegBank[SVCBANK][13]; - } - if (state->RegBank[SVCBANK][14] != mirror_register_file[R14_SVC]) { - fprintf(state->state_log, "R14_SVC:0x%x\n", state->RegBank[SVCBANK][14]); - mirror_register_file[R14_SVC] = state->RegBank[SVCBANK][14]; - } - if (state->RegBank[ABORTBANK][13] != mirror_register_file[R13_ABORT]) { - fprintf(state->state_log, "R13_ABORT:0x%x\n", state->RegBank[ABORTBANK][13]); - mirror_register_file[R13_ABORT] = state->RegBank[ABORTBANK][13]; - } - if (state->RegBank[ABORTBANK][14] != mirror_register_file[R14_ABORT]) { - fprintf(state->state_log, "R14_ABORT:0x%x\n", state->RegBank[ABORTBANK][14]); - mirror_register_file[R14_ABORT] = state->RegBank[ABORTBANK][14]; - } - if (state->RegBank[UNDEFBANK][13] != mirror_register_file[R13_UNDEF]) { - fprintf(state->state_log, "R13_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][13]); - mirror_register_file[R13_UNDEF] = state->RegBank[UNDEFBANK][13]; - } - if (state->RegBank[UNDEFBANK][14] != mirror_register_file[R14_UNDEF]) { - fprintf(state->state_log, "R14_UNDEF:0x%x\n", state->RegBank[UNDEFBANK][14]); - mirror_register_file[R14_UNDEF] = state->RegBank[UNDEFBANK][14]; - } - if (state->RegBank[IRQBANK][13] != mirror_register_file[R13_IRQ]) { - fprintf(state->state_log, "R13_IRQ:0x%x\n", state->RegBank[IRQBANK][13]); - mirror_register_file[R13_IRQ] = state->RegBank[IRQBANK][13]; - } - if (state->RegBank[IRQBANK][14] != mirror_register_file[R14_IRQ]) { - fprintf(state->state_log, "R14_IRQ:0x%x\n", state->RegBank[IRQBANK][14]); - mirror_register_file[R14_IRQ] = state->RegBank[IRQBANK][14]; - } - if (state->RegBank[FIQBANK][8] != mirror_register_file[R8_FIRQ]) { - fprintf(state->state_log, "R8_FIRQ:0x%x\n", state->RegBank[FIQBANK][8]); - mirror_register_file[R8_FIRQ] = state->RegBank[FIQBANK][8]; - } - if (state->RegBank[FIQBANK][9] != mirror_register_file[R9_FIRQ]) { - fprintf(state->state_log, "R9_FIRQ:0x%x\n", state->RegBank[FIQBANK][9]); - mirror_register_file[R9_FIRQ] = state->RegBank[FIQBANK][9]; - } - if (state->RegBank[FIQBANK][10] != mirror_register_file[R10_FIRQ]) { - fprintf(state->state_log, "R10_FIRQ:0x%x\n", state->RegBank[FIQBANK][10]); - mirror_register_file[R10_FIRQ] = state->RegBank[FIQBANK][10]; - } - if (state->RegBank[FIQBANK][11] != mirror_register_file[R11_FIRQ]) { - fprintf(state->state_log, "R11_FIRQ:0x%x\n", state->RegBank[FIQBANK][11]); - mirror_register_file[R11_FIRQ] = state->RegBank[FIQBANK][11]; - } - if (state->RegBank[FIQBANK][12] != mirror_register_file[R12_FIRQ]) { - fprintf(state->state_log, "R12_FIRQ:0x%x\n", state->RegBank[FIQBANK][12]); - mirror_register_file[R12_FIRQ] = state->RegBank[FIQBANK][12]; - } - if (state->RegBank[FIQBANK][13] != mirror_register_file[R13_FIRQ]) { - fprintf(state->state_log, "R13_FIRQ:0x%x\n", state->RegBank[FIQBANK][13]); - mirror_register_file[R13_FIRQ] = state->RegBank[FIQBANK][13]; - } - if (state->RegBank[FIQBANK][14] != mirror_register_file[R14_FIRQ]) { - fprintf(state->state_log, "R14_FIRQ:0x%x\n", state->RegBank[FIQBANK][14]); - mirror_register_file[R14_FIRQ] = state->RegBank[FIQBANK][14]; - } - if (state->Spsr[SVCBANK] != mirror_register_file[SPSR_SVC]) { - fprintf(state->state_log, "SPSR_SVC:0x%x\n", state->Spsr[SVCBANK]); - mirror_register_file[SPSR_SVC] = state->RegBank[SVCBANK]; - } - if (state->Spsr[ABORTBANK] != mirror_register_file[SPSR_ABORT]) { - fprintf(state->state_log, "SPSR_ABORT:0x%x\n", state->Spsr[ABORTBANK]); - mirror_register_file[SPSR_ABORT] = state->RegBank[ABORTBANK]; - } - if (state->Spsr[UNDEFBANK] != mirror_register_file[SPSR_UNDEF]) { - fprintf(state->state_log, "SPSR_UNDEF:0x%x\n", state->Spsr[UNDEFBANK]); - mirror_register_file[SPSR_UNDEF] = state->RegBank[UNDEFBANK]; - } - if (state->Spsr[IRQBANK] != mirror_register_file[SPSR_IRQ]) { - fprintf(state->state_log, "SPSR_IRQ:0x%x\n", state->Spsr[IRQBANK]); - mirror_register_file[SPSR_IRQ] = state->RegBank[IRQBANK]; - } - if (state->Spsr[FIQBANK] != mirror_register_file[SPSR_FIRQ]) { - fprintf(state->state_log, "SPSR_FIRQ:0x%x\n", state->Spsr[FIQBANK]); - mirror_register_file[SPSR_FIRQ] = state->RegBank[FIQBANK]; - } - -#endif - -#ifdef NEED_UI_LOOP_HOOK - if (ui_loop_hook != NULL && ui_loop_hook_counter-- < 0) { - ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; - ui_loop_hook (0); - } -#endif /* NEED_UI_LOOP_HOOK */ - - /*added energy_prof statement by ksh in 2004-11-26 */ - //chy 2005-07-28 for standalone - //ARMul_do_energy(state,instr,pc); -//teawater add for record reg value to ./reg.txt 2005.07.10--------------------- - if (state->tea_break_ok && pc == state->tea_break_addr) { - ARMul_Debug (state, 0, 0); - state->tea_break_ok = 0; - } - else { - state->tea_break_ok = 1; - } -//AJ2D-------------------------------------------------------------------------- -//chy 2006-04-14 for ctrl-c debug -#if 0 - if (debugmode) { - if (instr != ARMul_ABORTWORD) { - remote_interrupt_test_time++; - //chy 2006-04-14 2000 should be changed in skyeye_conf ???!!! - if (remote_interrupt_test_time >= 2000) { - remote_interrupt_test_time=0; - if (remote_interrupt()) { - //for test - //printf("SKYEYE: ICE_debug recv Ctrl_C\n"); - state->EndCondition = 0; - state->Emulate = STOP; - } - } - } - } -#endif - - /* jump out every time */ - //state->EndCondition = 0; - //state->Emulate = STOP; -//chy 2006-04-12 for ICE debug -TEST_EMULATE: - if (state->Emulate == ONCE) - state->Emulate = STOP; - //chy: 2003-08-23: should not use CHANGEMODE !!!! - /* If we have changed mode, allow the PC to advance before stopping. */ - // else if (state->Emulate == CHANGEMODE) - // continue; - else if (state->Emulate != RUN) - break; - } - while (!state->stop_simulator); - - state->decoded = decoded; - state->loaded = loaded; - state->pc = pc; - //chy 2006-04-12, for ICE debug - state->decoded_addr=decoded_addr; - state->loaded_addr=loaded_addr; - - return pc; -} - -//teawater add for arm2x86 2005.02.17------------------------------------------- -/*ywc 2005-04-01*/ -//#include "tb.h" -//#include "arm2x86_self.h" - -static volatile void (*gen_func) (void); -//static volatile ARMul_State *tmp_st; -//static volatile ARMul_State *save_st; -static volatile uint32_t tmp_st; -static volatile uint32_t save_st; -static volatile uint32_t save_T0; -static volatile uint32_t save_T1; -static volatile uint32_t save_T2; - -#ifdef MODE32 -#ifdef DBCT -//teawater change for debug function 2005.07.09--------------------------------- -ARMword -ARMul_Emulate32_dbct (ARMul_State * state) -{ - static int init = 0; - static FILE *fd; - - /*if (!init) { - - fd = fopen("./pc.txt", "w"); - if (!fd) { - exit(-1); - } - init = 1; - } */ - - state->Reg[15] += INSN_SIZE; - do { - /*if (skyeye_config.log.logon>=1) { - if (state->NumInstrs>=skyeye_config.log.start && state->NumInstrs<=skyeye_config.log.end) { - static int mybegin=0; - static int myinstrnum=0; - - if (mybegin==0) mybegin=1; - if (mybegin==1) { - state->Reg[15] -= INSN_SIZE; - if (skyeye_config.log.logon>=1) fprintf(skyeye_logfd,"N %llx :p %x,i %x,",state->NumInstrs, (state->Reg[15] - INSN_SIZE), instr); - if (skyeye_config.log.logon>=2) SKYEYE_OUTREGS(skyeye_logfd); - if (skyeye_config.log.logon>=3) SKYEYE_OUTMOREREGS(skyeye_logfd); - fprintf(skyeye_logfd,"\n"); - if (skyeye_config.log.length>0) { - myinstrnum++; - if (myinstrnum>=skyeye_config.log.length) { - myinstrnum=0; - fflush(skyeye_logfd); - fseek(skyeye_logfd,0L,SEEK_SET); - } - } - state->Reg[15] += INSN_SIZE; - } - } - } */ - state->trap = 0; - gen_func = - (void *) tb_find (state, state->Reg[15] - INSN_SIZE); - if (!gen_func) { - //fprintf(stderr, "SKYEYE: tb_find: Error in find the translate block.\n"); - //exit(-1); - //TRAP_INSN_ABORT - //TEA_OUT(printf("\n------------\npc:%x\n", state->Reg[15] - INSN_SIZE)); - //TEA_OUT(printf("TRAP_INSN_ABORT\n")); -//teawater add for xscale(arm v5) 2005.09.01------------------------------------ - /*XScale_set_fsr_far(state, ARMul_CP15_R5_MMU_EXCPT, state->Reg[15] - INSN_SIZE); - state->Reg[15] += INSN_SIZE; - ARMul_Abort(state, ARMul_PrefetchAbortV); - state->Reg[15] += INSN_SIZE; - goto next; */ - state->trap = TRAP_INSN_ABORT; - goto check; -//AJ2D-------------------------------------------------------------------------- - } - - save_st = (uint32_t) st; - save_T0 = T0; - save_T1 = T1; - save_T2 = T2; - tmp_st = (uint32_t) state; - wmb (); - st = (ARMul_State *) tmp_st; - gen_func (); - st = (ARMul_State *) save_st; - T0 = save_T0; - T1 = save_T1; - T2 = save_T2; - - /*if (state->trap != TRAP_OUT) { - state->tea_break_ok = 1; - } - if (state->trap <= TRAP_SET_R15) { - goto next; - } */ - //TEA_OUT(printf("\n------------\npc:%x\n", state->Reg[15] - INSN_SIZE)); -//teawater add check thumb 2005.07.21------------------------------------------- - /*if (TFLAG) { - state->Reg[15] -= 2; - return(state->Reg[15]); - } */ -//AJ2D-------------------------------------------------------------------------- - -//teawater add for xscale(arm v5) 2005.09.01------------------------------------ - check: -//AJ2D-------------------------------------------------------------------------- - switch (state->trap) { - case TRAP_RESET: - { - //TEA_OUT(printf("TRAP_RESET\n")); - ARMul_Abort (state, ARMul_ResetV); - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_UNPREDICTABLE: - { - ARMul_Debug (state, 0, 0); - } - break; - case TRAP_INSN_UNDEF: - { - //TEA_OUT(printf("TRAP_INSN_UNDEF\n")); - state->Reg[15] += INSN_SIZE; - ARMul_UndefInstr (state, 0); - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_SWI: - { - //TEA_OUT(printf("TRAP_SWI\n")); - state->Reg[15] += INSN_SIZE; - ARMul_Abort (state, ARMul_SWIV); - state->Reg[15] += INSN_SIZE; - } - break; -//teawater add for xscale(arm v5) 2005.09.01------------------------------------ - case TRAP_INSN_ABORT: - { - XScale_set_fsr_far (state, - ARMul_CP15_R5_MMU_EXCPT, - state->Reg[15] - - INSN_SIZE); - state->Reg[15] += INSN_SIZE; - ARMul_Abort (state, ARMul_PrefetchAbortV); - state->Reg[15] += INSN_SIZE; - } - break; -//AJ2D-------------------------------------------------------------------------- - case TRAP_DATA_ABORT: - { - //TEA_OUT(printf("TRAP_DATA_ABORT\n")); - state->Reg[15] += INSN_SIZE; - ARMul_Abort (state, ARMul_DataAbortV); - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_IRQ: - { - //TEA_OUT(printf("TRAP_IRQ\n")); - state->Reg[15] += INSN_SIZE; - ARMul_Abort (state, ARMul_IRQV); - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_FIQ: - { - //TEA_OUT(printf("TRAP_FIQ\n")); - state->Reg[15] += INSN_SIZE; - ARMul_Abort (state, ARMul_FIQV); - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_SETS_R15: - { - //TEA_OUT(printf("TRAP_SETS_R15\n")); - /*if (state->Bank > 0) { - state->Cpsr = state->Spsr[state->Bank]; - ARMul_CPSRAltered (state); - } */ - WriteSR15 (state, state->Reg[15]); - } - break; - case TRAP_SET_CPSR: - { - //TEA_OUT(printf("TRAP_SET_CPSR\n")); - //chy 2006-02-15 USERBANK=SYSTEMBANK=0 - //chy 2006-02-16 should use Mode to test - //if (state->Bank > 0) { - if (state->Mode != USER26MODE && state->Mode != USER32MODE){ - ARMul_CPSRAltered (state); - } - state->Reg[15] += INSN_SIZE; - } - break; - case TRAP_OUT: - { - //TEA_OUT(printf("TRAP_OUT\n")); - goto out; - } - break; - case TRAP_BREAKPOINT: - { - //TEA_OUT(printf("TRAP_BREAKPOINT\n")); - state->Reg[15] -= INSN_SIZE; - if (!ARMul_OSHandleSWI - (state, SWI_Breakpoint)) { - ARMul_Abort (state, ARMul_SWIV); - } - state->Reg[15] += INSN_SIZE; - } - break; - } - - next: - if (state->Emulate == ONCE) { - state->Emulate = STOP; - break; - } - else if (state->Emulate != RUN) { - break; - } - } - while (!state->stop_simulator); - - out: - state->Reg[15] -= INSN_SIZE; - return (state->Reg[15]); -} -#endif -//AJ2D-------------------------------------------------------------------------- -#endif -//AJ2D-------------------------------------------------------------------------- - -/* This routine evaluates most Data Processing register RHS's with the S - bit clear. It is intended to be called from the macro DPRegRHS, which - filters the common case of an unshifted register with in line code. */ - -static ARMword -GetDPRegRHS (ARMul_State * state, ARMword instr) -{ - ARMword shamt, base; - - base = RHSReg; - if (BIT (4)) { - /* Shift amount in a register. */ - UNDEF_Shift; - INCPC; -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - ARMul_Icycles (state, 1, 0L); - shamt = state->Reg[BITS (8, 11)] & 0xff; - switch ((int) BITS (5, 6)) { - case LSL: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return (0); - else - return (base << shamt); - case LSR: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return ((ARMword) ((int) base >> 31L)); - else - return ((ARMword) - (( int) base >> (int) shamt)); - case ROR: - shamt &= 0x1f; - if (shamt == 0) - return (base); - else - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - else { - /* Shift amount is a constant. */ -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - shamt = BITS (7, 11); - switch ((int) BITS (5, 6)) { - case LSL: - return (base << shamt); - case LSR: - if (shamt == 0) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return ((ARMword) (( int) base >> 31L)); - else - return ((ARMword) - (( int) base >> (int) shamt)); - case ROR: - if (shamt == 0) - /* It's an RRX. */ - return ((base >> 1) | (CFLAG << 31)); - else - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - - return 0; -} - -/* This routine evaluates most Logical Data Processing register RHS's - with the S bit set. It is intended to be called from the macro - DPSRegRHS, which filters the common case of an unshifted register - with in line code. */ - -static ARMword -GetDPSRegRHS (ARMul_State * state, ARMword instr) -{ - ARMword shamt, base; - - base = RHSReg; - if (BIT (4)) { - /* Shift amount in a register. */ - UNDEF_Shift; - INCPC; -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - ARMul_Icycles (state, 1, 0L); - shamt = state->Reg[BITS (8, 11)] & 0xff; - switch ((int) BITS (5, 6)) { - case LSL: - if (shamt == 0) - return (base); - else if (shamt == 32) { - ASSIGNC (base & 1); - return (0); - } - else if (shamt > 32) { - CLEARC; - return (0); - } - else { - ASSIGNC ((base >> (32 - shamt)) & 1); - return (base << shamt); - } - case LSR: - if (shamt == 0) - return (base); - else if (shamt == 32) { - ASSIGNC (base >> 31); - return (0); - } - else if (shamt > 32) { - CLEARC; - return (0); - } - else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return (base >> shamt); - } - case ASR: - if (shamt == 0) - return (base); - else if (shamt >= 32) { - ASSIGNC (base >> 31L); - return ((ARMword) (( int) base >> 31L)); - } - else { - ASSIGNC ((ARMword) - (( int) base >> - (int) (shamt - 1)) & 1); - return ((ARMword) - ((int) base >> (int) shamt)); - } - case ROR: - if (shamt == 0) - return (base); - shamt &= 0x1f; - if (shamt == 0) { - ASSIGNC (base >> 31); - return (base); - } - else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - } - else { - /* Shift amount is a constant. */ -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - shamt = BITS (7, 11); - - switch ((int) BITS (5, 6)) { - case LSL: - ASSIGNC ((base >> (32 - shamt)) & 1); - return (base << shamt); - case LSR: - if (shamt == 0) { - ASSIGNC (base >> 31); - return (0); - } - else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return (base >> shamt); - } - case ASR: - if (shamt == 0) { - ASSIGNC (base >> 31L); - return ((ARMword) ((int) base >> 31L)); - } - else { - ASSIGNC ((ARMword) - ((int) base >> - (int) (shamt - 1)) & 1); - return ((ARMword) - (( int) base >> (int) shamt)); - } - case ROR: - if (shamt == 0) { - /* It's an RRX. */ - shamt = CFLAG; - ASSIGNC (base & 1); - return ((base >> 1) | (shamt << 31)); - } - else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - } - - return 0; -} - -/* This routine handles writes to register 15 when the S bit is not set. */ - -static void -WriteR15 (ARMul_State * state, ARMword src) -{ - /* The ARM documentation states that the two least significant bits - are discarded when setting PC, except in the cases handled by - WriteR15Branch() below. It's probably an oversight: in THUMB - mode, the second least significant bit should probably not be - discarded. */ -#ifdef MODET - if (TFLAG) - src &= 0xfffffffe; - else -#endif - src &= 0xfffffffc; - -#ifdef MODE32 - state->Reg[15] = src & PCBITS; -#else - state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE; - ARMul_R15Altered (state); -#endif - - FLUSHPIPE; -} - -/* This routine handles writes to register 15 when the S bit is set. */ - -static void -WriteSR15 (ARMul_State * state, ARMword src) -{ -#ifdef MODE32 - if (state->Bank > 0) { - state->Cpsr = state->Spsr[state->Bank]; - ARMul_CPSRAltered (state); - } -#ifdef MODET - if (TFLAG) - src &= 0xfffffffe; - else -#endif - src &= 0xfffffffc; - state->Reg[15] = src & PCBITS; -#else -#ifdef MODET - if (TFLAG) - /* ARMul_R15Altered would have to support it. */ - abort (); - else -#endif - src &= 0xfffffffc; - - if (state->Bank == USERBANK) - state->Reg[15] = - (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE; - else - state->Reg[15] = src; - - ARMul_R15Altered (state); -#endif - FLUSHPIPE; -} - -/* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM - will switch to Thumb mode if the least significant bit is set. */ - -static void -WriteR15Branch (ARMul_State * state, ARMword src) -{ -#ifdef MODET - if (src & 1) { - /* Thumb bit. */ - SETT; - state->Reg[15] = src & 0xfffffffe; - } - else { - CLEART; - state->Reg[15] = src & 0xfffffffc; - } - state->Cpsr = ARMul_GetCPSR (state); - FLUSHPIPE; -#else - WriteR15 (state, src); -#endif -} - -/* This routine evaluates most Load and Store register RHS's. It is - intended to be called from the macro LSRegRHS, which filters the - common case of an unshifted register with in line code. */ - -static ARMword -GetLSRegRHS (ARMul_State * state, ARMword instr) -{ - ARMword shamt, base; - - base = RHSReg; -#ifndef MODE32 - if (base == 15) - /* Now forbidden, but ... */ - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - - shamt = BITS (7, 11); - switch ((int) BITS (5, 6)) { - case LSL: - return (base << shamt); - case LSR: - if (shamt == 0) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return ((ARMword) (( int) base >> 31L)); - else - return ((ARMword) (( int) base >> (int) shamt)); - case ROR: - if (shamt == 0) - /* It's an RRX. */ - return ((base >> 1) | (CFLAG << 31)); - else - return ((base << (32 - shamt)) | (base >> shamt)); - default: - break; - } - return 0; -} - -/* This routine evaluates the ARM7T halfword and signed transfer RHS's. */ - -static ARMword -GetLS7RHS (ARMul_State * state, ARMword instr) -{ - if (BIT (22) == 0) { - /* Register. */ -#ifndef MODE32 - if (RHSReg == 15) - /* Now forbidden, but ... */ - return ECC | ER15INT | R15PC | EMODE; -#endif - return state->Reg[RHSReg]; - } - - /* Immediate. */ - return BITS (0, 3) | (BITS (8, 11) << 4); -} - -/* This function does the work of loading a word for a LDR instruction. */ -#define MEM_LOAD_LOG(description) if (skyeye_config.log.memlogon >= 1) { \ - fprintf(skyeye_logfd, \ - "m LOAD %s: N %llx :p %x :i %x :a %x :d %x\n", \ - description, state->NumInstrs, state->pc, instr, \ - address, dest); \ - } - -#define MEM_STORE_LOG(description) if (skyeye_config.log.memlogon >= 1) { \ - fprintf(skyeye_logfd, \ - "m STORE %s: N %llx :p %x :i %x :a %x :d %x\n", \ - description, state->NumInstrs, state->pc, instr, \ - address, DEST); \ - } - - - -static unsigned -LoadWord (ARMul_State * state, ARMword instr, ARMword address) -{ - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - - dest = ARMul_LoadWordN (state, address); - - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - if (address & 3) - dest = ARMul_Align (state, address, dest); - WRITEDESTB (dest); - ARMul_Icycles (state, 1, 0L); - - //MEM_LOAD_LOG("WORD"); - - return (DESTReg != LHSReg); -} - -#ifdef MODET -/* This function does the work of loading a halfword. */ - -static unsigned -LoadHalfWord (ARMul_State * state, ARMword instr, ARMword address, - int signextend) -{ - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - dest = ARMul_LoadHalfWord (state, address); - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - UNDEF_LSRBPC; - if (signextend) - if (dest & 1 << (16 - 1)) - dest = (dest & ((1 << 16) - 1)) - (1 << 16); - - WRITEDEST (dest); - ARMul_Icycles (state, 1, 0L); - - //MEM_LOAD_LOG("HALFWORD"); - - return (DESTReg != LHSReg); -} - -#endif /* MODET */ - -/* This function does the work of loading a byte for a LDRB instruction. */ - -static unsigned -LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend) -{ - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - dest = ARMul_LoadByte (state, address); - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - UNDEF_LSRBPC; - if (signextend) - if (dest & 1 << (8 - 1)) - dest = (dest & ((1 << 8) - 1)) - (1 << 8); - - WRITEDEST (dest); - ARMul_Icycles (state, 1, 0L); - - //MEM_LOAD_LOG("BYTE"); - - return (DESTReg != LHSReg); -} - -/* This function does the work of loading two words for a LDRD instruction. */ - -static void -Handle_Load_Double (ARMul_State * state, ARMword instr) -{ - ARMword dest_reg; - ARMword addr_reg; - ARMword write_back = BIT (21); - ARMword immediate = BIT (22); - ARMword add_to_base = BIT (23); - ARMword pre_indexed = BIT (24); - ARMword offset; - ARMword addr; - ARMword sum; - ARMword base; - ARMword value1; - ARMword value2; - - BUSUSEDINCPCS; - - /* If the writeback bit is set, the pre-index bit must be clear. */ - if (write_back && !pre_indexed) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the base address register. */ - addr_reg = LHSReg; - - /* Extract the destination register and check it. */ - dest_reg = DESTReg; - - /* Destination register must be even. */ - if ((dest_reg & 1) - /* Destination register cannot be LR. */ - || (dest_reg == 14)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Compute the base address. */ - base = state->Reg[addr_reg]; - - /* Compute the offset. */ - offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> - Reg[RHSReg]; - - /* Compute the sum of the two. */ - if (add_to_base) - sum = base + offset; - else - sum = base - offset; - - /* If this is a pre-indexed mode use the sum. */ - if (pre_indexed) - addr = sum; - else - addr = base; - - /* The address must be aligned on a 8 byte boundary. */ - if (addr & 0x7) { -#ifdef ABORTS - ARMul_DATAABORT (addr); -#else - ARMul_UndefInstr (state, instr); -#endif - return; - } - - /* For pre indexed or post indexed addressing modes, - check that the destination registers do not overlap - the address registers. */ - if ((!pre_indexed || write_back) - && (addr_reg == dest_reg || addr_reg == dest_reg + 1)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Load the words. */ - value1 = ARMul_LoadWordN (state, addr); - value2 = ARMul_LoadWordN (state, addr + 4); - - /* Check for data aborts. */ - if (state->Aborted) { - TAKEABORT; - return; - } - - ARMul_Icycles (state, 2, 0L); - - /* Store the values. */ - state->Reg[dest_reg] = value1; - state->Reg[dest_reg + 1] = value2; - - /* Do the post addressing and writeback. */ - if (!pre_indexed) - addr = sum; - - if (!pre_indexed || write_back) - state->Reg[addr_reg] = addr; -} - -/* This function does the work of storing two words for a STRD instruction. */ - -static void -Handle_Store_Double (ARMul_State * state, ARMword instr) -{ - ARMword src_reg; - ARMword addr_reg; - ARMword write_back = BIT (21); - ARMword immediate = BIT (22); - ARMword add_to_base = BIT (23); - ARMword pre_indexed = BIT (24); - ARMword offset; - ARMword addr; - ARMword sum; - ARMword base; - - BUSUSEDINCPCS; - - /* If the writeback bit is set, the pre-index bit must be clear. */ - if (write_back && !pre_indexed) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the base address register. */ - addr_reg = LHSReg; - - /* Base register cannot be PC. */ - if (addr_reg == 15) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the source register. */ - src_reg = DESTReg; - - /* Source register must be even. */ - if (src_reg & 1) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Compute the base address. */ - base = state->Reg[addr_reg]; - - /* Compute the offset. */ - offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> - Reg[RHSReg]; - - /* Compute the sum of the two. */ - if (add_to_base) - sum = base + offset; - else - sum = base - offset; - - /* If this is a pre-indexed mode use the sum. */ - if (pre_indexed) - addr = sum; - else - addr = base; - - /* The address must be aligned on a 8 byte boundary. */ - if (addr & 0x7) { -#ifdef ABORTS - ARMul_DATAABORT (addr); -#else - ARMul_UndefInstr (state, instr); -#endif - return; - } - - /* For pre indexed or post indexed addressing modes, - check that the destination registers do not overlap - the address registers. */ - if ((!pre_indexed || write_back) - && (addr_reg == src_reg || addr_reg == src_reg + 1)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Load the words. */ - ARMul_StoreWordN (state, addr, state->Reg[src_reg]); - ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]); - - if (state->Aborted) { - TAKEABORT; - return; - } - - /* Do the post addressing and writeback. */ - if (!pre_indexed) - addr = sum; - - if (!pre_indexed || write_back) - state->Reg[addr_reg] = addr; -} - -/* This function does the work of storing a word from a STR instruction. */ - -static unsigned -StoreWord (ARMul_State * state, ARMword instr, ARMword address) -{ - //MEM_STORE_LOG("WORD"); - - BUSUSEDINCPCN; -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif -#ifdef MODE32 - ARMul_StoreWordN (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadWordN (state, address); - } - else - ARMul_StoreWordN (state, address, DEST); -#endif - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - - return TRUE; -} - -#ifdef MODET -/* This function does the work of storing a byte for a STRH instruction. */ - -static unsigned -StoreHalfWord (ARMul_State * state, ARMword instr, ARMword address) -{ - //MEM_STORE_LOG("HALFWORD"); - - BUSUSEDINCPCN; - -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif - -#ifdef MODE32 - ARMul_StoreHalfWord (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadHalfWord (state, address); - } - else - ARMul_StoreHalfWord (state, address, DEST); -#endif - - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - return TRUE; -} - -#endif /* MODET */ - -/* This function does the work of storing a byte for a STRB instruction. */ - -static unsigned -StoreByte (ARMul_State * state, ARMword instr, ARMword address) -{ - //MEM_STORE_LOG("BYTE"); - - BUSUSEDINCPCN; -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif -#ifdef MODE32 - ARMul_StoreByte (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadByte (state, address); - } - else - ARMul_StoreByte (state, address, DEST); -#endif - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - //UNDEF_LSRBPC; - return TRUE; -} - -/* This function does the work of loading the registers listed in an LDM - instruction, when the S bit is clear. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - -static void -LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) -{ - ARMword dest, temp; - - //UNDEF_LSMNoRegs; - //UNDEF_LSMPCBase; - //UNDEF_LSMBaseInListWb; - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif -/*chy 2004-05-23 may write twice - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; -*/ - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - - dest = ARMul_LoadWordN (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp++] = dest; - else if (!state->Aborted) { - XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } -/*chy 2004-05-23 chy goto end*/ - if (state->Aborted) - goto L_ldm_makeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Load this register. */ - address += 4; - dest = ARMul_LoadWordS (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp] = dest; - else if (!state->Aborted) { - XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address); - state->Aborted = ARMul_DataAbortV; - } - /*chy 2004-05-23 chy goto end */ - if (state->Aborted) - goto L_ldm_makeabort; - - } - - if (BIT (15) && !state->Aborted) - /* PC is in the reg list. */ - WriteR15Branch(state, (state->Reg[15] & PCMASK)); - - /* To write back the final register. */ -/* ARMul_Icycles (state, 1, 0L);*/ -/*chy 2004-05-23, see below - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - } -*/ -/*chy 2004-05-23 should compare the Abort Models*/ - L_ldm_makeabort: - /* To write back the final register. */ - ARMul_Icycles (state, 1, 0L); - - /* chy 2005-11-24, bug found by benjl@cse.unsw.edu.au, etc */ - /* - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - if (!(state->abortSig && state->Aborted && state->lateabtSig == LOW)) - LSBase = WBBase; - TAKEABORT; - }else if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - */ - if (state->Aborted) { - if (BIT (21) && LHSReg != 15) { - if (!(state->abortSig)) { - } - } - TAKEABORT; - } - else if (BIT (21) && LHSReg != 15) { - LSBase = WBBase; - } - /* chy 2005-11-24, over */ - -} - -/* This function does the work of loading the registers listed in an LDM - instruction, when the S bit is set. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - -static void -LoadSMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) -{ - ARMword dest, temp; - - //UNDEF_LSMNoRegs; - //UNDEF_LSMPCBase; - //UNDEF_LSMBaseInListWb; - - BUSUSEDINCPCS; - -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif -/* chy 2004-05-23, may write twice - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; -*/ - if (!BIT (15) && state->Bank != USERBANK) { - /* Temporary reg bank switch. */ - (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); - UNDEF_LSMUserBankWb; - } - - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - - dest = ARMul_LoadWordN (state, address); - - if (!state->abortSig) - state->Reg[temp++] = dest; - else if (!state->Aborted) { - XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - -/*chy 2004-05-23 chy goto end*/ - if (state->Aborted) - goto L_ldm_s_makeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Load this register. */ - address += 4; - dest = ARMul_LoadWordS (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp] = dest; - else if (!state->Aborted) { - XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address); - state->Aborted = ARMul_DataAbortV; - } - /*chy 2004-05-23 chy goto end */ - if (state->Aborted) - goto L_ldm_s_makeabort; - } - -/*chy 2004-05-23 label of ldm_s_makeabort*/ - L_ldm_s_makeabort: -/*chy 2004-06-06 LSBase process should be here, not in the end of this function. Because ARMul_CPSRAltered maybe change R13(SP) R14(lr). If not, simulate INSTR ldmia sp!,[....pc]^ error.*/ -/*chy 2004-05-23 should compare the Abort Models*/ - if (state->Aborted) { - if (BIT (21) && LHSReg != 15) - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - TAKEABORT; - } - else if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - if (BIT (15) && !state->Aborted) { - /* PC is in the reg list. */ -#ifdef MODE32 - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ){ - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); - } - - WriteR15 (state, (state->Reg[15] & PCMASK)); -#else - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE ) { - /* Protect bits in user mode. */ - ASSIGNN ((state->Reg[15] & NBIT) != 0); - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); - ASSIGNC ((state->Reg[15] & CBIT) != 0); - ASSIGNV ((state->Reg[15] & VBIT) != 0); - } - else - ARMul_R15Altered (state); - - FLUSHPIPE; -#endif - } - - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (!BIT (15) && state->Mode != USER26MODE - && state->Mode != USER32MODE ) - /* Restore the correct bank. */ - (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); - - /* To write back the final register. */ - ARMul_Icycles (state, 1, 0L); -/* chy 2004-05-23, see below - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - } -*/ -} - -/* This function does the work of storing the registers listed in an STM - instruction, when the S bit is clear. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - -static void -StoreMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) -{ - ARMword temp; - - UNDEF_LSMNoRegs; - UNDEF_LSMPCBase; - UNDEF_LSMBaseInListWb; - - if (!TFLAG) - /* N-cycle, increment the PC and update the NextInstr state. */ - BUSUSEDINCPCN; - -#ifndef MODE32 - if (VECTORACCESS (address) || ADDREXCEPT (address)) - INTERNALABORT (address); - - if (BIT (15)) - PATCHR15; -#endif - - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - -#ifdef MODE32 - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#else - if (state->Aborted) { - (void) ARMul_LoadWordN (state, address); - - /* Fake the Stores as Loads. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - (void) ARMul_LoadWordS (state, address); - } - - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - TAKEABORT; - return; - } - else - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#endif - - if (state->abortSig && !state->Aborted) { - XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - -//chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_takeabort; - - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - ARMul_StoreWordS (state, address, state->Reg[temp]); - - if (state->abortSig && !state->Aborted) { - XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address); - state->Aborted = ARMul_DataAbortV; - } - //chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_takeabort; - - } - -//chy 2004-05-23,should compare the Abort Models - L_stm_takeabort: - if (BIT (21) && LHSReg != 15) { - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - } - if (state->Aborted) - TAKEABORT; -} - -/* This function does the work of storing the registers listed in an STM - instruction when the S bit is set. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - -static void -StoreSMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) -{ - ARMword temp; - - UNDEF_LSMNoRegs; - UNDEF_LSMPCBase; - UNDEF_LSMBaseInListWb; - - BUSUSEDINCPCN; - -#ifndef MODE32 - if (VECTORACCESS (address) || ADDREXCEPT (address)) - INTERNALABORT (address); - - if (BIT (15)) - PATCHR15; -#endif - - if (state->Bank != USERBANK) { - /* Force User Bank. */ - (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); - UNDEF_LSMUserBankWb; - } - - for (temp = 0; !BIT (temp); temp++); /* N cycle first. */ - -#ifdef MODE32 - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#else - if (state->Aborted) { - (void) ARMul_LoadWordN (state, address); - - for (; temp < 16; temp++) - /* Fake the Stores as Loads. */ - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - (void) ARMul_LoadWordS (state, address); - } - - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - return; - } - else - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#endif - - if (state->abortSig && !state->Aborted) { - XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - -//chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_s_takeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - ARMul_StoreWordS (state, address, state->Reg[temp]); - - if (state->abortSig && !state->Aborted) { - XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address); - state->Aborted = ARMul_DataAbortV; - } - //chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_s_takeabort; - } - - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ) - /* Restore the correct bank. */ - (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); - - -//chy 2004-05-23,should compare the Abort Models - L_stm_s_takeabort: - if (BIT (21) && LHSReg != 15) { - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - } - - if (state->Aborted) - TAKEABORT; -} - -/* This function does the work of adding two 32bit values - together, and calculating if a carry has occurred. */ - -static ARMword -Add32 (ARMword a1, ARMword a2, int *carry) -{ - ARMword result = (a1 + a2); - unsigned int uresult = (unsigned int) result; - unsigned int ua1 = (unsigned int) a1; - - /* If (result == RdLo) and (state->Reg[nRdLo] == 0), - or (result > RdLo) then we have no carry. */ - if ((uresult == ua1) ? (a2 != 0) : (uresult < ua1)) - *carry = 1; - else - *carry = 0; - - return result; -} - -/* This function does the work of multiplying - two 32bit values to give a 64bit result. */ - -static unsigned -Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc) -{ - /* Operand register numbers. */ - int nRdHi, nRdLo, nRs, nRm; - ARMword RdHi = 0, RdLo = 0, Rm; - /* Cycle count. */ - int scount; - - nRdHi = BITS (16, 19); - nRdLo = BITS (12, 15); - nRs = BITS (8, 11); - nRm = BITS (0, 3); - - /* Needed to calculate the cycle count. */ - Rm = state->Reg[nRm]; - - /* Check for illegal operand combinations first. */ - if (nRdHi != 15 - && nRdLo != 15 - && nRs != 15 - //&& nRm != 15 && nRdHi != nRdLo && nRdHi != nRm && nRdLo != nRm) { - && nRm != 15 && nRdHi != nRdLo ) { - /* Intermediate results. */ - ARMword lo, mid1, mid2, hi; - int carry; - ARMword Rs = state->Reg[nRs]; - int sign = 0; - - if (msigned) { - /* Compute sign of result and adjust operands if necessary. */ - sign = (Rm ^ Rs) & 0x80000000; - - if (((signed int) Rm) < 0) - Rm = -Rm; - - if (((signed int) Rs) < 0) - Rs = -Rs; - } - - /* We can split the 32x32 into four 16x16 operations. This - ensures that we do not lose precision on 32bit only hosts. */ - lo = ((Rs & 0xFFFF) * (Rm & 0xFFFF)); - mid1 = ((Rs & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); - mid2 = (((Rs >> 16) & 0xFFFF) * (Rm & 0xFFFF)); - hi = (((Rs >> 16) & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); - - /* We now need to add all of these results together, taking - care to propogate the carries from the additions. */ - RdLo = Add32 (lo, (mid1 << 16), &carry); - RdHi = carry; - RdLo = Add32 (RdLo, (mid2 << 16), &carry); - RdHi += (carry + ((mid1 >> 16) & 0xFFFF) + - ((mid2 >> 16) & 0xFFFF) + hi); - - if (sign) { - /* Negate result if necessary. */ - RdLo = ~RdLo; - RdHi = ~RdHi; - if (RdLo == 0xFFFFFFFF) { - RdLo = 0; - RdHi += 1; - } - else - RdLo += 1; - } - - state->Reg[nRdLo] = RdLo; - state->Reg[nRdHi] = RdHi; - } - else{ - fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS, instr=0x%x\n", instr); - } - if (scc) - /* Ensure that both RdHi and RdLo are used to compute Z, - but don't let RdLo's sign bit make it to N. */ - ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); - - /* The cycle count depends on whether the instruction is a signed or - unsigned multiply, and what bits are clear in the multiplier. */ - if (msigned && (Rm & ((unsigned) 1 << 31))) - /* Invert the bits to make the check against zero. */ - Rm = ~Rm; - - if ((Rm & 0xFFFFFF00) == 0) - scount = 1; - else if ((Rm & 0xFFFF0000) == 0) - scount = 2; - else if ((Rm & 0xFF000000) == 0) - scount = 3; - else - scount = 4; - - return 2 + scount; -} - -/* This function does the work of multiplying two 32bit - values and adding a 64bit value to give a 64bit result. */ - -static unsigned -MultiplyAdd64 (ARMul_State * state, ARMword instr, int msigned, int scc) -{ - unsigned scount; - ARMword RdLo, RdHi; - int nRdHi, nRdLo; - int carry = 0; - - nRdHi = BITS (16, 19); - nRdLo = BITS (12, 15); - - RdHi = state->Reg[nRdHi]; - RdLo = state->Reg[nRdLo]; - - scount = Multiply64 (state, instr, msigned, LDEFAULT); - - RdLo = Add32 (RdLo, state->Reg[nRdLo], &carry); - RdHi = (RdHi + state->Reg[nRdHi]) + carry; - - state->Reg[nRdLo] = RdLo; - state->Reg[nRdHi] = RdHi; - - if (scc) - /* Ensure that both RdHi and RdLo are used to compute Z, - but don't let RdLo's sign bit make it to N. */ - ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); - - /* Extra cycle for addition. */ - return scount + 1; -} - -/* Attempt to emulate an ARMv6 instruction. - Returns non-zero upon success. */ - -static int -handle_v6_insn (ARMul_State * state, ARMword instr) -{ - switch (BITS (20, 27)) - { -#if 0 - case 0x03: printf ("Unhandled v6 insn: ldr\n"); break; - case 0x04: printf ("Unhandled v6 insn: umaal\n"); break; - case 0x06: printf ("Unhandled v6 insn: mls/str\n"); break; - case 0x16: printf ("Unhandled v6 insn: smi\n"); break; - case 0x18: printf ("Unhandled v6 insn: strex\n"); break; - case 0x19: printf ("Unhandled v6 insn: ldrex\n"); break; - case 0x1a: printf ("Unhandled v6 insn: strexd\n"); break; - case 0x1b: printf ("Unhandled v6 insn: ldrexd\n"); break; - case 0x1c: printf ("Unhandled v6 insn: strexb\n"); break; - case 0x1d: printf ("Unhandled v6 insn: ldrexb\n"); break; - case 0x1e: printf ("Unhandled v6 insn: strexh\n"); break; - case 0x1f: printf ("Unhandled v6 insn: ldrexh\n"); break; - case 0x30: printf ("Unhandled v6 insn: movw\n"); break; - case 0x32: printf ("Unhandled v6 insn: nop/sev/wfe/wfi/yield\n"); break; - case 0x34: printf ("Unhandled v6 insn: movt\n"); break; - case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; - case 0x61: printf ("Unhandled v6 insn: sadd/ssub\n"); break; - case 0x62: printf ("Unhandled v6 insn: qadd/qsub\n"); break; - case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break; - case 0x65: printf ("Unhandled v6 insn: uadd/usub\n"); break; - case 0x66: printf ("Unhandled v6 insn: uqadd/uqsub\n"); break; - case 0x67: printf ("Unhandled v6 insn: uhadd/uhsub\n"); break; - case 0x68: printf ("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); break; -#endif - case 0x6c: printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break; - case 0x70: printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break; - case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); break; - case 0x75: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); break; - case 0x78: printf ("Unhandled v6 insn: usad/usada8\n"); break; -#if 0 - case 0x7a: printf ("Unhandled v6 insn: usbfx\n"); break; - case 0x7c: printf ("Unhandled v6 insn: bfc/bfi\n"); break; -#endif - - -/* add new instr for arm v6. */ - ARMword lhs, temp; - case 0x18: /* ORR reg */ - { - /* dyf add armv6 instr strex 2010.9.17 */ - if (BITS (4, 7) == 0x9) { - lhs = LHS; - ARMul_StoreWordS(state, lhs, RHS); - //StoreWord(state, lhs, RHS) - if (state->Aborted) { - TAKEABORT; - } - - return 1; - } - break; - } - - case 0x19: /* orrs reg */ - { - /* dyf add armv6 instr ldrex */ - if (BITS (4, 7) == 0x9) { - lhs = LHS; - LoadWord (state, instr, lhs); - return 1; - } - break; - } - - case 0x1c: /* BIC reg */ - { - /* dyf add for STREXB */ - if (BITS (4, 7) == 0x9) { - lhs = LHS; - ARMul_StoreByte (state, lhs, RHS); - BUSUSEDINCPCN; - if (state->Aborted) { - TAKEABORT; - } - - //printf("In %s, strexb not implemented\n", __FUNCTION__); - UNDEF_LSRBPC; - /* WRITESDEST (dest); */ - return 1; - } - break; - } - - case 0x1d: /* BICS reg */ - { - if ((BITS (4, 7)) == 0x9) { - /* ldrexb */ - temp = LHS; - LoadByte (state, instr, temp, LUNSIGNED); - //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); - //printf("ldrexb\n"); - //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); - //exit(-1); - - //printf("In %s, ldrexb not implemented\n", __FUNCTION__); - return 1; - } - break; - } -/* add end */ - - case 0x6a: - { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) - { - case 0x07: ror = 0; break; - case 0x47: ror = 8; break; - case 0x87: ror = 16; break; - case 0xc7: ror = 24; break; - - case 0x01: - case 0xf3: - printf ("Unhandled v6 insn: ssat\n"); - return 0; - default: - break; - } - - if (ror == -1) - { - if (BITS (4, 6) == 0x7) - { - printf ("Unhandled v6 insn: ssat\n"); - return 0; - } - break; - } - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); - if (Rm & 0x80) - Rm |= 0xffffff00; - - if (BITS (16, 19) == 0xf) - /* SXTB */ - state->Reg[BITS (12, 15)] = Rm; - else - /* SXTAB */ - state->Reg[BITS (12, 15)] += Rm; - } - return 1; - - case 0x6b: - { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) - { - case 0x07: ror = 0; break; - case 0x47: ror = 8; break; - case 0x87: ror = 16; break; - case 0xc7: ror = 24; break; - - case 0xf3: - DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); - return 1; - case 0xfb: - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); - return 1; - default: - break; - } - - if (ror == -1) - break; - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); - if (Rm & 0x8000) - Rm |= 0xffff0000; - - if (BITS (16, 19) == 0xf) - /* SXTH */ - state->Reg[BITS (12, 15)] = Rm; - else - /* SXTAH */ - state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; - } - return 1; - - case 0x6e: - { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) - { - case 0x07: ror = 0; break; - case 0x47: ror = 8; break; - case 0x87: ror = 16; break; - case 0xc7: ror = 24; break; - - case 0x01: - case 0xf3: - printf ("Unhandled v6 insn: usat\n"); - return 0; - default: - break; - } - - if (ror == -1) - { - if (BITS (4, 6) == 0x7) - { - printf ("Unhandled v6 insn: usat\n"); - return 0; - } - break; - } - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); - - if (BITS (16, 19) == 0xf) - /* UXTB */ - state->Reg[BITS (12, 15)] = Rm; - else - /* UXTAB */ - state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; - } - return 1; - - case 0x6f: - { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) - { - case 0x07: ror = 0; break; - case 0x47: ror = 8; break; - case 0x87: ror = 16; break; - case 0xc7: ror = 24; break; - - case 0xfb: - printf ("Unhandled v6 insn: revsh\n"); - return 0; - default: - break; - } - - if (ror == -1) - break; - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); - - /* UXT */ - /* state->Reg[BITS (12, 15)] = Rm; */ - /* dyf add */ - if (BITS (16, 19) == 0xf) { - state->Reg[BITS (12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF; - } else { - /* UXTAH */ - /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */ -// printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] -// , Rm, BITS(10, 11)); -// printf("icounter is %lld\n", state->NumInstrs); - state->Reg[BITS (12, 15)] = (state->Reg[BITS (16, 19)] >> (8 * (BITS(10, 11)))) + Rm; -// printf("rd is %x\n", state->Reg[BITS (12, 15)]); -// exit(-1); - } - } - return 1; - -#if 0 - case 0x84: printf ("Unhandled v6 insn: srs\n"); break; -#endif - default: - break; - } - printf ("Unhandled v6 insn: UNKNOWN: %08x\n", instr); - return 0; -} diff --git a/src/core/src/arm/interpreter/armemu.h b/src/core/src/arm/interpreter/armemu.h deleted file mode 100644 index 2ab317fd..00000000 --- a/src/core/src/arm/interpreter/armemu.h +++ /dev/null @@ -1,659 +0,0 @@ -/* armemu.h -- ARMulator emulation macros: 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. */ -#ifndef __ARMEMU_H__ -#define __ARMEMU_H__ - -#include "common.h" -#include "armdefs.h" -//#include "skyeye.h" - -extern ARMword isize; - -/* Condition code values. */ -#define EQ 0 -#define NE 1 -#define CS 2 -#define CC 3 -#define MI 4 -#define PL 5 -#define VS 6 -#define VC 7 -#define HI 8 -#define LS 9 -#define GE 10 -#define LT 11 -#define GT 12 -#define LE 13 -#define AL 14 -#define NV 15 - -/* Shift Opcodes. */ -#define LSL 0 -#define LSR 1 -#define ASR 2 -#define ROR 3 - -/* Macros to twiddle the status flags and mode. */ -#define NBIT ((unsigned)1L << 31) -#define ZBIT (1L << 30) -#define CBIT (1L << 29) -#define VBIT (1L << 28) -#define SBIT (1L << 27) -#define IBIT (1L << 7) -#define FBIT (1L << 6) -#define IFBITS (3L << 6) -#define R15IBIT (1L << 27) -#define R15FBIT (1L << 26) -#define R15IFBITS (3L << 26) - -#define POS(i) ( (~(i)) >> 31 ) -#define NEG(i) ( (i) >> 31 ) - -#ifdef MODET /* Thumb support. */ -/* ??? This bit is actually in the low order bit of the PC in the hardware. - It isn't clear if the simulator needs to model that or not. */ -#define TBIT (1L << 5) -#define TFLAG state->TFlag -#define SETT state->TFlag = 1 -#define CLEART state->TFlag = 0 -#define ASSIGNT(res) state->TFlag = res -#define INSN_SIZE (TFLAG ? 2 : 4) -#else -#define TBIT (1L << 5) -#define INSN_SIZE 4 -#define TFLAG 0 -#endif - -/*add armv6 CPSR feature*/ -#define EFLAG state->EFlag -#define SETE state->EFlag = 1 -#define CLEARE state->EFlag = 0 -#define ASSIGNE(res) state->NFlag = res - -#define AFLAG state->AFlag -#define SETA state->AFlag = 1 -#define CLEARA state->AFlag = 0 -#define ASSIGNA(res) state->NFlag = res - -#define QFLAG state->QFlag -#define SETQ state->QFlag = 1 -#define CLEARQ state->AFlag = 0 -#define ASSIGNQ(res) state->QFlag = res - -/* add end */ - -#define NFLAG state->NFlag -#define SETN state->NFlag = 1 -#define CLEARN state->NFlag = 0 -#define ASSIGNN(res) state->NFlag = res - -#define ZFLAG state->ZFlag -#define SETZ state->ZFlag = 1 -#define CLEARZ state->ZFlag = 0 -#define ASSIGNZ(res) state->ZFlag = res - -#define CFLAG state->CFlag -#define SETC state->CFlag = 1 -#define CLEARC state->CFlag = 0 -#define ASSIGNC(res) state->CFlag = res - -#define VFLAG state->VFlag -#define SETV state->VFlag = 1 -#define CLEARV state->VFlag = 0 -#define ASSIGNV(res) state->VFlag = res - -#define SFLAG state->SFlag -#define SETS state->SFlag = 1 -#define CLEARS state->SFlag = 0 -#define ASSIGNS(res) state->SFlag = res - -#define IFLAG (state->IFFlags >> 1) -#define FFLAG (state->IFFlags & 1) -#define IFFLAGS state->IFFlags -#define ASSIGNINT(res) state->IFFlags = (((res) >> 6) & 3) -#define ASSIGNR15INT(res) state->IFFlags = (((res) >> 26) & 3) ; - -#define PSR_FBITS (0xff000000L) -#define PSR_SBITS (0x00ff0000L) -#define PSR_XBITS (0x0000ff00L) -#define PSR_CBITS (0x000000ffL) - -#if defined MODE32 || defined MODET -#define CCBITS (0xf8000000L) -#else -#define CCBITS (0xf0000000L) -#endif - -#define INTBITS (0xc0L) - -#if defined MODET && defined MODE32 -#define PCBITS (0xffffffffL) -#else -#define PCBITS (0xfffffffcL) -#endif - -#define MODEBITS (0x1fL) -#define R15INTBITS (3L << 26) - -#if defined MODET && defined MODE32 -#define R15PCBITS (0x03ffffffL) -#else -#define R15PCBITS (0x03fffffcL) -#endif - -#define R15PCMODEBITS (0x03ffffffL) -#define R15MODEBITS (0x3L) - -#ifdef MODE32 -#define PCMASK PCBITS -#define PCWRAP(pc) (pc) -#else -#define PCMASK R15PCBITS -#define PCWRAP(pc) ((pc) & R15PCBITS) -#endif - -#define R15CCINTMODE (state->Reg[15] & (CCBITS | R15INTBITS | R15MODEBITS)) -#define R15INT (state->Reg[15] & R15INTBITS) -#define R15INTPC (state->Reg[15] & (R15INTBITS | R15PCBITS)) -#define R15INTPCMODE (state->Reg[15] & (R15INTBITS | R15PCBITS | R15MODEBITS)) -#define R15INTMODE (state->Reg[15] & (R15INTBITS | R15MODEBITS)) -#define R15PC (state->Reg[15] & R15PCBITS) -#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS)) -#define R15MODE (state->Reg[15] & R15MODEBITS) - -#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27)) -#define EINT (IFFLAGS << 6) -#define ER15INT (IFFLAGS << 26) -#define EMODE (state->Mode) - -//#ifdef MODET -//#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) -//#else -//#define CPSR (ECC | EINT | EMODE) -//#endif - -#ifdef MODE32 -#define PATCHR15 -#else -#define PATCHR15 state->Reg[15] = ECC | ER15INT | EMODE | R15PC -#endif - -#define GETSPSR(bank) (ARMul_GetSPSR (state, EMODE)) -#define SETPSR_F(d,s) d = ((d) & ~PSR_FBITS) | ((s) & PSR_FBITS) -#define SETPSR_S(d,s) d = ((d) & ~PSR_SBITS) | ((s) & PSR_SBITS) -#define SETPSR_X(d,s) d = ((d) & ~PSR_XBITS) | ((s) & PSR_XBITS) -#define SETPSR_C(d,s) d = ((d) & ~PSR_CBITS) | ((s) & PSR_CBITS) - -#define SETR15PSR(s) \ - do \ - { \ - if (state->Mode == USER26MODE) \ - { \ - state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE; \ - ASSIGNN ((state->Reg[15] & NBIT) != 0); \ - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); \ - ASSIGNC ((state->Reg[15] & CBIT) != 0); \ - ASSIGNV ((state->Reg[15] & VBIT) != 0); \ - } \ - else \ - { \ - state->Reg[15] = R15PC | ((s) & (CCBITS | R15INTBITS | R15MODEBITS)); \ - ARMul_R15Altered (state); \ - } \ - } \ - while (0) - -#define SETABORT(i, m, d) \ - do \ - { \ - int SETABORT_mode = (m); \ - \ - ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \ - ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \ - | (i) | SETABORT_mode)); \ - state->Reg[14] = temp - (d); \ - } \ - while (0) - -//#ifndef MODE32 -#define VECTORS 0x20 -#define LEGALADDR 0x03ffffff -#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig) -#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig) -//#endif - -#define INTERNALABORT(address) \ - do \ - { \ - if (address < VECTORS) \ - state->Aborted = ARMul_DataAbortV; \ - else \ - state->Aborted = ARMul_AddrExceptnV; \ - } \ - while (0) - -#ifdef MODE32 -#define TAKEABORT ARMul_Abort (state, ARMul_DataAbortV) -#else -#define TAKEABORT \ - do \ - { \ - if (state->Aborted == ARMul_AddrExceptnV) \ - ARMul_Abort (state, ARMul_AddrExceptnV); \ - else \ - ARMul_Abort (state, ARMul_DataAbortV); \ - } \ - while (0) -#endif - -#define CPTAKEABORT \ - do \ - { \ - if (!state->Aborted) \ - ARMul_Abort (state, ARMul_UndefinedInstrV); \ - else if (state->Aborted == ARMul_AddrExceptnV) \ - ARMul_Abort (state, ARMul_AddrExceptnV); \ - else \ - ARMul_Abort (state, ARMul_DataAbortV); \ - } \ - while (0); - - -/* Different ways to start the next instruction. */ -#define SEQ 0 -#define NONSEQ 1 -#define PCINCEDSEQ 2 -#define PCINCEDNONSEQ 3 -#define PRIMEPIPE 4 -#define RESUME 8 - -/************************************/ -/* shenoubang 2012-3-11 */ -/* for armv7 DBG DMB DSB instr*/ -/************************************/ -#define MBReqTypes_Writes 0 -#define MBReqTypes_All 1 - -#define NORMALCYCLE state->NextInstr = 0 -#define BUSUSEDN state->NextInstr |= 1 /* The next fetch will be an N cycle. */ -#define BUSUSEDINCPCS \ - do \ - { \ - if (! state->is_v4) \ - { \ - /* A standard PC inc and an S cycle. */ \ - state->Reg[15] += isize; \ - state->NextInstr = (state->NextInstr & 0xff) | 2; \ - } \ - } \ - while (0) - -#define BUSUSEDINCPCN \ - do \ - { \ - if (state->is_v4) \ - BUSUSEDN; \ - else \ - { \ - /* A standard PC inc and an N cycle. */ \ - state->Reg[15] += isize; \ - state->NextInstr |= 3; \ - } \ - } \ - while (0) - -#define INCPC \ - do \ - { \ - /* A standard PC inc. */ \ - state->Reg[15] += isize; \ - state->NextInstr |= 2; \ - } \ - while (0) - -#define FLUSHPIPE state->NextInstr |= PRIMEPIPE - -/* Cycle based emulation. */ - -#define OUTPUTCP(i,a,b) -#define NCYCLE -#define SCYCLE -#define ICYCLE -#define CCYCLE -#define NEXTCYCLE(c) - -/* Macros to extract parts of instructions. */ -#define DESTReg (BITS (12, 15)) -#define LHSReg (BITS (16, 19)) -#define RHSReg (BITS ( 0, 3)) - -#define DEST (state->Reg[DESTReg]) - -#ifdef MODE32 -#ifdef MODET -#define LHS ((LHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[LHSReg])) -#define RHS ((RHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[RHSReg])) -#else -#define LHS (state->Reg[LHSReg]) -#define RHS (state->Reg[RHSReg]) -#endif -#else -#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg])) -#define RHS ((RHSReg == 15) ? R15PC : (state->Reg[RHSReg])) -#endif - -#define MULDESTReg (BITS (16, 19)) -#define MULLHSReg (BITS ( 0, 3)) -#define MULRHSReg (BITS ( 8, 11)) -#define MULACCReg (BITS (12, 15)) - -#define DPImmRHS (ARMul_ImmedTable[BITS(0, 11)]) -#define DPSImmRHS temp = BITS(0,11) ; \ - rhs = ARMul_ImmedTable[temp] ; \ - if (temp > 255) /* There was a shift. */ \ - ASSIGNC (rhs >> 31) ; - -#ifdef MODE32 -#define DPRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ - : GetDPRegRHS (state, instr)) -#define DPSRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ - : GetDPSRegRHS (state, instr)) -#else -#define DPRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetDPRegRHS (state, instr)) -#define DPSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetDPSRegRHS (state, instr)) -#endif - -#define LSBase state->Reg[LHSReg] -#define LSImmRHS (BITS(0,11)) - -#ifdef MODE32 -#define LSRegRHS ((BITS (4, 11) == 0) ? state->Reg[RHSReg] \ - : GetLSRegRHS (state, instr)) -#else -#define LSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetLSRegRHS (state, instr)) -#endif - -#define LSMNumRegs ((ARMword) ARMul_BitList[BITS (0, 7)] + \ - (ARMword) ARMul_BitList[BITS (8, 15)] ) -#define LSMBaseFirst ((LHSReg == 0 && BIT (0)) || \ - (BIT (LHSReg) && BITS (0, LHSReg - 1) == 0)) - -#define SWAPSRC (state->Reg[RHSReg]) - -#define LSCOff (BITS (0, 7) << 2) -#define CPNum BITS (8, 11) - -/* Determine if access to coprocessor CP is permitted. - The XScale has a register in CP15 which controls access to CP0 - CP13. */ -//chy 2003-09-03, new CP_ACCESS_ALLOWED -/* -#define CP_ACCESS_ALLOWED(STATE, CP) \ - ( ((CP) >= 14) \ - || (! (STATE)->is_XScale) \ - || (read_cp15_reg (15, 0, 1) & (1 << (CP)))) -*/ -//#define CP_ACCESS_ALLOWED(STATE, CP) \ -// (((CP) >= 14) \ -// || (!(STATE)->is_XScale) \ -// || (xscale_cp15_cp_access_allowed(STATE, 15, CP))) - -#define CP_ACCESS_ALLOWED(STATE, CP) false // Disabled coprocessor shit /bunnei - -/* Macro to rotate n right by b bits. */ -#define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) - -/* Macros to store results of instructions. */ -#define WRITEDEST(d) \ - do \ - { \ - if (DESTReg == 15) \ - WriteR15 (state, d); \ - else \ - DEST = d; \ - } \ - while (0) - -#define WRITESDEST(d) \ - do \ - { \ - if (DESTReg == 15) \ - WriteSR15 (state, d); \ - else \ - { \ - DEST = d; \ - ARMul_NegZero (state, d); \ - } \ - } \ - while (0) - -#define WRITEDESTB(d) \ - do \ - { \ - if (DESTReg == 15){ \ - WriteR15Branch (state, d); \ - } \ - else{ \ - DEST = d; \ - } \ - } \ - while (0) - -#define BYTETOBUS(data) ((data & 0xff) | \ - ((data & 0xff) << 8) | \ - ((data & 0xff) << 16) | \ - ((data & 0xff) << 24)) - -#define BUSTOBYTE(address, data) \ - do \ - { \ - if (state->bigendSig) \ - temp = (data >> (((address ^ 3) & 3) << 3)) & 0xff; \ - else \ - temp = (data >> ((address & 3) << 3)) & 0xff; \ - } \ - while (0) - -#define LOADMULT(instr, address, wb) LoadMult (state, instr, address, wb) -#define LOADSMULT(instr, address, wb) LoadSMult (state, instr, address, wb) -#define STOREMULT(instr, address, wb) StoreMult (state, instr, address, wb) -#define STORESMULT(instr, address, wb) StoreSMult (state, instr, address, wb) - -#define POSBRANCH ((instr & 0x7fffff) << 2) -#define NEGBRANCH ((0xff000000 |(instr & 0xffffff)) << 2) - - -/* Values for Emulate. */ -#define STOP 0 /* stop */ -#define CHANGEMODE 1 /* change mode */ -#define ONCE 2 /* execute just one interation */ -#define RUN 3 /* continuous execution */ - -/* Stuff that is shared across modes. */ -extern unsigned ARMul_MultTable[]; /* Number of I cycles for a mult. */ -extern ARMword ARMul_ImmedTable[]; /* Immediate DP LHS values. */ -extern char ARMul_BitList[]; /* Number of bits in a byte table. */ - -#define EVENTLISTSIZE 1024L - -/* Thumb support. */ -typedef enum -{ - t_undefined, /* Undefined Thumb instruction. */ - t_decoded, /* Instruction decoded to ARM equivalent. */ - t_branch /* Thumb branch (already processed). */ -} -tdstate; - -/********************************************************************************* - * Check all the possible undef or unpredict behavior, Some of them probably is - * out-of-updated with the newer ISA. - * -- Michael.Kang - ********************************************************************************/ -#define UNDEF_WARNING ERROR_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n"); - -/* Macros to scrutinize instructions. */ -#define UNDEF_Test UNDEF_WARNING -//#define UNDEF_Test - -//#define UNDEF_Shift UNDEF_WARNING -#define UNDEF_Shift - -//#define UNDEF_MSRPC UNDEF_WARNING -#define UNDEF_MSRPC - -//#define UNDEF_MRSPC UNDEF_WARNING -#define UNDEF_MRSPC - -#define UNDEF_MULPCDest UNDEF_WARNING -//#define UNDEF_MULPCDest - -#define UNDEF_MULDestEQOp1 UNDEF_WARNING -//#define UNDEF_MULDestEQOp1 - -//#define UNDEF_LSRBPC UNDEF_WARNING -#define UNDEF_LSRBPC - -//#define UNDEF_LSRBaseEQOffWb UNDEF_WARNING -#define UNDEF_LSRBaseEQOffWb - -//#define UNDEF_LSRBaseEQDestWb UNDEF_WARNING -#define UNDEF_LSRBaseEQDestWb - -//#define UNDEF_LSRPCBaseWb UNDEF_WARNING -#define UNDEF_LSRPCBaseWb - -//#define UNDEF_LSRPCOffWb UNDEF_WARNING -#define UNDEF_LSRPCOffWb - -//#define UNDEF_LSMNoRegs UNDEF_WARNING -#define UNDEF_LSMNoRegs - -//#define UNDEF_LSMPCBase UNDEF_WARNING -#define UNDEF_LSMPCBase - -//#define UNDEF_LSMUserBankWb UNDEF_WARNING -#define UNDEF_LSMUserBankWb - -//#define UNDEF_LSMBaseInListWb UNDEF_WARNING -#define UNDEF_LSMBaseInListWb - -#define UNDEF_SWPPC UNDEF_WARNING -//#define UNDEF_SWPPC - -#define UNDEF_CoProHS UNDEF_WARNING -//#define UNDEF_CoProHS - -#define UNDEF_MCRPC UNDEF_WARNING -//#define UNDEF_MCRPC - -//#define UNDEF_LSCPCBaseWb UNDEF_WARNING -#define UNDEF_LSCPCBaseWb - -#define UNDEF_UndefNotBounced UNDEF_WARNING -//#define UNDEF_UndefNotBounced - -#define UNDEF_ShortInt UNDEF_WARNING -//#define UNDEF_ShortInt - -#define UNDEF_IllegalMode UNDEF_WARNING -//#define UNDEF_IllegalMode - -#define UNDEF_Prog32SigChange UNDEF_WARNING -//#define UNDEF_Prog32SigChange - -#define UNDEF_Data32SigChange UNDEF_WARNING -//#define UNDEF_Data32SigChange - -/* Prototypes for exported functions. */ -extern unsigned ARMul_NthReg (ARMword, unsigned); -extern int AddOverflow (ARMword, ARMword, ARMword); -extern int SubOverflow (ARMword, ARMword, ARMword); -/* Prototypes for exported functions. */ -#ifdef __cplusplus - extern "C" { -#endif -extern ARMword ARMul_Emulate26 (ARMul_State *); -extern ARMword ARMul_Emulate32 (ARMul_State *); -#ifdef __cplusplus - } -#endif -extern unsigned IntPending (ARMul_State *); -extern void ARMul_CPSRAltered (ARMul_State *); -extern void ARMul_R15Altered (ARMul_State *); -extern ARMword ARMul_GetPC (ARMul_State *); -extern ARMword ARMul_GetNextPC (ARMul_State *); -extern ARMword ARMul_GetR15 (ARMul_State *); -extern ARMword ARMul_GetCPSR (ARMul_State *); -extern void ARMul_EnvokeEvent (ARMul_State *); -extern unsigned int ARMul_Time (ARMul_State *); -extern void ARMul_NegZero (ARMul_State *, ARMword); -extern void ARMul_SetPC (ARMul_State *, ARMword); -extern void ARMul_SetR15 (ARMul_State *, ARMword); -extern void ARMul_SetCPSR (ARMul_State *, ARMword); -extern ARMword ARMul_GetSPSR (ARMul_State *, ARMword); -extern void ARMul_Abort26 (ARMul_State *, ARMword); -extern void ARMul_Abort32 (ARMul_State *, ARMword); -extern ARMword ARMul_MRC (ARMul_State *, ARMword); -extern void ARMul_MRRC (ARMul_State *, ARMword, ARMword *, ARMword *); -extern void ARMul_CDP (ARMul_State *, ARMword); -extern void ARMul_LDC (ARMul_State *, ARMword, ARMword); -extern void ARMul_STC (ARMul_State *, ARMword, ARMword); -extern void ARMul_MCR (ARMul_State *, ARMword, ARMword); -extern void ARMul_MCRR (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_SetSPSR (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_Align (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); -extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); -extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); -extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); -extern ARMword ARMul_GetReg (ARMul_State *, unsigned, unsigned); -extern void ARMul_SetReg (ARMul_State *, unsigned, unsigned, ARMword); -extern void ARMul_ScheduleEvent (ARMul_State *, unsigned int, - unsigned (*)(ARMul_State *)); -/* Coprocessor support functions. */ -extern unsigned 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); -extern ARMword read_cp15_reg (unsigned, unsigned, unsigned); - -extern unsigned DSPLDC4 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMCR4 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC4 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPSTC4 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP4 (ARMul_State *, unsigned, ARMword); -extern unsigned DSPMCR5 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC5 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPLDC5 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPSTC5 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP5 (ARMul_State *, unsigned, ARMword); -extern unsigned DSPMCR6 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC6 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP6 (ARMul_State *, unsigned, ARMword); - - -#endif diff --git a/src/core/src/arm/interpreter/arminit.cpp b/src/core/src/arm/interpreter/arminit.cpp deleted file mode 100644 index f48232ee..00000000 --- a/src/core/src/arm/interpreter/arminit.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/* arminit.c -- ARMulator initialization: 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. */ - - -#include "platform.h" -#if EMU_PLATFORM == PLATFORM_LINUX -#include -#endif - -#include - -#include "armdefs.h" -#include "armemu.h" - -/***************************************************************************\ -* Definitions for the emulator architecture * -\***************************************************************************/ - -void ARMul_EmulateInit (void); -ARMul_State *ARMul_NewState (ARMul_State * state); -void ARMul_Reset (ARMul_State * state); -ARMword ARMul_DoCycle (ARMul_State * state); -unsigned ARMul_DoCoPro (ARMul_State * state); -ARMword ARMul_DoProg (ARMul_State * state); -ARMword ARMul_DoInstr (ARMul_State * state); -void ARMul_Abort (ARMul_State * state, ARMword address); - -unsigned ARMul_MultTable[32] = - { 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16 -}; -ARMword ARMul_ImmedTable[4096]; /* immediate DP LHS values */ -char ARMul_BitList[256]; /* number of bits in a byte table */ - -//chy 2006-02-22 add test debugmode -extern int debugmode; -extern int remote_interrupt( void ); - - -void arm_dyncom_Abort(ARMul_State * state, ARMword vector) -{ - ARMul_Abort(state, vector); -} - - -/* ahe-ykl : the following code to initialize user mode - code is architecture dependent and probably model dependant. */ - -//#include "skyeye_arch.h" -//#include "skyeye_pref.h" -//#include "skyeye_exec_info.h" -//#include "bank_defs.h" -#include "armcpu.h" -//#include "skyeye_callback.h" - -//void arm_user_mode_init(generic_arch_t * arch_instance) -//{ -// sky_pref_t *pref = get_skyeye_pref(); -// -// if (pref->user_mode_sim) -// { -// sky_exec_info_t *info = get_skyeye_exec_info(); -// info->arch_page_size = 0x1000; -// info->arch_stack_top = 0x1ffffff0;// + 0x401fe7 - 0xff0; /* arbitrary value */ -// /* stack initial address specific to architecture may be placed here */ -// -// /* we need to mmap the stack space, if we are using skyeye space */ -// if (info->mmap_access) -// { -// /* get system stack size */ -// size_t stacksize = 0; -// pthread_attr_t attr; -// pthread_attr_init(&attr); -// pthread_attr_getstacksize(&attr, &stacksize); -// if (stacksize > info->arch_stack_top) -// { -// printf("arch_stack_top is too low\n"); -// stacksize = info->arch_stack_top; -// } -// -// /* Note: Skyeye is occupating 0x400000 to 0x600000 */ -// /* We do a mmap */ -// void* ret = mmap( (info->arch_stack_top) - stacksize, -// stacksize + 0x1000 , PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); -// if (ret == MAP_FAILED){ -// /* ideally, we should find an empty space until it works */ -// printf("mmap error, stack couldn't be mapped: errno %d\n", errno); -// exit(-1); -// } else { -// memset(ret, '\0', stacksize); -// //printf("stack top has been defined at %x size %x\n", (uint32_t) ret + stacksize, stacksize); -// //info->arch_stack_top = (uint32_t) ret + stacksize; -// } -// } -// -// exec_stack_init(); -// -// ARM_CPU_State* cpu = get_current_cpu(); -// arm_core_t* core = &cpu->core[0]; -// -// uint32_t sp = info->initial_sp; -// -// core->Cpsr = 0x10; /* User mode */ -// /* FIXME: may need to add thumb */ -// core->Reg[13] = sp; -// core->Reg[10] = info->start_data; -// core->Reg[0] = 0; -// bus_read(32, sp + 4, &(core->Reg[1])); -// bus_read(32, sp + 8, &(core->Reg[2])); -// } -// -//} - -/***************************************************************************\ -* Call this routine once to set up the emulator's tables. * -\***************************************************************************/ - -void -ARMul_EmulateInit (void) -{ - unsigned int i, j; - - for (i = 0; i < 4096; i++) { /* the values of 12 bit dp rhs's */ - ARMul_ImmedTable[i] = ROTATER (i & 0xffL, (i >> 7L) & 0x1eL); - } - - for (i = 0; i < 256; ARMul_BitList[i++] = 0); /* how many bits in LSM */ - for (j = 1; j < 256; j <<= 1) - for (i = 0; i < 256; i++) - if ((i & j) > 0) - ARMul_BitList[i]++; - - for (i = 0; i < 256; i++) - ARMul_BitList[i] *= 4; /* you always need 4 times these values */ - -} - -/***************************************************************************\ -* Returns a new instantiation of the ARMulator's state * -\***************************************************************************/ - -ARMul_State * -ARMul_NewState (ARMul_State *state) -{ - unsigned i, j; - - memset (state, 0, sizeof (ARMul_State)); - - state->Emulate = RUN; - for (i = 0; i < 16; i++) { - state->Reg[i] = 0; - for (j = 0; j < 7; j++) - state->RegBank[j][i] = 0; - } - for (i = 0; i < 7; i++) - state->Spsr[i] = 0; - state->Mode = 0; - - state->CallDebug = FALSE; - state->Debug = FALSE; - state->VectorCatch = 0; - state->Aborted = FALSE; - state->Reseted = FALSE; - state->Inted = 3; - state->LastInted = 3; - - state->CommandLine = NULL; - - state->EventSet = 0; - state->Now = 0; - state->EventPtr = - (struct EventNode **) malloc ((unsigned) EVENTLISTSIZE * - sizeof (struct EventNode *)); -#if DIFF_STATE - state->state_log = fopen("/data/state.log", "w"); - printf("create pc log file.\n"); -#endif - if (state->EventPtr == NULL) { - printf ("SKYEYE: ARMul_NewState malloc state->EventPtr error\n"); - exit(-1); - } - for (i = 0; i < EVENTLISTSIZE; i++) - *(state->EventPtr + i) = NULL; -#if SAVE_LOG - state->state_log = fopen("/tmp/state.log", "w"); - printf("create pc log file.\n"); -#else -#if DIFF_LOG - state->state_log = fopen("/tmp/state.log", "r"); - printf("loaded pc log file.\n"); -#endif -#endif - -#ifdef ARM61 - state->prog32Sig = LOW; - state->data32Sig = LOW; -#else - state->prog32Sig = HIGH; - state->data32Sig = HIGH; -#endif - - state->lateabtSig = HIGH; - state->bigendSig = LOW; - - //chy:2003-08-19 - state->LastTime = 0; - state->CP14R0_CCD = -1; - - /* ahe-ykl: common function for interpret and dyncom */ - //sky_pref_t *pref = get_skyeye_pref(); - //if (pref->user_mode_sim) - // register_callback(arm_user_mode_init, Bootmach_callback); - - memset(&state->exclusive_tag_array[0], 0xFF, sizeof(state->exclusive_tag_array[0]) * 128); - state->exclusive_access_state = 0; - //state->cpu = (cpu_config_t *) malloc (sizeof (cpu_config_t)); - //state->mem_bank = (mem_config_t *) malloc (sizeof (mem_config_t)); - return (state); -} - -/***************************************************************************\ -* Call this routine to set ARMulator to model a certain processor * -\***************************************************************************/ - -void -ARMul_SelectProcessor (ARMul_State * state, unsigned properties) -{ - if (properties & ARM_Fix26_Prop) { - state->prog32Sig = LOW; - state->data32Sig = LOW; - } - else { - state->prog32Sig = HIGH; - state->data32Sig = HIGH; - } -/* 2004-05-09 chy -below line sould be in skyeye_mach_XXX.c 's XXX_mach_init function -*/ - // state->lateabtSig = HIGH; - - - state->is_v4 = - (properties & (ARM_v4_Prop | ARM_v5_Prop)) ? HIGH : LOW; - state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW; - state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW; - state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW; - state->is_iWMMXt = (properties & ARM_iWMMXt_Prop) ? HIGH : LOW; - /* state->is_v6 = LOW */; - /* jeff.du 2010-08-05 */ - state->is_v6 = (properties & ARM_v6_Prop) ? HIGH : LOW; - state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW; - //chy 2005-09-19 - state->is_pxa27x = (properties & ARM_PXA27X_Prop) ? HIGH : LOW; - - /* shenoubang 2012-3-11 */ - state->is_v7 = (properties & ARM_v7_Prop) ? HIGH : LOW; - - /* Only initialse the coprocessor support once we - know what kind of chip we are dealing with. */ - //ARMul_CoProInit (state); Commented out /bunnei - -} - -/***************************************************************************\ -* Call this routine to set up the initial machine state (or perform a RESET * -\***************************************************************************/ - -void -ARMul_Reset (ARMul_State * state) -{ - //fprintf(stderr,"armul_reset 0: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - state->NextInstr = 0; - if (state->prog32Sig) { - state->Reg[15] = 0; - state->Cpsr = INTBITS | SVC32MODE; - state->Mode = SVC32MODE; - } - else { - state->Reg[15] = R15INTBITS | SVC26MODE; - state->Cpsr = INTBITS | SVC26MODE; - state->Mode = SVC26MODE; - } - //fprintf(stderr,"armul_reset 1: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - ARMul_CPSRAltered (state); - state->Bank = SVCBANK; - FLUSHPIPE; - - state->EndCondition = 0; - state->ErrorCode = 0; - - //fprintf(stderr,"armul_reset 2: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - 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; - state->NumNcycles = 0; - state->NumScycles = 0; - state->NumIcycles = 0; - state->NumCcycles = 0; - state->NumFcycles = 0; - - //fprintf(stderr,"armul_reset 3: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - //mmu_reset (state); Commented out /bunnei - //fprintf(stderr,"armul_reset 4: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - - //mem_reset (state); /* move to memory/ram.c */ - - //fprintf(stderr,"armul_reset 5: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - /*remove later. walimis 03.7.17 */ - //io_reset(state); - //lcd_disable(state); - - /*ywc 2005-04-07 move from ARMul_NewState , because skyeye_config.no_dbct will - *be configured in skyeye_option_init and it is called after ARMul_NewState*/ - state->tea_break_ok = 0; - state->tea_break_addr = 0; - state->tea_pc = 0; -#ifdef DBCT - if (!skyeye_config.no_dbct) { - //teawater add for arm2x86 2005.02.14------------------------------------------- - if (arm2x86_init (state)) { - printf ("SKYEYE: arm2x86_init error\n"); - skyeye_exit (-1); - } - //AJ2D-------------------------------------------------------------------------- - } -#endif -} - - -/***************************************************************************\ -* Emulate the execution of an entire program. Start the correct emulator * -* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * -* address of the last instruction that is executed. * -\***************************************************************************/ - -//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- -#ifdef DBCT_TEST_SPEED -static ARMul_State *dbct_test_speed_state = NULL; -static void -dbct_test_speed_sig(int signo) -{ - printf("\n0x%llx %llu\n", dbct_test_speed_state->instr_count, dbct_test_speed_state->instr_count); - skyeye_exit(0); -} -#endif //DBCT_TEST_SPEED -//AJ2D-------------------------------------------------------------------------- - -ARMword -ARMul_DoProg (ARMul_State * state) -{ - ARMword pc = 0; - - /* - * 2007-01-24 removed the term-io functions by Anthony Lee, - * moved to "device/uart/skyeye_uart_stdio.c". - */ - -//teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- -#ifdef DBCT_TEST_SPEED - { - if (!dbct_test_speed_state) { - //init timer - struct itimerval value; - struct sigaction act; - - dbct_test_speed_state = state; - state->instr_count = 0; - act.sa_handler = dbct_test_speed_sig; - act.sa_flags = SA_RESTART; - //cygwin don't support ITIMER_VIRTUAL or ITIMER_PROF -#ifndef __CYGWIN__ - if (sigaction(SIGVTALRM, &act, NULL) == -1) { -#else - if (sigaction(SIGALRM, &act, NULL) == -1) { -#endif //__CYGWIN__ - fprintf(stderr, "init timer error.\n"); - skyeye_exit(-1); - } - if (skyeye_config.dbct_test_speed_sec) { - value.it_value.tv_sec = skyeye_config.dbct_test_speed_sec; - } - else { - value.it_value.tv_sec = DBCT_TEST_SPEED_SEC; - } - printf("dbct_test_speed_sec = %ld\n", value.it_value.tv_sec); - value.it_value.tv_usec = 0; - value.it_interval.tv_sec = 0; - value.it_interval.tv_usec = 0; -#ifndef __CYGWIN__ - if (setitimer(ITIMER_VIRTUAL, &value, NULL) == -1) { -#else - if (setitimer(ITIMER_REAL, &value, NULL) == -1) { -#endif //__CYGWIN__ - fprintf(stderr, "init timer error.\n"); - skyeye_exit(-1); - } - } - } -#endif //DBCT_TEST_SPEED -//AJ2D-------------------------------------------------------------------------- - state->Emulate = RUN; - while (state->Emulate != STOP) { - state->Emulate = RUN; - - /*ywc 2005-03-31 */ - if (state->prog32Sig && ARMul_MODE32BIT) { -#ifdef DBCT - if (skyeye_config.no_dbct) { - pc = ARMul_Emulate32 (state); - } - else { - pc = ARMul_Emulate32_dbct (state); - } -#else - pc = ARMul_Emulate32 (state); -#endif - } - - else { - _dbg_assert_msg_(ARM11, false, "Unsupported ARM 26-bit Mode!"); - } - //chy 2006-02-22, should test debugmode first - //chy 2006-04-14, put below codes in ARMul_Emulate -#if 0 - if(debugmode) - if(remote_interrupt()) - state->Emulate = STOP; -#endif - } - - /* - * 2007-01-24 removed the term-io functions by Anthony Lee, - * moved to "device/uart/skyeye_uart_stdio.c". - */ - - return (pc); -} - -/***************************************************************************\ -* Emulate the execution of one instruction. Start the correct emulator * -* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * -* address of the instruction that is executed. * -\***************************************************************************/ - -ARMword -ARMul_DoInstr (ARMul_State * state) -{ - ARMword pc = 0; - - state->Emulate = ONCE; - - /*ywc 2005-03-31 */ - if (state->prog32Sig && ARMul_MODE32BIT) { -#ifdef DBCT - if (skyeye_config.no_dbct) { - pc = ARMul_Emulate32 (state); - } - else { -//teawater add compile switch for DBCT GDB RSP function 2005.10.21-------------- -#ifndef DBCT_GDBRSP - printf("DBCT GDBRSP function switch is off.\n"); - printf("To use this function, open \"#define DBCT_GDBRSP\" in arch/arm/common/armdefs.h & recompile skyeye.\n"); - skyeye_exit(-1); -#endif //DBCT_GDBRSP -//AJ2D-------------------------------------------------------------------------- - pc = ARMul_Emulate32_dbct (state); - } -#else - pc = ARMul_Emulate32 (state); -#endif - } - - else { - _dbg_assert_msg_(ARM11, false, "Unsupported ARM 26-bit Mode!"); - } - - return (pc); -} - -/***************************************************************************\ -* This routine causes an Abort to occur, including selecting the correct * -* mode, register bank, and the saving of registers. Call with the * -* appropriate vector's memory address (0,4,8 ....) * -\***************************************************************************/ - -void -ARMul_Abort (ARMul_State * state, ARMword vector) -{ - ARMword temp; - int isize = INSN_SIZE; - int esize = (TFLAG ? 0 : 4); - int e2size = (TFLAG ? -4 : 0); - - state->Aborted = FALSE; - - if (state->prog32Sig) - if (ARMul_MODE26BIT) - temp = R15PC; - else - temp = state->Reg[15]; - else - temp = R15PC | ECC | ER15INT | EMODE; - - switch (vector) { - case ARMul_ResetV: /* RESET */ - SETABORT (INTBITS, state->prog32Sig ? SVC32MODE : SVC26MODE, - 0); - break; - case ARMul_UndefinedInstrV: /* Undefined Instruction */ - SETABORT (IBIT, state->prog32Sig ? UNDEF32MODE : SVC26MODE, - isize); - break; - case ARMul_SWIV: /* Software Interrupt */ - SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE, - isize); - break; - case ARMul_PrefetchAbortV: /* Prefetch Abort */ - state->AbortAddr = 1; - SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, - esize); - break; - case ARMul_DataAbortV: /* Data Abort */ - SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, - e2size); - break; - case ARMul_AddrExceptnV: /* Address Exception */ - SETABORT (IBIT, SVC26MODE, isize); - break; - case ARMul_IRQV: /* IRQ */ - //chy 2003-09-02 the if sentence seems no use -#if 0 - if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) - || (temp & ARMul_CP13_R0_IRQ)) -#endif - SETABORT (IBIT, - state->prog32Sig ? IRQ32MODE : IRQ26MODE, - esize); - break; - case ARMul_FIQV: /* FIQ */ - //chy 2003-09-02 the if sentence seems no use -#if 0 - if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) - || (temp & ARMul_CP13_R0_FIQ)) -#endif - SETABORT (INTBITS, - state->prog32Sig ? FIQ32MODE : FIQ26MODE, - esize); - break; - } - - if (ARMul_MODE32BIT) { - if (state->mmu.control & CONTROL_VECTOR) - vector += 0xffff0000; //for v4 high exception address - if (state->vector_remap_flag) - vector += state->vector_remap_addr; /* support some remap function in LPC processor */ - ARMul_SetR15 (state, vector); - } - else - ARMul_SetR15 (state, R15CCINTMODE | vector); -} diff --git a/src/core/src/arm/interpreter/armmmu.cpp b/src/core/src/arm/interpreter/armmmu.cpp deleted file mode 100644 index 242e6a83..00000000 --- a/src/core/src/arm/interpreter/armmmu.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - armmmu.c - Memory Management Unit emulation. - ARMulator extensions for the ARM7100 family. - Copyright (C) 1999 Ben Williamson - - 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 -#include -#include "armdefs.h" -/* two header for arm disassemble */ -//#include "skyeye_arch.h" -#include "armcpu.h" - - -extern mmu_ops_t xscale_mmu_ops; -exception_t arm_mmu_write(short size, u32 addr, uint32_t *value); -exception_t arm_mmu_read(short size, u32 addr, uint32_t *value); -#define MMU_OPS (state->mmu.ops) -ARMword skyeye_cachetype = -1; - -int -mmu_init (ARMul_State * state) -{ - int ret; - - state->mmu.control = 0x70; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - - switch (state->cpu->cpu_val & state->cpu->cpu_mask) { - //case SA1100: - //case SA1110: - // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n"); - // state->mmu.ops = sa_mmu_ops; - // break; - //case PXA250: - //case PXA270: //xscale - // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n"); - // state->mmu.ops = xscale_mmu_ops; - // break; - //case 0x41807200: //arm720t - //case 0x41007700: //arm7tdmi - //case 0x41007100: //arm7100 - // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n"); - // state->mmu.ops = arm7100_mmu_ops; - // break; - //case 0x41009200: - // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n"); - // state->mmu.ops = arm920t_mmu_ops; - // break; - //case 0x41069260: - // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n"); - // state->mmu.ops = arm926ejs_mmu_ops; - // break; - /* case 0x560f5810: */ - case 0x0007b000: - NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n"); - state->mmu.ops = arm1176jzf_s_mmu_ops; - break; - - default: - ERROR_LOG (ARM11, - "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n", - state->cpu->cpu_val & state->cpu->cpu_mask); - break; - - }; - ret = state->mmu.ops.init (state); - state->mmu_inited = (ret == 0); - /* initialize mmu_read and mmu_write for disassemble */ - //skyeye_config_t *config = get_current_config(); - //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); - //arch_instance->mmu_read = arm_mmu_read; - //arch_instance->mmu_write = arm_mmu_write; - - return ret; -} - -int -mmu_reset (ARMul_State * state) -{ - if (state->mmu_inited) - mmu_exit (state); - return mmu_init (state); -} - -void -mmu_exit (ARMul_State * state) -{ - MMU_OPS.exit (state); - state->mmu_inited = 0; -} - -fault_t -mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_byte (state, virt_addr, data); -}; - -fault_t -mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_halfword (state, virt_addr, data); -}; - -fault_t -mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_word (state, virt_addr, data); -}; - -fault_t -mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - //static int count = 0; - //count ++; - fault = MMU_OPS.write_byte (state, virt_addr, data); - return fault; -} - -fault_t -mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - //static int count = 0; - //count ++; - fault = MMU_OPS.write_halfword (state, virt_addr, data); - return fault; -} - -fault_t -mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - fault = MMU_OPS.write_word (state, virt_addr, data); - - /*used for debug for MMU* - - if (!fault){ - ARMword tmp; - - if (mmu_read_word(state, virt_addr, &tmp)){ - err_msg("load back\n"); - exit(-1); - }else{ - if (tmp != data){ - err_msg("load back not equal %d %x\n", count, virt_addr); - } - } - } - */ - - return fault; -}; - -fault_t -mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr) -{ - return MMU_OPS.load_instr (state, virt_addr, instr); -} - -ARMword -mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) -{ - return MMU_OPS.mrc (state, instr, value); -} - -void -mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) -{ - MMU_OPS.mcr (state, instr, value); -} - -/*ywc 20050416*/ -int -mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) -{ - return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr)); -} - -// -// -///* dis_mmu_read for disassemble */ -//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value) -//{ -// ARMul_State *state; -// ARM_CPU_State *cpu = get_current_cpu(); -// state = &cpu->core[0]; -// switch(size){ -// case 8: -// MMU_OPS.read_byte (state, addr, value); -// break; -// case 16: -// case 32: -// break; -// default: -// ERROR_LOG(ARM11, "Error size %d", size); -// break; -// } -// return No_exp; -//} -///* dis_mmu_write for disassemble */ -//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value) -//{ -// ARMul_State *state; -// ARM_CPU_State *cpu = get_current_cpu(); -// state = &cpu->core[0]; -// switch(size){ -// case 8: -// MMU_OPS.write_byte (state, addr, value); -// break; -// case 16: -// case 32: -// break; -// default: -// printf("In %s error size %d Line %d\n", __func__, size, __LINE__); -// break; -// } -// return No_exp; -//} diff --git a/src/core/src/arm/interpreter/armmmu.h b/src/core/src/arm/interpreter/armmmu.h deleted file mode 100644 index c28d8753..00000000 --- a/src/core/src/arm/interpreter/armmmu.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - armmmu.c - Memory Management Unit emulation. - ARMulator extensions for the ARM7100 family. - Copyright (C) 1999 Ben Williamson - - 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 -*/ - -#ifndef _ARMMMU_H_ -#define _ARMMMU_H_ - - -#define WORD_SHT 2 -#define WORD_SIZE (1<mmu.control) -#define MMU_Enabled (state->mmu.control & CONTROL_MMU) -#define MMU_Disabled (!(MMU_Enabled)) -#define MMU_Aligned (state->mmu.control & CONTROL_ALIGN_FAULT) - -#define MMU_ICacheEnabled (MMU_CTL & CONTROL_INSTRUCTION_CACHE) -#define MMU_ICacheDisabled (!(MMU_ICacheDisabled)) - -#define MMU_DCacheEnabled (MMU_CTL & CONTROL_DATA_CACHE) -#define MMU_DCacheDisabled (!(MMU_DCacheEnabled)) - -#define MMU_CacheEnabled (MMU_CTL & CONTROL_CACHE) -#define MMU_CacheDisabled (!(MMU_CacheEnabled)) - -#define MMU_WBEnabled (MMU_CTL & CONTROL_WRITE_BUFFER) -#define MMU_WBDisabled (!(MMU_WBEnabled)) - -/*virt_addr exchange according to CP15.R13(process id virtul mapping)*/ -#define PID_VA_MAP_MASK 0xfe000000 -//#define mmu_pid_va_map(va) ({\ -// ARMword ret; \ -// if ((va) & PID_VA_MAP_MASK)\ -// ret = (va); \ -// else \ -// ret = ((va) | (state->mmu.process_id & PID_VA_MAP_MASK));\ -// ret;\ -//}) -#define mmu_pid_va_map(va) ((va) & PID_VA_MAP_MASK) ? (va) : ((va) | (state->mmu.process_id & PID_VA_MAP_MASK)) - -/* FS[3:0] in the fault status register: */ - -typedef enum fault_t -{ - NO_FAULT = 0x0, - ALIGNMENT_FAULT = 0x1, - - SECTION_TRANSLATION_FAULT = 0x5, - PAGE_TRANSLATION_FAULT = 0x7, - SECTION_DOMAIN_FAULT = 0x9, - PAGE_DOMAIN_FAULT = 0xB, - SECTION_PERMISSION_FAULT = 0xD, - SUBPAGE_PERMISSION_FAULT = 0xF, - - /* defined by skyeye */ - TLB_READ_MISS = 0x30, - TLB_WRITE_MISS = 0x40, - -} fault_t; - -typedef struct mmu_ops_s -{ - /*initilization */ - int (*init) (ARMul_State * state); - /*free on exit */ - void (*exit) (ARMul_State * state); - /*read byte data */ - fault_t (*read_byte) (ARMul_State * state, ARMword va, - ARMword * data); - /*write byte data */ - fault_t (*write_byte) (ARMul_State * state, ARMword va, - ARMword data); - /*read halfword data */ - fault_t (*read_halfword) (ARMul_State * state, ARMword va, - ARMword * data); - /*write halfword data */ - fault_t (*write_halfword) (ARMul_State * state, ARMword va, - ARMword data); - /*read word data */ - fault_t (*read_word) (ARMul_State * state, ARMword va, - ARMword * data); - /*write word data */ - fault_t (*write_word) (ARMul_State * state, ARMword va, - ARMword data); - /*load instr */ - fault_t (*load_instr) (ARMul_State * state, ARMword va, - ARMword * instr); - /*mcr */ - ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val); - /*mrc */ - ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val); - - /*ywc 2005-04-16 convert virtual address to physics address */ - int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr, - ARMword * phys_addr); -} mmu_ops_t; - - -#include "arm/mmu/tlb.h" -#include "arm/mmu/rb.h" -#include "arm/mmu/wb.h" -#include "arm/mmu/cache.h" - -/*special process mmu.h*/ -//#include "arm/mmu/sa_mmu.h" -//#include "arm/mmu/arm7100_mmu.h" -//#include "arm/mmu/arm920t_mmu.h" -//#include "arm/mmu/arm926ejs_mmu.h" -#include "arm/mmu/arm1176jzf_s_mmu.h" -//#include "arm/mmu/cortex_a9_mmu.h" - -typedef struct mmu_state_t -{ - ARMword control; - ARMword translation_table_base; -/* dyf 201-08-11 for arm1176 */ - ARMword auxiliary_control; - ARMword coprocessor_access_control; - ARMword translation_table_base0; - ARMword translation_table_base1; - ARMword translation_table_ctrl; -/* arm1176 end */ - - ARMword domain_access_control; - ARMword fault_status; - ARMword fault_statusi; /* prefetch fault status */ - ARMword fault_address; - ARMword last_domain; - ARMword process_id; - ARMword context_id; - ARMword thread_uro_id; - ARMword cache_locked_down; - ARMword tlb_locked_down; -//chy 2003-08-24 for xscale - ARMword cache_type; // 0 - ARMword aux_control; // 1 - ARMword copro_access; // 15 - - mmu_ops_t ops; - //union - //{ - //sa_mmu_t sa_mmu; - //arm7100_mmu_t arm7100_mmu; - //arm920t_mmu_t arm920t_mmu; - //arm926ejs_mmu_t arm926ejs_mmu; - //} u; -} mmu_state_t; - -int mmu_init (ARMul_State * state); -int mmu_reset (ARMul_State * state); -void mmu_exit (ARMul_State * state); - -fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr, - ARMword * data); -fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr, - ARMword * instr); - -ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); -void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); - -/*ywc 20050416*/ -int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, - ARMword * phys_addr); - -fault_t -mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t -mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t -mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); -#endif /* _ARMMMU_H_ */ diff --git a/src/core/src/arm/interpreter/armos.cpp b/src/core/src/arm/interpreter/armos.cpp deleted file mode 100644 index 43484ee5..00000000 --- a/src/core/src/arm/interpreter/armos.cpp +++ /dev/null @@ -1,742 +0,0 @@ -/* armos.c -- ARMulator OS interface: 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. */ - -/* This file contains a model of Demon, ARM Ltd's Debug Monitor, -including all the SWI's required to support the C library. The code in -it is not really for the faint-hearted (especially the abort handling -code), but it is a complete example. Defining NOOS will disable all the -fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI -0x11 to halt the emulator. */ - -//chy 2005-09-12 disable below line -//#include "config.h" - -#include -#include -#include -#include "skyeye_defs.h" -#ifndef __USE_LARGEFILE64 -#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/ -#endif -#include -#include - - -#ifndef O_RDONLY -#define O_RDONLY 0 -#endif -#ifndef O_WRONLY -#define O_WRONLY 1 -#endif -#ifndef O_RDWR -#define O_RDWR 2 -#endif -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifdef __STDC__ -#define unlink(s) remove(s) -#endif - -#ifdef HAVE_UNISTD_H -#include /* For SEEK_SET etc */ -#endif - -#ifdef __riscos -extern int _fisatty (FILE *); -#define isatty_(f) _fisatty(f) -#else -#ifdef __ZTC__ -#include -#define isatty_(f) isatty((f)->_file) -#else -#ifdef macintosh -#include -#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL)) -#else -#define isatty_(f) isatty (fileno (f)) -#endif -#endif -#endif - -#include "armdefs.h" -#include "armos.h" -#include "armemu.h" - -#ifndef NOOS -#ifndef VALIDATE -/* #ifndef ASIM */ -//chy 2005-09-12 disable below line -//#include "armfpe.h" -/* #endif */ -#endif -#endif - -#define DUMP_SYSCALL 0 -#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0) -//#define debug(...) printf(__VA_ARGS__); -#define debug(...) ; - -extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); - -#ifndef FOPEN_MAX -#define FOPEN_MAX 64 -#endif - -/***************************************************************************\ -* OS private Information * -\***************************************************************************/ - -unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number) -{ - return ARMul_OSHandleSWI(state, number); -} - -//mmap_area_t *mmap_global = NULL; - -static int translate_open_mode[] = { - O_RDONLY, /* "r" */ - O_RDONLY + O_BINARY, /* "rb" */ - O_RDWR, /* "r+" */ - O_RDWR + O_BINARY, /* "r+b" */ - O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ - O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ - O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ - O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ - O_WRONLY + O_APPEND + O_CREAT, /* "a" */ - O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ - O_RDWR + O_APPEND + O_CREAT, /* "a+" */ - O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ -}; -// -//static void -//SWIWrite0 (ARMul_State * state, ARMword addr) -//{ -// ARMword temp; -// -// //while ((temp = ARMul_ReadByte (state, addr++)) != 0) -// while(1){ -// mem_read(8, addr++, &temp); -// if(temp != 0) -// (void) fputc ((char) temp, stdout); -// else -// break; -// } -//} -// -//static void -//WriteCommandLineTo (ARMul_State * state, ARMword addr) -//{ -// ARMword temp; -// char *cptr = state->CommandLine; -// if (cptr == NULL) -// cptr = "\0"; -// do { -// temp = (ARMword) * cptr++; -// //ARMul_WriteByte (state, addr++, temp); -// mem_write(8, addr++, temp); -// } -// while (temp != 0); -//} -// -//static void -//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) -//{ -// char dummy[2000]; -// int flags; -// int i; -// -// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++); -// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0]))); -// /* Now we need to decode the Demon open mode */ -// flags = translate_open_mode[SWIflags]; -// flags = SWIflags; -// -// /* Filename ":tt" is special: it denotes stdin/out */ -// if (strcmp (dummy, ":tt") == 0) { -// if (flags == O_RDONLY) /* opening tty "r" */ -// state->Reg[0] = 0; /* stdin */ -// else -// state->Reg[0] = 1; /* stdout */ -// } -// else { -// state->Reg[0] = (int) open (dummy, flags, 0666); -// } -//} -// -//static void -//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) -//{ -// int res; -// int i; -// char *local = (char*) malloc (len); -// -// if (local == NULL) { -// fprintf (stderr, -// "sim: Unable to read 0x%ulx bytes - out of memory\n", -// len); -// return; -// } -// -// res = read (f, local, len); -// if (res > 0) -// for (i = 0; i < res; i++) -// //ARMul_WriteByte (state, ptr + i, local[i]); -// mem_write(8, ptr + i, local[i]); -// free (local); -// //state->Reg[0] = res == -1 ? -1 : len - res; -// state->Reg[0] = res; -//} -// -//static void -//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) -//{ -// int res; -// ARMword i; -// char *local = malloc (len); -// -// if (local == NULL) { -// fprintf (stderr, -// "sim: Unable to write 0x%lx bytes - out of memory\n", -// (long unsigned int) len); -// return; -// } -// -// for (i = 0; i < len; i++){ -// //local[i] = ARMul_ReadByte (state, ptr + i); -// ARMword data; -// mem_read(8, ptr + i, &data); -// local[i] = data & 0xFF; -// } -// -// res = write (f, local, len); -// //state->Reg[0] = res == -1 ? -1 : len - res; -// state->Reg[0] = res; -// free (local); -//} - -//static void -//SWIflen (ARMul_State * state, ARMword fh) -//{ -// ARMword addr; -// -// if (fh == 0 || fh > FOPEN_MAX) { -// state->Reg[0] = -1L; -// return; -// } -// -// addr = lseek (fh, 0, SEEK_CUR); -// -// state->Reg[0] = lseek (fh, 0L, SEEK_END); -// (void) lseek (fh, addr, SEEK_SET); -// -//} - -/***************************************************************************\ -* The emulator calls this routine when a SWI instruction is encuntered. The * -* parameter passed is the SWI number (lower 24 bits of the instruction). * -\***************************************************************************/ -/* ahe-ykl information is retrieved from elf header and the starting value of - brk_static is in sky_info_t */ - -/* brk static hold the value of brk */ -static uint32_t brk_static = -1; - -unsigned -ARMul_OSHandleSWI (ARMul_State * state, ARMword number) -{ - number &= 0xfffff; - ARMword addr, temp; - - switch (number) { -// case SWI_Syscall: -// if (state->Reg[7] != 0) -// return ARMul_OSHandleSWI(state, state->Reg[7]); -// else -// return FALSE; -// case SWI_Read: -// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); -// return TRUE; -// -// case SWI_GetUID32: -// state->Reg[0] = getuid(); -// return TRUE; -// -// case SWI_GetGID32: -// state->Reg[0] = getgid(); -// return TRUE; -// -// case SWI_GetEUID32: -// state->Reg[0] = geteuid(); -// return TRUE; -// -// case SWI_GetEGID32: -// state->Reg[0] = getegid(); -// return TRUE; -// -// case SWI_Write: -// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); -// return TRUE; -// -// case SWI_Open: -// SWIopen (state, state->Reg[0], state->Reg[1]); -// return TRUE; -// -// case SWI_Close: -// state->Reg[0] = close (state->Reg[0]); -// return TRUE; -// -// case SWI_Seek:{ -// /* We must return non-zero for failure */ -// state->Reg[0] = -// lseek (state->Reg[0], state->Reg[1], -// SEEK_SET); -// return TRUE; -// } -// -// case SWI_ExitGroup: -// case SWI_Exit: -// { -// struct timeval tv; -// //gettimeofday(&tv,NULL); -// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec); -// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us()); -// -// /* quit here */ -// run_command("quit"); -// return TRUE; -// } -// case SWI_Times:{ -// uint32_t dest = state->Reg[0]; -// struct tms now; -// struct target_tms32 nowret; -// -// uint32_t ret = times(&now); -// -// if (ret == -1){ -// debug("syscall %s error %d\n", "SWI_Times", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// nowret.tms_cstime = now.tms_cstime; -// nowret.tms_cutime = now.tms_cutime; -// nowret.tms_stime = now.tms_stime; -// nowret.tms_utime = now.tms_utime; -// -// uint32_t offset; -// for (offset = 0; offset < sizeof(nowret); offset++) { -// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset)); -// } -// -// state->Reg[0] = ret; -// return TRUE; -// } -// -// case SWI_Gettimeofday: { -// uint32_t dest1 = state->Reg[0]; -// uint32_t dest2 = state->Reg[1]; // Unsure of this -// struct timeval val; -// struct timezone zone; -// struct target_timeval32 valret; -// struct target_timezone32 zoneret; -// -// uint32_t ret = gettimeofday(&val, &zone); -// valret.tv_sec = val.tv_sec; -// valret.tv_usec = val.tv_usec; -// zoneret.tz_dsttime = zoneret.tz_dsttime; -// zoneret.tz_minuteswest = zoneret.tz_minuteswest; -// -// if (ret == -1){ -// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// uint32_t offset; -// if (dest1) { -// for (offset = 0; offset < sizeof(valret); offset++) { -// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset)); -// } -// state->Reg[0] = ret; -// } -// if (dest2) { -// for (offset = 0; offset < sizeof(zoneret); offset++) { -// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset)); -// } -// state->Reg[0] = ret; -// } -// -// return TRUE; -// } -// case SWI_Brk: -// /* initialize brk value */ -// /* suppose that brk_static doesn't reach 0xffffffff... */ -// if (brk_static == -1) { -// brk_static = (get_skyeye_pref()->info).brk; -// } -// -// /* FIXME there might be a need to do a mmap */ -// -// if(state->Reg[0]){ -// if (get_skyeye_exec_info()->mmap_access) { -// /* if new brk is greater than current brk, allocate memory */ -// if (state->Reg[0] > brk_static) { -// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static, -// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 ); -// if (ret != MAP_FAILED) -// brk_static = ret; -// } -// } -// brk_static = state->Reg[0]; -// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */ -// } else { -// state->Reg[0] = brk_static; -// } -// return TRUE; -// -// case SWI_Break: -// state->Emulate = FALSE; -// return TRUE; -// -// case SWI_Mmap:{ -// int addr = state->Reg[0]; -// int len = state->Reg[1]; -// int prot = state->Reg[2]; -// int flag = state->Reg[3]; -// int fd = state->Reg[4]; -// int offset = state->Reg[5]; -// mmap_area_t *area = new_mmap_area(addr, len); -// state->Reg[0] = area->bank.addr; -// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\ -// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]); -// return TRUE; -// } -// -// case SWI_Munmap: -// state->Reg[0] = 0; -// return TRUE; -// -// case SWI_Mmap2:{ -// int addr = state->Reg[0]; -// int len = state->Reg[1]; -// int prot = state->Reg[2]; -// int flag = state->Reg[3]; -// int fd = state->Reg[4]; -// int offset = state->Reg[5] * 4096; /* page offset */ -// mmap_area_t *area = new_mmap_area(addr, len); -// state->Reg[0] = area->bank.addr; -// -// return TRUE; -// } -// -// case SWI_Breakpoint: -// //chy 2005-09-12 change below line -// //state->EndCondition = RDIError_BreakpointReached; -// //printf ("SKYEYE: in armos.c : should not come here!!!!\n"); -// state->EndCondition = 0; -// /*modified by ksh to support breakpoiont*/ -// state->Emulate = STOP; -// return (TRUE); -// case SWI_Uname: -// { -// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */ -// struct utsname utsbuf; -// //printf("Uname size is %x\n", sizeof(utsbuf)); -// char *buf; -// uintptr_t sp ; /* used as a temporary address */ -// -//#define COPY_UTS_STRING(addr) \ -// buf = addr; \ -// while(*buf != NULL) { \ -// bus_write(8, sp, *buf); \ -// sp++; \ -// buf++; \ -// } -//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \ -// sp = (uintptr_t) uts->field; \ -// COPY_UTS_STRING((&utsbuf)->field); -// -// if (uname(&utsbuf) < 0) { -// printf("syscall uname: utsname error\n"); -// state->Reg[0] = -1; -// return FALSE; -// } -// -// /* FIXME for now, this is just the host system call -// Some data should be missing, as it depends on -// the version of utsname */ -// COPY_UTS(sysname); -// COPY_UTS(nodename); -// COPY_UTS(release); -// COPY_UTS(version); -// COPY_UTS(machine); -// -// state->Reg[0] = 0; -// return TRUE; -// } -// case SWI_Fcntl: -// { -// uint32_t fd = state->Reg[0]; -// uint32_t cmd = state->Reg[1]; -// uint32_t arg = state->Reg[2]; -// uint32_t ret; -// -// switch(cmd){ -// case (F_GETFD): -// { -// ret = fcntl(fd, cmd, arg); -// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// default: -// break; -// } -// -// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd); -// state->Reg[0] = -1; -// return FALSE; -// -// } -// case SWI_Fstat64: -// { -// uint32_t dest = state->Reg[1]; -// uint32_t fd = state->Reg[0]; -// struct stat64 statbuf; -// struct target_stat64 statret; -// memset(&statret, 0, sizeof(struct target_stat64)); -// uint32_t ret = fstat64(fd, &statbuf); -// -// if (ret == -1){ -// printf("syscall %s returned error\n", "SWI_Fstat"); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// /* copy statbuf to the process memory space -// FIXME can't say if endian has an effect here */ -// uint32_t offset; -// //printf("Fstat system is size %x\n", sizeof(statbuf)); -// //printf("Fstat target is size %x\n", sizeof(statret)); -// -// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */ -// statret.st_dev = statbuf.st_dev; -// statret.st_ino = statbuf.st_ino; -// statret.st_mode = statbuf.st_mode; -// statret.st_nlink = statbuf.st_nlink; -// statret.st_uid = statbuf.st_uid; -// statret.st_gid = statbuf.st_gid; -// statret.st_rdev = statbuf.st_rdev; -// statret.st_size = statbuf.st_size; -// statret.st_blksize = statbuf.st_blksize; -// statret.st_blocks = statbuf.st_blocks; -// statret.st32_atime = statbuf.st_atime; -// statret.st32_mtime = statbuf.st_mtime; -// statret.st32_ctime = statbuf.st_ctime; -// -// for (offset = 0; offset < sizeof(statret); offset++) { -// bus_write(8, dest + offset, *((uint8_t *) &statret + offset)); -// } -// -// state->Reg[0] = ret; -// return TRUE; -// } -// case SWI_Set_tls: -// { -// //printf("syscall set_tls unimplemented\n"); -// state->mmu.thread_uro_id = state->Reg[0]; -// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0]; -// state->Reg[0] = 0; -// return FALSE; -// } -//#if 0 -// case SWI_Clock: -// /* return number of centi-seconds... */ -// state->Reg[0] = -//#ifdef CLOCKS_PER_SEC -// (CLOCKS_PER_SEC >= 100) -// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) -// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); -//#else -// /* presume unix... clock() returns microseconds */ -// (ARMword) (clock () / 10000); -//#endif -// return (TRUE); -// -// case SWI_Time: -// state->Reg[0] = (ARMword) time (NULL); -// return (TRUE); -// case SWI_Flen: -// SWIflen (state, state->Reg[0]); -// return (TRUE); -// -//#endif - default: - - _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!"); - - return (FALSE); - } -} -// -///** -// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc. -// */ -//static mmap_area_t* new_mmap_area(int sim_addr, int len){ -// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t)); -// if(area == NULL){ -// printf("error, failed %s\n",__FUNCTION__); -// exit(0); -// } -//#if FAST_MEMORY -// if (mmap_next_base == -1) -// { -// mmap_next_base = get_skyeye_exec_info()->brk; -// } -//#endif -// -// memset(area, 0x0, sizeof(mmap_area_t)); -// area->bank.addr = mmap_next_base; -// area->bank.len = len; -// area->bank.bank_write = mmap_mem_write; -// area->bank.bank_read = mmap_mem_read; -// area->bank.type = MEMTYPE_RAM; -// area->bank.objname = "mmap"; -// addr_mapping(&area->bank); -// -//#if FAST_MEMORY -// if (get_skyeye_exec_info()->mmap_access) -// { -// /* FIXME check proper flags */ -// /* FIXME we may delete the need of banks up there */ -// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -// mmap_next_base = ret; -// } -// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base); -//#else -// area->mmap_addr = malloc(len); -// if(area->mmap_addr == NULL){ -// printf("error mmap malloc\n"); -// exit(0); -// } -// memset(area->mmap_addr, 0x0, len); -//#endif -// -// area->next = NULL; -// if(mmap_global){ -// area->next = mmap_global->next; -// mmap_global->next = area; -// }else{ -// mmap_global = area; -// } -// mmap_next_base = mmap_next_base + len; -// return area; -//} -// -//static mmap_area_t *get_mmap_area(int addr){ -// mmap_area_t *tmp = mmap_global; -// while(tmp){ -// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){ -// return tmp; -// } -// tmp = tmp->next; -// } -// printf("cannot get mmap area:addr=0x%x\n", addr); -// return NULL; -//} -// -///** -// * @brief the mmap_area bank write function. Get from ppc. -// * -// * @param size size to write, 8/16/32 -// * @param addr address to write -// * @param value value to write -// * -// * @return sucess return 1,otherwise 0. -// */ -//static char mmap_mem_write(short size, int addr, uint32_t value){ -// mmap_area_t *area_tmp = get_mmap_area(addr); -// mem_bank_t *bank_tmp = &area_tmp->bank; -// int offset = addr - bank_tmp->addr; -// switch(size){ -// case 8:{ -// //uint8_t value_endian = value; -// uint8_t value_endian = (uint8_t)value; -// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// case 16:{ -// //uint16_t value_endian = half_to_BE((uint16_t)value); -// uint16_t value_endian = ((uint16_t)value); -// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// case 32:{ -// //uint32_t value_endian = word_to_BE((uint32_t)value); -// uint32_t value_endian = ((uint32_t)value); -// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// default: -// printf("invalid size %d\n",size); -// return 0; -// } -// return 1; -//} -// -///** -// * @brief the mmap_area bank read function. Get from ppc. -// * -// * @param size size to read, 8/16/32 -// * @param addr address to read -// * @param value value to read -// * -// * @return sucess return 1,otherwise 0. -// */ -//static char mmap_mem_read(short size, int addr, uint32_t * value){ -// mmap_area_t *area_tmp = get_mmap_area(addr); -// mem_bank_t *bank_tmp = &area_tmp->bank; -// int offset = addr - bank_tmp->addr; -// switch(size){ -// case 8:{ -// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); -// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); -// break; -// } -// case 16:{ -// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value); -// break; -// } -// case 32: -// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); -// break; -// default: -// printf("invalid size %d\n",size); -// return 0; -// } -// return 1; -//} diff --git a/src/core/src/arm/interpreter/armos.h b/src/core/src/arm/interpreter/armos.h deleted file mode 100644 index 4b58801a..00000000 --- a/src/core/src/arm/interpreter/armos.h +++ /dev/null @@ -1,138 +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. */ - -//#include "bank_defs.h" -//#include "dyncom/defines.h" - -//typedef struct mmap_area{ -// mem_bank_t bank; -// void *mmap_addr; -// struct mmap_area *next; -//}mmap_area_t; - -#if FAST_MEMORY -/* in user mode, mmap_base will be on initial brk, - set at the first mmap request */ -#define mmap_base -1 -#else -#define mmap_base 0x50000000 -#endif -static long mmap_next_base = mmap_base; - -//static mmap_area_t* new_mmap_area(int sim_addr, int len); -static char mmap_mem_write(short size, int addr, uint32_t value); -static char mmap_mem_read(short size, int addr, uint32_t * value); - -/***************************************************************************\ -* 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 - -#if 0 -#define SWI_Time 0xd -#define SWI_Clock 0x61 -#define SWI_Time 0x63 -#define SWI_Remove 0x64 -#define SWI_Rename 0x65 -#define SWI_Flen 0x6c -#endif - -#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 */ - -/***************************************************************************\ -* SWI structures * -\***************************************************************************/ - -/* Arm binaries (for now) only support 32 bit, and expect to receive - 32-bit compliant structure in return of a systen call. Because - we use host system calls to emulate system calls, the returned - structure can be 32-bit compliant or 64-bit compliant, depending - on the OS running skyeye. Therefore, we need a fixed size structure - adapted to arm.*/ - -/* Borrowed from qemu */ -struct target_stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; - uint32_t __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - uint32_t st_uid; - uint32_t st_gid; - unsigned short st_rdev; - unsigned char __pad3[10]; - unsigned char __pad31[4]; - long long st_size; - uint32_t st_blksize; - unsigned char __pad32[4]; - uint32_t st_blocks; - uint32_t __pad4; - uint32_t st32_atime; - uint32_t __pad5; - uint32_t st32_mtime; - uint32_t __pad6; - uint32_t st32_ctime; - uint32_t __pad7; - unsigned long long st_ino; -};// __attribute__((packed)); - -struct target_tms32 { - uint32_t tms_utime; - uint32_t tms_stime; - uint32_t tms_cutime; - uint32_t tms_cstime; -}; - -struct target_timeval32 { - uint32_t tv_sec; /* seconds */ - uint32_t tv_usec; /* microseconds */ -}; - -struct target_timezone32 { - int32_t tz_minuteswest; /* minutes west of Greenwich */ - int32_t tz_dsttime; /* type of DST correction */ -}; - diff --git a/src/core/src/arm/interpreter/armsupp.cpp b/src/core/src/arm/interpreter/armsupp.cpp deleted file mode 100644 index a0c866c1..00000000 --- a/src/core/src/arm/interpreter/armsupp.cpp +++ /dev/null @@ -1,954 +0,0 @@ -/* armsupp.c -- ARMulator support code: 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. */ - -#include "armdefs.h" -#include "armemu.h" -//#include "ansidecl.h" -#include "skyeye_defs.h" -unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum); -//extern int skyeye_instr_debug; -/* Definitions for the support routines. */ - -static ARMword ModeToBank (ARMword); -static void EnvokeList (ARMul_State *, unsigned int, unsigned int); - -struct EventNode -{ /* An event list node. */ - unsigned (*func) (ARMul_State *); /* The function to call. */ - struct EventNode *next; -}; - -/* This routine returns the value of a register from a mode. */ - -ARMword -ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg) -{ - mode &= MODEBITS; - if (mode != state->Mode) - return (state->RegBank[ModeToBank ((ARMword) mode)][reg]); - else - return (state->Reg[reg]); -} - -/* This routine sets the value of a register for a mode. */ - -void -ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value) -{ - mode &= MODEBITS; - if (mode != state->Mode) - state->RegBank[ModeToBank ((ARMword) mode)][reg] = value; - else - state->Reg[reg] = value; -} - -/* This routine returns the value of the PC, mode independently. */ - -ARMword -ARMul_GetPC (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return state->Reg[15]; - else - return R15PC; -} - -/* This routine returns the value of the PC, mode independently. */ - -ARMword -ARMul_GetNextPC (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return state->Reg[15] + isize; - else - return (state->Reg[15] + isize) & R15PCBITS; -} - -/* This routine sets the value of the PC. */ - -void -ARMul_SetPC (ARMul_State * state, ARMword value) -{ - if (ARMul_MODE32BIT) - state->Reg[15] = value & PCBITS; - else - state->Reg[15] = R15CCINTMODE | (value & R15PCBITS); - FLUSHPIPE; -} - -/* This routine returns the value of register 15, mode independently. */ - -ARMword -ARMul_GetR15 (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return (state->Reg[15]); - else - return (R15PC | ECC | ER15INT | EMODE); -} - -/* This routine sets the value of Register 15. */ - -void -ARMul_SetR15 (ARMul_State * state, ARMword value) -{ - if (ARMul_MODE32BIT) - state->Reg[15] = value & PCBITS; - else { - state->Reg[15] = value; - ARMul_R15Altered (state); - } - FLUSHPIPE; -} - -/* This routine returns the value of the CPSR. */ - -ARMword -ARMul_GetCPSR (ARMul_State * state) -{ - //chy 2003-08-20: below is from gdb20030716, maybe isn't suitable for system simulator - //return (CPSR | state->Cpsr); for gdb20030716 - // NOTE(bunnei): Changed this from [now] commented out macro "CPSR" - return ((ECC | EINT | EMODE | (TFLAG << 5))); //had be tested in old skyeye with gdb5.0-5.3 -} - -/* This routine sets the value of the CPSR. */ - -void -ARMul_SetCPSR (ARMul_State * state, ARMword value) -{ - state->Cpsr = value; - ARMul_CPSRAltered (state); -} - -/* This routine does all the nasty bits involved in a write to the CPSR, - including updating the register bank, given a MSR instruction. */ - -void -ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs) -{ - state->Cpsr = ARMul_GetCPSR (state); - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { - /* In user mode, only write flags. */ - if (BIT (16)) - SETPSR_C (state->Cpsr, rhs); - if (BIT (17)) - SETPSR_X (state->Cpsr, rhs); - if (BIT (18)) - SETPSR_S (state->Cpsr, rhs); - } - if (BIT (19)) - SETPSR_F (state->Cpsr, rhs); - ARMul_CPSRAltered (state); -} - -/* Get an SPSR from the specified mode. */ - -ARMword -ARMul_GetSPSR (ARMul_State * state, ARMword mode) -{ - ARMword bank = ModeToBank (mode & MODEBITS); - - if (!BANK_CAN_ACCESS_SPSR (bank)) - return ARMul_GetCPSR (state); - - return state->Spsr[bank]; -} - -/* This routine does a write to an SPSR. */ - -void -ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) -{ - ARMword bank = ModeToBank (mode & MODEBITS); - - if (BANK_CAN_ACCESS_SPSR (bank)) - state->Spsr[bank] = value; -} - -/* This routine does a write to the current SPSR, given an MSR instruction. */ - -void -ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs) -{ - if (BANK_CAN_ACCESS_SPSR (state->Bank)) { - if (BIT (16)) - SETPSR_C (state->Spsr[state->Bank], rhs); - if (BIT (17)) - SETPSR_X (state->Spsr[state->Bank], rhs); - if (BIT (18)) - SETPSR_S (state->Spsr[state->Bank], rhs); - if (BIT (19)) - SETPSR_F (state->Spsr[state->Bank], rhs); - } -} - -/* This routine updates the state of the emulator after the Cpsr has been - changed. Both the processor flags and register bank are updated. */ - -void -ARMul_CPSRAltered (ARMul_State * state) -{ - ARMword oldmode; - - if (state->prog32Sig == LOW) - state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS); - - oldmode = state->Mode; - - if (state->Mode != (state->Cpsr & MODEBITS)) { - state->Mode = - ARMul_SwitchMode (state, state->Mode, - state->Cpsr & MODEBITS); - - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - } - //state->Cpsr &= ~MODEBITS; - - ASSIGNINT (state->Cpsr & INTBITS); - //state->Cpsr &= ~INTBITS; - ASSIGNN ((state->Cpsr & NBIT) != 0); - //state->Cpsr &= ~NBIT; - ASSIGNZ ((state->Cpsr & ZBIT) != 0); - //state->Cpsr &= ~ZBIT; - ASSIGNC ((state->Cpsr & CBIT) != 0); - //state->Cpsr &= ~CBIT; - ASSIGNV ((state->Cpsr & VBIT) != 0); - //state->Cpsr &= ~VBIT; - ASSIGNS ((state->Cpsr & SBIT) != 0); - //state->Cpsr &= ~SBIT; -#ifdef MODET - ASSIGNT ((state->Cpsr & TBIT) != 0); - //state->Cpsr &= ~TBIT; -#endif - - if (oldmode > SVC26MODE) { - if (state->Mode <= SVC26MODE) { - state->Emulate = CHANGEMODE; - state->Reg[15] = ECC | ER15INT | EMODE | R15PC; - } - } - else { - if (state->Mode > SVC26MODE) { - state->Emulate = CHANGEMODE; - state->Reg[15] = R15PC; - } - else - state->Reg[15] = ECC | ER15INT | EMODE | R15PC; - } -} - -/* This routine updates the state of the emulator after register 15 has - been changed. Both the processor flags and register bank are updated. - This routine should only be called from a 26 bit mode. */ - -void -ARMul_R15Altered (ARMul_State * state) -{ - if (state->Mode != R15MODE) { - state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE); - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - } - - if (state->Mode > SVC26MODE) - state->Emulate = CHANGEMODE; - - ASSIGNR15INT (R15INT); - - ASSIGNN ((state->Reg[15] & NBIT) != 0); - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); - ASSIGNC ((state->Reg[15] & CBIT) != 0); - ASSIGNV ((state->Reg[15] & VBIT) != 0); -} - -/* This routine controls the saving and restoring of registers across mode - changes. The regbank matrix is largely unused, only rows 13 and 14 are - used across all modes, 8 to 14 are used for FIQ, all others use the USER - column. It's easier this way. old and new parameter are modes numbers. - Notice the side effect of changing the Bank variable. */ - -ARMword -ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode) -{ - unsigned i; - ARMword oldbank; - ARMword newbank; - static int revision_value = 53; - - oldbank = ModeToBank (oldmode); - newbank = state->Bank = ModeToBank (newmode); - - /* Do we really need to do it? */ - if (oldbank != newbank) { - if (oldbank == 3 && newbank == 2) { - //printf("icounter is %d PC is %x MODE CHANGED : %d --> %d\n", state->NumInstrs, state->pc, oldbank, newbank); - if (state->NumInstrs >= 5832487) { -// printf("%d, ", state->NumInstrs + revision_value); -// printf("revision_value : %d\n", revision_value); - revision_value ++; - } - } - /* Save away the old registers. */ - switch (oldbank) { - case USERBANK: - case IRQBANK: - case SVCBANK: - case ABORTBANK: - case UNDEFBANK: - if (newbank == FIQBANK) - for (i = 8; i < 13; i++) - state->RegBank[USERBANK][i] = - state->Reg[i]; - state->RegBank[oldbank][13] = state->Reg[13]; - state->RegBank[oldbank][14] = state->Reg[14]; - break; - case FIQBANK: - for (i = 8; i < 15; i++) - state->RegBank[FIQBANK][i] = state->Reg[i]; - break; - case DUMMYBANK: - for (i = 8; i < 15; i++) - state->RegBank[DUMMYBANK][i] = 0; - break; - default: - abort (); - } - - /* Restore the new registers. */ - switch (newbank) { - case USERBANK: - case IRQBANK: - case SVCBANK: - case ABORTBANK: - case UNDEFBANK: - if (oldbank == FIQBANK) - for (i = 8; i < 13; i++) - state->Reg[i] = - state->RegBank[USERBANK][i]; - state->Reg[13] = state->RegBank[newbank][13]; - state->Reg[14] = state->RegBank[newbank][14]; - break; - case FIQBANK: - for (i = 8; i < 15; i++) - state->Reg[i] = state->RegBank[FIQBANK][i]; - break; - case DUMMYBANK: - for (i = 8; i < 15; i++) - state->Reg[i] = 0; - break; - default: - abort (); - } - } - - return newmode; -} - -/* Given a processor mode, this routine returns the - register bank that will be accessed in that mode. */ - -static ARMword -ModeToBank (ARMword mode) -{ - static ARMword bankofmode[] = { - USERBANK, FIQBANK, IRQBANK, SVCBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - USERBANK, FIQBANK, IRQBANK, SVCBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK - }; - - if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0]))) - return DUMMYBANK; - - return bankofmode[mode]; -} - -/* Returns the register number of the nth register in a reg list. */ - -unsigned -ARMul_NthReg (ARMword instr, unsigned number) -{ - unsigned bit, upto; - - for (bit = 0, upto = 0; upto <= number; bit++) - if (BIT (bit)) - upto++; - - return (bit - 1); -} - -/* Assigns the N and Z flags depending on the value of result. */ - -void -ARMul_NegZero (ARMul_State * state, ARMword result) -{ - if (NEG (result)) { - SETN; - CLEARZ; - } - else if (result == 0) { - CLEARN; - SETZ; - } - else { - CLEARN; - CLEARZ; - } -} - -/* Compute whether an addition of A and B, giving RESULT, overflowed. */ - -int -AddOverflow (ARMword a, ARMword b, ARMword result) -{ - return ((NEG (a) && NEG (b) && POS (result)) - || (POS (a) && POS (b) && NEG (result))); -} - -/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */ - -int -SubOverflow (ARMword a, ARMword b, ARMword result) -{ - return ((NEG (a) && POS (b) && POS (result)) - || (POS (a) && NEG (b) && NEG (result))); -} - -/* Assigns the C flag after an addition of a and b to give result. */ - -void -ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNC ((NEG (a) && NEG (b)) || - (NEG (a) && POS (result)) || (NEG (b) && POS (result))); -} - -/* Assigns the V flag after an addition of a and b to give result. */ - -void -ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNV (AddOverflow (a, b, result)); -} - -/* Assigns the C flag after an subtraction of a and b to give result. */ - -void -ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNC ((NEG (a) && POS (b)) || - (NEG (a) && POS (result)) || (POS (b) && POS (result))); -} - -/* Assigns the V flag after an subtraction of a and b to give result. */ - -void -ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNV (SubOverflow (a, b, result)); -} - -/* This function does the work of generating the addresses used in an - LDC instruction. The code here is always post-indexed, it's up to the - caller to get the input address correct and to handle base register - modification. It also handles the Busy-Waiting. */ - -void -ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address) -{ - unsigned cpab; - ARMword data; - - UNDEF_LSCPCBaseWb; - //printf("SKYEYE ARMul_LDC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); -/*chy 2004-05-23 should update this function in the future,should concern dataabort*/ -// chy 2004-05-25 , fix it now,so needn't printf -// printf("SKYEYE ARMul_LDC, should update this function!!!!!\n"); - //exit(-1); - - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - /* - printf - ("SKYEYE ARMul_LDC,NOT ALLOW, underinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - ARMul_UndefInstr (state, instr); - return; - } - - if (ADDREXCEPT (address)) - INTERNALABORT (address); - - cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } - else - cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, - 0); - } - if (cpab == ARMul_CANT) { - /* - printf - ("SKYEYE ARMul_LDC,NOT CAN, underinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - CPTAKEABORT; - return; - } - - cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0); - data = ARMul_LoadWordN (state, address); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_ldc_takeabort; - - BUSUSEDINCPCN; -//chy 2004-05-25 -/* - if (BIT (21)) - LSBase = state->Base; -*/ - - cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); - - while (cpab == ARMul_INC) { - address += 4; - data = ARMul_LoadWordN (state, address); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_ldc_takeabort; - - cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); - } - -//chy 2004-05-25 - L_ldc_takeabort: - if (BIT (21)) { - if (! - ((state->abortSig || state->Aborted) - && state->lateabtSig == LOW)) - LSBase = state->Base; - } - - if (state->abortSig || state->Aborted) - TAKEABORT; -} - -/* This function does the work of generating the addresses used in an - STC instruction. The code here is always post-indexed, it's up to the - caller to get the input address correct and to handle base register - modification. It also handles the Busy-Waiting. */ - -void -ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) -{ - unsigned cpab; - ARMword data; - - UNDEF_LSCPCBaseWb; - - //printf("SKYEYE ARMul_STC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); - /*chy 2004-05-23 should update this function in the future,should concern dataabort */ -// skyeye_instr_debug=0;printf("SKYEYE debug end!!!!\n"); -// chy 2004-05-25 , fix it now,so needn't printf -// printf("SKYEYE ARMul_STC, should update this function!!!!!\n"); - - //exit(-1); - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - /* - printf - ("SKYEYE ARMul_STC,NOT ALLOW, undefinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - ARMul_UndefInstr (state, instr); - return; - } - - if (ADDREXCEPT (address) || VECTORACCESS (address)) - INTERNALABORT (address); - - cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } - else - cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, - &data); - } - - if (cpab == ARMul_CANT) { - /* - printf - ("SKYEYE ARMul_STC,CANT, undefinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - CPTAKEABORT; - return; - } -#ifndef MODE32 - if (ADDREXCEPT (address) || VECTORACCESS (address)) - INTERNALABORT (address); -#endif - BUSUSEDINCPCN; -//chy 2004-05-25 -/* - if (BIT (21)) - LSBase = state->Base; -*/ - cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); - ARMul_StoreWordN (state, address, data); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_stc_takeabort; - - while (cpab == ARMul_INC) { - address += 4; - cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); - ARMul_StoreWordN (state, address, data); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_stc_takeabort; - } -//chy 2004-05-25 - L_stc_takeabort: - if (BIT (21)) { - if (! - ((state->abortSig || state->Aborted) - && state->lateabtSig == LOW)) - LSBase = state->Base; - } - - if (state->abortSig || state->Aborted) - TAKEABORT; -} - -/* This function does the Busy-Waiting for an MCR instruction. */ - -void -ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source) -{ - unsigned cpab; - - //printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - //chy 2004-07-19 should fix in the future ????!!!! - //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); - ARMul_UndefInstr (state, instr); - return; - } - - cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); - - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } - else - cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, - source); - } - - if (cpab == ARMul_CANT) { - printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } - else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - } -} - -/* This function does the Busy-Waiting for an MCRR instruction. */ - -void -ARMul_MCRR (ARMul_State * state, ARMword instr, ARMword source1, ARMword source2) -{ - unsigned cpab; - - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - ARMul_UndefInstr (state, instr); - return; - } - - cpab = (state->MCRR[CPNum]) (state, ARMul_FIRST, instr, source1, source2); - - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->MCRR[CPNum]) (state, ARMul_INTERRUPT, - instr, 0, 0); - return; - } - else - cpab = (state->MCRR[CPNum]) (state, ARMul_BUSY, instr, - source1, source2); - } - if (cpab == ARMul_CANT) { - printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x, source %x %x\n", __FUNCTION__, CPNum, instr, source1, source2); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } - else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - } -} - -/* This function does the Busy-Waiting for an MRC instruction. */ - -ARMword -ARMul_MRC (ARMul_State * state, ARMword instr) -{ - unsigned cpab; - ARMword result = 0; - - //printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - //chy 2004-07-19 should fix in the future????!!!! - //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr); - ARMul_UndefInstr (state, instr); - return -1; - } - - cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return (0); - } - else - cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, - &result); - } - if (cpab == ARMul_CANT) { - printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); - /* Parent will destroy the flags otherwise. */ - result = ECC; - } - else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - ARMul_Icycles (state, 1, 0); - } - - return result; -} - -/* This function does the Busy-Waiting for an MRRC instruction. (to verify) */ - -void -ARMul_MRRC (ARMul_State * state, ARMword instr, ARMword * dest1, ARMword * dest2) -{ - unsigned cpab; - ARMword result1 = 0; - ARMword result2 = 0; - - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - ARMul_UndefInstr (state, instr); - return; - } - - cpab = (state->MRRC[CPNum]) (state, ARMul_FIRST, instr, &result1, &result2); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->MRRC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0, 0); - return; - } - else - cpab = (state->MRRC[CPNum]) (state, ARMul_BUSY, instr, - &result1, &result2); - } - if (cpab == ARMul_CANT) { - printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x\n", __FUNCTION__, CPNum, instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } - else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - ARMul_Icycles (state, 1, 0); - } - - *dest1 = result1; - *dest2 = result2; -} - -/* This function does the Busy-Waiting for an CDP instruction. */ - -void -ARMul_CDP (ARMul_State * state, ARMword instr) -{ - unsigned cpab; - - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - ARMul_UndefInstr (state, instr); - return; - } - cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, - instr); - return; - } - else - cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr); - } - if (cpab == ARMul_CANT) - ARMul_Abort (state, ARMul_UndefinedInstrV); - else - BUSUSEDN; -} - -/* This function handles Undefined instructions, as CP isntruction. */ - -void -ARMul_UndefInstr (ARMul_State * state, ARMword instr) -{ - ERROR_LOG(ARM11, "Undefined instruction!! Instr: 0x%x", instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); -} - -/* Return TRUE if an interrupt is pending, FALSE otherwise. */ - -unsigned -IntPending (ARMul_State * state) -{ - /* Any exceptions. */ - if (state->NresetSig == LOW) { - ARMul_Abort (state, ARMul_ResetV); - return TRUE; - } - else if (!state->NfiqSig && !FFLAG) { - ARMul_Abort (state, ARMul_FIQV); - return TRUE; - } - else if (!state->NirqSig && !IFLAG) { - ARMul_Abort (state, ARMul_IRQV); - return TRUE; - } - - return FALSE; -} - -/* Align a word access to a non word boundary. */ - -ARMword -ARMul_Align (ARMul_State *state, ARMword address, ARMword data) -{ - /* This code assumes the address is really unaligned, - as a shift by 32 is undefined in C. */ - - address = (address & 3) << 3; /* Get the word address. */ - return ((data >> address) | (data << (32 - address))); /* rot right */ -} - -/* This routine is used to call another routine after a certain number of - cycles have been executed. The first parameter is the number of cycles - delay before the function is called, the second argument is a pointer - to the function. A delay of zero doesn't work, just call the function. */ - -void -ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, - unsigned (*what) (ARMul_State *)) -{ - unsigned int when; - struct EventNode *event; - - if (state->EventSet++ == 0) - state->Now = ARMul_Time (state); - when = (state->Now + delay) % EVENTLISTSIZE; - event = (struct EventNode *) malloc (sizeof (struct EventNode)); - - _dbg_assert_msg_(ARM11, event, "SKYEYE:ARMul_ScheduleEvent: malloc event error\n"); - - event->func = what; - event->next = *(state->EventPtr + when); - *(state->EventPtr + when) = event; -} - -/* This routine is called at the beginning of - every cycle, to envoke scheduled events. */ - -void -ARMul_EnvokeEvent (ARMul_State * state) -{ - static unsigned int then; - - then = state->Now; - state->Now = ARMul_Time (state) % EVENTLISTSIZE; - if (then < state->Now) - /* Schedule events. */ - EnvokeList (state, then, state->Now); - else if (then > state->Now) { - /* Need to wrap around the list. */ - EnvokeList (state, then, EVENTLISTSIZE - 1L); - EnvokeList (state, 0L, state->Now); - } -} - -/* Envokes all the entries in a range. */ - -static void -EnvokeList (ARMul_State * state, unsigned int from, unsigned int to) -{ - for (; from <= to; from++) { - struct EventNode *anevent; - - anevent = *(state->EventPtr + from); - while (anevent) { - (anevent->func) (state); - state->EventSet--; - anevent = anevent->next; - } - *(state->EventPtr + from) = NULL; - } -} - -/* This routine is returns the number of clock ticks since the last reset. */ - -unsigned int -ARMul_Time (ARMul_State * state) -{ - return (state->NumScycles + state->NumNcycles + - state->NumIcycles + state->NumCcycles + state->NumFcycles); -} diff --git a/src/core/src/arm/interpreter/armvirt.cpp b/src/core/src/arm/interpreter/armvirt.cpp deleted file mode 100644 index a072b73b..00000000 --- a/src/core/src/arm/interpreter/armvirt.cpp +++ /dev/null @@ -1,680 +0,0 @@ -/* armvirt.c -- ARMulator virtual memory interace: 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. */ - -/* This file contains a complete ARMulator memory model, modelling a -"virtual memory" system. A much simpler model can be found in armfast.c, -and that model goes faster too, but has a fixed amount of memory. This -model's memory has 64K pages, allocated on demand from a 64K entry page -table. The routines PutWord and GetWord implement this. Pages are never -freed as they might be needed again. A single area of memory may be -defined to generate aborts. */ - -#include "armdefs.h" -#include "skyeye_defs.h" -//#include "code_cov.h" - -#ifdef VALIDATE /* for running the validate suite */ -#define TUBE 48 * 1024 * 1024 /* write a char on the screen */ -#define ABORTS 1 -#endif - -/* #define ABORTS */ - -#ifdef ABORTS /* the memory system will abort */ -/* For the old test suite Abort between 32 Kbytes and 32 Mbytes - For the new test suite Abort between 8 Mbytes and 26 Mbytes */ -/* #define LOWABORT 32 * 1024 -#define HIGHABORT 32 * 1024 * 1024 */ -#define LOWABORT 8 * 1024 * 1024 -#define HIGHABORT 26 * 1024 * 1024 - -#endif - -#define NUMPAGES 64 * 1024 -#define PAGESIZE 64 * 1024 -#define PAGEBITS 16 -#define OFFSETBITS 0xffff -//chy 2003-08-19: seems no use ???? -int SWI_vector_installed = FALSE; -extern ARMword skyeye_cachetype; - -/***************************************************************************\ -* Get a byte into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -GetByte (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; - - fault = mmu_read_byte (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: GetByte fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Get a halfword into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -GetHalfWord (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; - - fault = mmu_read_halfword (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: GetHalfWord fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Get a Word from Virtual Memory, maybe allocating the page * -\***************************************************************************/ - -static fault_t -GetWord (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; - - fault = mmu_read_word (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -#if 0 -/* XXX */ extern int hack; - hack = 1; -#endif -#if 0 - printf ("mmu_read_word at 0x%08x: ", address); - switch (fault) { - case ALIGNMENT_FAULT: - printf ("ALIGNMENT_FAULT"); - break; - case SECTION_TRANSLATION_FAULT: - printf ("SECTION_TRANSLATION_FAULT"); - break; - case PAGE_TRANSLATION_FAULT: - printf ("PAGE_TRANSLATION_FAULT"); - break; - case SECTION_DOMAIN_FAULT: - printf ("SECTION_DOMAIN_FAULT"); - break; - case SECTION_PERMISSION_FAULT: - printf ("SECTION_PERMISSION_FAULT"); - break; - case SUBPAGE_PERMISSION_FAULT: - printf ("SUBPAGE_PERMISSION_FAULT"); - break; - default: - printf ("Unrecognized fault number!"); - } - printf ("\tpc = 0x%08x\n", state->Reg[15]); -#endif - } - return fault; -} - -//2003-07-10 chy: lyh change -/****************************************************************************\ - * Load a Instrion Word into Virtual Memory * -\****************************************************************************/ -static fault_t -LoadInstr (ARMul_State * state, ARMword address, ARMword * instr) -{ - fault_t fault; - fault = mmu_load_instr (state, address, instr); - return fault; - //if (fault) - // log_msg("load_instr fault = %d, address = %x\n", fault, address); -} - -/***************************************************************************\ -* Put a byte into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -PutByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - - fault = mmu_write_byte (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: PutByte fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Put a halfword into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -PutHalfWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - - fault = mmu_write_halfword (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: PutHalfWord fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Put a Word into Virtual Memory, maybe allocating the page * -\***************************************************************************/ - -static fault_t -PutWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - - fault = mmu_write_word (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -#if 0 -/* XXX */ extern int hack; - hack = 1; -#endif -#if 0 - printf ("mmu_write_word at 0x%08x: ", address); - switch (fault) { - case ALIGNMENT_FAULT: - printf ("ALIGNMENT_FAULT"); - break; - case SECTION_TRANSLATION_FAULT: - printf ("SECTION_TRANSLATION_FAULT"); - break; - case PAGE_TRANSLATION_FAULT: - printf ("PAGE_TRANSLATION_FAULT"); - break; - case SECTION_DOMAIN_FAULT: - printf ("SECTION_DOMAIN_FAULT"); - break; - case SECTION_PERMISSION_FAULT: - printf ("SECTION_PERMISSION_FAULT"); - break; - case SUBPAGE_PERMISSION_FAULT: - printf ("SUBPAGE_PERMISSION_FAULT"); - break; - default: - printf ("Unrecognized fault number!"); - } - printf ("\tpc = 0x%08x\n", state->Reg[15]); -#endif - } - return fault; -} - -/***************************************************************************\ -* Initialise the memory interface * -\***************************************************************************/ - -unsigned -ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize) -{ - return TRUE; -} - -/***************************************************************************\ -* Remove the memory interface * -\***************************************************************************/ - -void -ARMul_MemoryExit (ARMul_State * state) -{ -} - -/***************************************************************************\ -* ReLoad Instruction * -\***************************************************************************/ - -ARMword -ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) -{ - ARMword data; - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } -#endif -#if 0 - /* do profiling for code coverage */ - if (skyeye_config.code_cov.prof_on) - cov_prof(EXEC_FLAG, address); -#endif -#if 1 - if ((isize == 2) && (address & 0x2)) { - ARMword lo, hi; - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetHalfWord (state, address, &lo); - else - fault = LoadInstr (state, address, &lo); -#if 0 - if (!fault) { - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetHalfWord (state, address + isize, &hi); - else - fault = LoadInstr (state, address + isize, &hi); - - } -#endif - if (fault) { - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - return lo; -#if 0 - if (state->bigendSig == HIGH) - return (lo << 16) | (hi >> 16); - else - return ((hi & 0xFFFF) << 16) | (lo >> 16); -#endif - } -#endif - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetWord (state, address, &data); - else - fault = LoadInstr (state, address, &data); - - if (fault) { - - /* dyf add for s3c6410 no instcache temporary 2010.9.17 */ - if (!(skyeye_cachetype == INSTCACHE)) { - /* set translation fault on prefetch abort */ - state->mmu.fault_statusi = fault & 0xFF; - state->mmu.fault_address = address; - } - /* add end */ - - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; -} - -/***************************************************************************\ -* Load Instruction, Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) -{ - state->NumScycles++; - -#ifdef HOURGLASS - if ((state->NumScycles & HOURGLASS_RATE) == 0) { - HOURGLASS; - } -#endif - - return ARMul_ReLoadInstr (state, address, isize); -} - -/***************************************************************************\ -* Load Instruction, Non Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) -{ - state->NumNcycles++; - - return ARMul_ReLoadInstr (state, address, isize); -} - -/***************************************************************************\ -* Read Word (but don't tell anyone!) * -\***************************************************************************/ - -ARMword -ARMul_ReadWord (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } -#endif - - fault = GetWord (state, address, &data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - return data; -} - -/***************************************************************************\ -* Load Word, Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadWordS (ARMul_State * state, ARMword address) -{ - state->NumScycles++; - - return ARMul_ReadWord (state, address); -} - -/***************************************************************************\ -* Load Word, Non Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadWordN (ARMul_State * state, ARMword address) -{ - state->NumNcycles++; - - return ARMul_ReadWord (state, address); -} - -/***************************************************************************\ -* Load Halfword, (Non Sequential Cycle) * -\***************************************************************************/ - -ARMword -ARMul_LoadHalfWord (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - - state->NumNcycles++; - fault = GetHalfWord (state, address, &data); - - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; - -} - -/***************************************************************************\ -* Read Byte (but don't tell anyone!) * -\***************************************************************************/ -int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult) -{ - ARMword data; - fault_t fault; - fault = GetByte (state, address, &data); - if (fault) { - *presult=-1; fault=ALIGNMENT_FAULT; return fault; - }else{ - *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault; - } -} - - -ARMword -ARMul_ReadByte (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - - fault = GetByte (state, address, &data); - - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; - -} - -/***************************************************************************\ -* Load Byte, (Non Sequential Cycle) * -\***************************************************************************/ - -ARMword -ARMul_LoadByte (ARMul_State * state, ARMword address) -{ - state->NumNcycles++; - - return ARMul_ReadByte (state, address); -} - -/***************************************************************************\ -* Write Word (but don't tell anyone!) * -\***************************************************************************/ - -void -ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } -#endif - - fault = PutWord (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } -} - -/***************************************************************************\ -* Store Word, Sequential Cycle * -\***************************************************************************/ - -void -ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumScycles++; - - ARMul_WriteWord (state, address, data); -} - -/***************************************************************************\ -* Store Word, Non Sequential Cycle * -\***************************************************************************/ - -void -ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumNcycles++; - - ARMul_WriteWord (state, address, data); -} - -/***************************************************************************\ -* Store HalfWord, (Non Sequential Cycle) * -\***************************************************************************/ - -void -ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - state->NumNcycles++; - fault = PutHalfWord (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } -} - -//chy 2006-04-15 -int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - fault = PutByte (state, address, data); - if (fault) - return 1; - else - return 0; -} -/***************************************************************************\ -* Write Byte (but don't tell anyone!) * -\***************************************************************************/ -//chy 2003-07-10, add real write byte fun -void -ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - fault = PutByte (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } -} - -/***************************************************************************\ -* Store Byte, (Non Sequential Cycle) * -\***************************************************************************/ - -void -ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumNcycles++; - -#ifdef VALIDATE - if (address == TUBE) { - if (data == 4) - state->Emulate = FALSE; - else - (void) putc ((char) data, stderr); /* Write Char */ - return; - } -#endif - - ARMul_WriteByte (state, address, data); -} - -/***************************************************************************\ -* Swap Word, (Two Non Sequential Cycles) * -\***************************************************************************/ - -ARMword -ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) -{ - ARMword temp; - - state->NumNcycles++; - - temp = ARMul_ReadWord (state, address); - - state->NumNcycles++; - - PutWord (state, address, data); - - return temp; -} - -/***************************************************************************\ -* Swap Byte, (Two Non Sequential Cycles) * -\***************************************************************************/ - -ARMword -ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) -{ - ARMword temp; - - temp = ARMul_LoadByte (state, address); - ARMul_StoreByte (state, address, data); - - return temp; -} - -/***************************************************************************\ -* Count I Cycles * -\***************************************************************************/ - -void -ARMul_Icycles (ARMul_State * state, unsigned number, - ARMword address) -{ - state->NumIcycles += number; - ARMul_CLEARABORT; -} - -/***************************************************************************\ -* Count C Cycles * -\***************************************************************************/ - -void -ARMul_Ccycles (ARMul_State * state, unsigned number, - ARMword address) -{ - state->NumCcycles += number; - ARMul_CLEARABORT; -} diff --git a/src/core/src/arm/interpreter/skyeye_defs.h b/src/core/src/arm/interpreter/skyeye_defs.h deleted file mode 100644 index 6562e595..00000000 --- a/src/core/src/arm/interpreter/skyeye_defs.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef CORE_ARM_SKYEYE_DEFS_H_ -#define CORE_ARM_SKYEYE_DEFS_H_ - -#include "common.h" - -#define MODE32 -#define MODET - -typedef struct -{ - 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; /*this cpu has what kind of cache */ -} cpu_config_t; - -typedef struct conf_object_s{ - char* objname; - void* obj; - char* class_name; -}conf_object_t; - -typedef 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 -}exception_t; - -typedef enum { - Align = 0, - UnAlign -}align_t; - -typedef enum { - Little_endian = 0, - Big_endian -}endian_t; -//typedef int exception_t; - -typedef enum{ - Phys_addr = 0, - Virt_addr -}addr_type_t; - -typedef exception_t(*read_byte_t)(conf_object_t* target, u32 addr, void *buf, size_t count); -typedef exception_t(*write_byte_t)(conf_object_t* target, u32 addr, const void *buf, size_t count); - -typedef struct memory_space{ - conf_object_t* conf_obj; - read_byte_t read; - write_byte_t write; -}memory_space_intf; - - -/* - * a running instance for a specific archteciture. - */ -typedef struct generic_arch_s -{ - char* arch_name; - void (*init) (void); - void (*reset) (void); - void (*step_once) (void); - void (*set_pc)(u32 addr); - u32 (*get_pc)(void); - u32 (*get_step)(void); - //chy 2004-04-15 - //int (*ICE_write_byte) (u32 addr, uint8_t v); - //int (*ICE_read_byte)(u32 addr, uint8_t *pv); - u32 (*get_regval_by_id)(int id); - u32 (*get_regnum)(void); - char* (*get_regname_by_id)(int id); - exception_t (*set_regval_by_id)(int id, u32 value); - /* - * read a data by virtual address. - */ - exception_t (*mmu_read)(short size, u32 addr, u32 * value); - /* - * write a data by a virtual address. - */ - exception_t (*mmu_write)(short size, u32 addr, u32 value); - /** - * get a signal from external - */ - //exception_t (*signal)(interrupt_signal_t* signal); - - endian_t endianess; - align_t alignment; -} generic_arch_t; - -#endif \ No newline at end of file diff --git a/src/core/src/arm/interpreter/thumbemu.cpp b/src/core/src/arm/interpreter/thumbemu.cpp deleted file mode 100644 index 032d84b6..00000000 --- a/src/core/src/arm/interpreter/thumbemu.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/* thumbemu.c -- Thumb instruction emulation. - Copyright (C) 1996, Cygnus Software Technologies 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. */ - -/* We can provide simple Thumb simulation by decoding the Thumb -instruction into its corresponding ARM instruction, and using the -existing ARM simulator. */ - -#include "skyeye_defs.h" - -#ifndef MODET /* required for the Thumb instruction support */ -#if 1 -#error "MODET needs to be defined for the Thumb world to work" -#else -#define MODET (1) -#endif -#endif - -#include "armdefs.h" -#include "armemu.h" -#include "armos.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 -ARMul_ThumbDecode ( - ARMul_State *state, - ARMword pc, - ARMword tinstr, - ARMword *ainstr) -{ - tdstate valid = t_decoded; /* default assumes a valid instruction */ - ARMword next_instr; - - if (state->bigendSig) { - next_instr = tinstr & 0xFFFF; - tinstr >>= 16; - } - else { - next_instr = tinstr >> 16; - tinstr &= 0xFFFF; - } - -#if 1 /* debugging to catch non updates */ - *ainstr = 0xDEADC0DE; -#endif - - switch ((tinstr & 0xF800) >> 11) { - case 0: /* LSL */ - case 1: /* LSR */ - case 2: /* ASR */ - /* Format 1 */ - *ainstr = 0xE1B00000 /* base opcode */ - | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */ - |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */ - |((tinstr & 0x0038) >> 3) /* Rs */ - |((tinstr & 0x0007) << 12); /* Rd */ - break; - case 3: /* ADD/SUB */ - /* Format 2 */ - { - ARMword subset[4] = { - 0xE0900000, /* ADDS Rd,Rs,Rn */ - 0xE0500000, /* SUBS Rd,Rs,Rn */ - 0xE2900000, /* ADDS Rd,Rs,#imm3 */ - 0xE2500000 /* SUBS Rd,Rs,#imm3 */ - }; - /* It is quicker indexing into a table, than performing switch - or conditionals: */ - *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */ - |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */ - |((tinstr & 0x0038) << (16 - 3)) /* Rs */ - |((tinstr & 0x0007) << (12 - 0)); /* Rd */ - } - break; - case 4: /* MOV */ - case 5: /* CMP */ - case 6: /* ADD */ - case 7: /* SUB */ - /* Format 3 */ - { - ARMword subset[4] = { - 0xE3B00000, /* MOVS Rd,#imm8 */ - 0xE3500000, /* CMP Rd,#imm8 */ - 0xE2900000, /* ADDS Rd,Rd,#imm8 */ - 0xE2500000, /* SUBS Rd,Rd,#imm8 */ - }; - *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */ - |((tinstr & 0x00FF) >> 0) /* imm8 */ - |((tinstr & 0x0700) << (16 - 8)) /* Rn */ - |((tinstr & 0x0700) << (12 - 8)); /* Rd */ - } - break; - case 8: /* Arithmetic and high register transfers */ - /* TODO: Since the subsets for both Format 4 and Format 5 - instructions are made up of different ARM encodings, we could - save the following conditional, and just have one large - subset. */ - if ((tinstr & (1 << 10)) == 0) { - /* Format 4 */ - enum OpcodeType { t_norm, t_shift, t_neg, t_mul }; - struct ThumbOpcode { - ARMword opcode; - OpcodeType otype; - }; - - ThumbOpcode subset[16] = { - { - 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */ - { - 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */ - { - 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */ - { - 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */ - { - 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */ - { - 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */ - { - 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */ - { - 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */ - { - 0xE1100000, t_norm}, /* TST Rd,Rs */ - { - 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */ - { - 0xE1500000, t_norm}, /* CMP Rd,Rs */ - { - 0xE1700000, t_norm}, /* CMN Rd,Rs */ - { - 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */ - { - 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */ - { - 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */ - { - 0xE1F00000, t_norm} /* MVNS Rd,Rs */ - }; - *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */ - switch (subset[(tinstr & 0x03C0) >> 6].otype) { - case t_norm: - *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */ - |((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0038) >> 3); /* Rs */ - break; - case t_shift: - *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0007) >> 0) /* Rm */ - |((tinstr & 0x0038) << (8 - 3)); /* Rs */ - break; - case t_neg: - *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)); /* Rn */ - break; - case t_mul: - *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */ - |((tinstr & 0x0007) << 8) /* Rs */ - |((tinstr & 0x0038) >> 3); /* Rm */ - break; - } - } - else { - /* Format 5 */ - ARMword Rd = ((tinstr & 0x0007) >> 0); - ARMword Rs = ((tinstr & 0x0038) >> 3); - if (tinstr & (1 << 7)) - Rd += 8; - if (tinstr & (1 << 6)) - Rs += 8; - switch ((tinstr & 0x03C0) >> 6) { - case 0x1: /* ADD Rd,Rd,Hs */ - case 0x2: /* ADD Hd,Hd,Rs */ - case 0x3: /* ADD Hd,Hd,Hs */ - *ainstr = 0xE0800000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0x5: /* CMP Rd,Hs */ - case 0x6: /* CMP Hd,Rs */ - case 0x7: /* CMP Hd,Hs */ - *ainstr = 0xE1500000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0x9: /* MOV Rd,Hs */ - case 0xA: /* MOV Hd,Rs */ - case 0xB: /* MOV Hd,Hs */ - *ainstr = 0xE1A00000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0xC: /* BX Rs */ - case 0xD: /* BX Hs */ - *ainstr = 0xE12FFF10 /* base */ - | ((tinstr & 0x0078) >> 3); /* Rd */ - break; - case 0x0: /* UNDEFINED */ - case 0x4: /* UNDEFINED */ - case 0x8: /* UNDEFINED */ - valid = t_undefined; - break; - case 0xE: /* BLX */ - case 0xF: /* BLX */ - if (state->is_v5) { - *ainstr = 0xE1200030 /* base */ - |(Rs << 0); /* Rm */ - } else { - valid = t_undefined; - } - break; - } - } - break; - case 9: /* LDR Rd,[PC,#imm8] */ - /* Format 6 */ - *ainstr = 0xE59F0000 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |((tinstr & 0x00FF) << (2 - 0)); /* off8 */ - break; - case 10: - case 11: - /* TODO: Format 7 and Format 8 perform the same ARM encoding, so - the following could be merged into a single subset, saving on - the following boolean: */ - if ((tinstr & (1 << 9)) == 0) { - /* Format 7 */ - ARMword subset[4] = { - 0xE7800000, /* STR Rd,[Rb,Ro] */ - 0xE7C00000, /* STRB Rd,[Rb,Ro] */ - 0xE7900000, /* LDR Rd,[Rb,Ro] */ - 0xE7D00000 /* LDRB Rd,[Rb,Ro] */ - }; - *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> 6); /* Ro */ - } - else { - /* Format 8 */ - ARMword subset[4] = { - 0xE18000B0, /* STRH Rd,[Rb,Ro] */ - 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */ - 0xE19000B0, /* LDRH Rd,[Rb,Ro] */ - 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */ - }; - *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> 6); /* Ro */ - } - break; - case 12: /* STR Rd,[Rb,#imm5] */ - case 13: /* LDR Rd,[Rb,#imm5] */ - case 14: /* STRB Rd,[Rb,#imm5] */ - case 15: /* LDRB Rd,[Rb,#imm5] */ - /* Format 9 */ - { - ARMword subset[4] = { - 0xE5800000, /* STR Rd,[Rb,#imm5] */ - 0xE5900000, /* LDR Rd,[Rb,#imm5] */ - 0xE5C00000, /* STRB Rd,[Rb,#imm5] */ - 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */ - }; - /* The offset range defends on whether we are transferring a - byte or word value: */ - *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */ - } - break; - case 16: /* STRH Rd,[Rb,#imm5] */ - case 17: /* LDRH Rd,[Rb,#imm5] */ - /* Format 10 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE1D000B0 /* LDRH */ - : 0xE1C000B0) /* STRH */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */ - |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */ - break; - case 18: /* STR Rd,[SP,#imm8] */ - case 19: /* LDR Rd,[SP,#imm8] */ - /* Format 11 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE59D0000 /* LDR */ - : 0xE58D0000) /* STR */ - |((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |((tinstr & 0x00FF) << 2); /* off8 */ - break; - case 20: /* ADD Rd,PC,#imm8 */ - case 21: /* ADD Rd,SP,#imm8 */ - /* Format 12 */ - if ((tinstr & (1 << 11)) == 0) { - /* NOTE: The PC value used here should by word aligned */ - /* We encode shift-left-by-2 in the rotate immediate field, - so no shift of off8 is needed. */ - *ainstr = 0xE28F0F00 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |(tinstr & 0x00FF); /* off8 */ - } - else { - /* We encode shift-left-by-2 in the rotate immediate field, - so no shift of off8 is needed. */ - *ainstr = 0xE28D0F00 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |(tinstr & 0x00FF); /* off8 */ - } - break; - case 22: - case 23: - if ((tinstr & 0x0F00) == 0x0000) { - /* Format 13 */ - /* NOTE: The instruction contains a shift left of 2 - equivalent (implemented as ROR #30): */ - *ainstr = ((tinstr & (1 << 7)) /* base */ - ? 0xE24DDF00 /* SUB */ - : 0xE28DDF00) /* ADD */ - |(tinstr & 0x007F); /* off7 */ - } - else if ((tinstr & 0x0F00) == 0x0e00) - *ainstr = 0xEF000000 | SWI_Breakpoint; - else { - /* Format 14 */ - ARMword subset[4] = { - 0xE92D0000, /* STMDB sp!,{rlist} */ - 0xE92D4000, /* STMDB sp!,{rlist,lr} */ - 0xE8BD0000, /* LDMIA sp!,{rlist} */ - 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */ - }; - *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */ - |(tinstr & 0x00FF); /* mask8 */ - } - break; - case 24: /* STMIA */ - case 25: /* LDMIA */ - /* Format 15 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE8B00000 /* LDMIA */ - : 0xE8A00000) /* STMIA */ - |((tinstr & 0x0700) << (16 - 8)) /* Rb */ - |(tinstr & 0x00FF); /* mask8 */ - break; - case 26: /* Bcc */ - case 27: /* Bcc/SWI */ - if ((tinstr & 0x0F00) == 0x0F00) { - if (tinstr == (ARMul_ABORTWORD & 0xffff) && - state->AbortAddr == pc) { - *ainstr = ARMul_ABORTWORD; - break; - } - /* Format 17 : SWI */ - *ainstr = 0xEF000000; - /* Breakpoint must be handled specially. */ - if ((tinstr & 0x00FF) == 0x18) - *ainstr |= ((tinstr & 0x00FF) << 16); - /* New breakpoint value. See gdb/arm-tdep.c */ - else if ((tinstr & 0x00FF) == 0xFE) - *ainstr |= SWI_Breakpoint; - else - *ainstr |= (tinstr & 0x00FF); - } - else if ((tinstr & 0x0F00) != 0x0E00) { - /* Format 16 */ - int doit = FALSE; - /* TODO: Since we are doing a switch here, we could just add - the SWI and undefined instruction checks into this - switch to same on a couple of conditionals: */ - switch ((tinstr & 0x0F00) >> 8) { - case EQ: - doit = ZFLAG; - break; - case NE: - doit = !ZFLAG; - break; - case VS: - doit = VFLAG; - break; - case VC: - doit = !VFLAG; - break; - case MI: - doit = NFLAG; - break; - case PL: - doit = !NFLAG; - break; - case CS: - doit = CFLAG; - break; - case CC: - doit = !CFLAG; - break; - case HI: - doit = (CFLAG && !ZFLAG); - break; - case LS: - doit = (!CFLAG || ZFLAG); - break; - case GE: - doit = ((!NFLAG && !VFLAG) - || (NFLAG && VFLAG)); - break; - case LT: - doit = ((NFLAG && !VFLAG) - || (!NFLAG && VFLAG)); - break; - case GT: - doit = ((!NFLAG && !VFLAG && !ZFLAG) - || (NFLAG && VFLAG && !ZFLAG)); - break; - case LE: - doit = ((NFLAG && !VFLAG) - || (!NFLAG && VFLAG)) || ZFLAG; - break; - } - if (doit) { - state->Reg[15] = (pc + 4 - + (((tinstr & 0x7F) << 1) - | ((tinstr & (1 << 7)) ? - 0xFFFFFF00 : 0))); - FLUSHPIPE; - } - valid = t_branch; - } - else /* UNDEFINED : cc=1110(AL) uses different format */ - valid = t_undefined; - break; - case 28: /* B */ - /* Format 18 */ - state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1) - | ((tinstr & (1 << 10)) ? - 0xFFFFF800 : 0))); - FLUSHPIPE; - valid = t_branch; - break; - case 29: - if(tinstr & 0x1) - valid = t_undefined; - else{ - /* BLX 1 for armv5t and above */ - ARMword tmp = (pc + 2); - state->Reg[15] = - (state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; - state->Reg[14] = (tmp | 1); - CLEART; - DEBUG_LOG(ARM11, "In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); - valid = t_branch; - FLUSHPIPE; - } - break; - case 30: /* BL instruction 1 */ - /* Format 19 */ - /* There is no single ARM instruction equivalent for this Thumb - instruction. To keep the simulation simple (from the user - perspective) we check if the following instruction is the - second half of this BL, and if it is we simulate it - immediately. */ - state->Reg[14] = state->Reg[15] - + (((tinstr & 0x07FF) << 12) - | ((tinstr & (1 << 10)) ? 0xFF800000 : 0)); - valid = t_branch; /* in-case we don't have the 2nd half */ - //tinstr = next_instr; /* move the instruction down */ - //if (((tinstr & 0xF800) >> 11) != 31) - // break; /* exit, since not correct instruction */ - /* else we fall through to process the second half of the BL */ - //pc += 2; /* point the pc at the 2nd half */ - state->Reg[15] = pc + 2; - FLUSHPIPE; - break; - case 31: /* BL instruction 2 */ - /* Format 19 */ - /* There is no single ARM instruction equivalent for this - instruction. Also, it should only ever be matched with the - fmt19 "BL instruction 1" instruction. However, we do allow - the simulation of it on its own, with undefined results if - r14 is not suitably initialised. */ - { - ARMword tmp = (pc + 2); - state->Reg[15] = - (state->Reg[14] + ((tinstr & 0x07FF) << 1)); - state->Reg[14] = (tmp | 1); - valid = t_branch; - FLUSHPIPE; - } - break; - } - - return valid; -} diff --git a/src/core/src/arm/mmu/arm1176jzf_s_mmu.cpp b/src/core/src/arm/mmu/arm1176jzf_s_mmu.cpp deleted file mode 100644 index 0a3206ab..00000000 --- a/src/core/src/arm/mmu/arm1176jzf_s_mmu.cpp +++ /dev/null @@ -1,1132 +0,0 @@ -/* - arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation. - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - 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 -#include -#include - -#include "mem_map.h" - -#include "arm/interpreter/skyeye_defs.h" - -#include "arm/interpreter/armdefs.h" -//#include "bank_defs.h" -#if 0 -#define TLB_SIZE 1024 * 1024 -#define ASID 255 -static uint32_t tlb_entry_array[TLB_SIZE][ASID]; -static inline void invalidate_all_tlb(ARMul_State *state){ - memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID); -} -static inline void invalidate_by_mva(ARMul_State *state, ARMword va){ - memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t)); - return; -} -static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){ - int i; - for(i = 0; i < TLB_SIZE; i++) - memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t)); - return; -} - -static uint32_t get_phys_page(ARMul_State* state, ARMword va){ - uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF]; - //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page); - return phys_page; -} - -static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){ - //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa); - //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12); - tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12; - - return; -} -#endif -#define BANK0_START 0x50000000 -static void* mem_ptr = NULL; - -static int exclusive_detect(ARMul_State* state, ARMword addr){ - #if 0 - for(int i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == addr) - return 0; - } - #endif - if(state->exclusive_tag_array[0] == addr) - return 0; - else - return -1; -} - -static void add_exclusive_addr(ARMul_State* state, ARMword addr){ - #if 0 - for(int i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == 0xffffffff){ - state->exclusive_tag_array[i] = addr; - //printf("In %s, add addr 0x%x\n", __func__, addr); - return; - } - } - printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__); - #endif - state->exclusive_tag_array[0] = addr; - return; -} - -static void remove_exclusive(ARMul_State* state, ARMword addr){ - #if 0 - int i; - for(i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == addr){ - state->exclusive_tag_array[i] = 0xffffffff; - //printf("In %s, remove addr 0x%x\n", __func__, addr); - return; - } - } - #endif - state->exclusive_tag_array[0] = 0xFFFFFFFF; -} - -/* This function encodes table 8-2 Interpreting AP bits, - returning non-zero if access is allowed. */ -static int -check_perms (ARMul_State *state, int ap, int read) -{ - int s, r, user; - - s = state->mmu.control & CONTROL_SYSTEM; - r = state->mmu.control & CONTROL_ROM; - /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */ -// printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read); -// printf("mode is %x\n", state->Mode); - user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); - - switch (ap) { - case 0: - return read && ((s && !user) || r); - case 1: - return !user; - case 2: - return read || !user; - case 3: - return 1; - } - return 0; -} - -#if 0 -fault_t -check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb, - int read) -{ - int access; - - state->mmu.last_domain = tlb->domain; - access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; - if ((access == 0) || (access == 2)) { - /* It's unclear from the documentation whether this - should always raise a section domain fault, or if - it should be a page domain fault in the case of an - L1 that describes a page table. In the ARM710T - datasheets, "Figure 8-9: Sequence for checking faults" - seems to indicate the former, while "Table 8-4: Priority - encoding of fault status" gives a value for FS[3210] in - the event of a domain fault for a page. Hmm. */ - return SECTION_DOMAIN_FAULT; - } - if (access == 1) { - /* client access - check perms */ - int subpage, ap; -#if 0 - switch (tlb->mapping) { - /*ks 2004-05-09 - * only for XScale - * Extend Small Page(ESP) Format - * 31-12 bits the base addr of ESP - * 11-10 bits SBZ - * 9-6 bits TEX - * 5-4 bits AP - * 3 bit C - * 2 bit B - * 1-0 bits 11 - * */ - case TLB_ESMALLPAGE: /* xj */ - subpage = 0; - /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */ - break; - - case TLB_TINYPAGE: - subpage = 0; - /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */ - break; - - case TLB_SMALLPAGE: - subpage = (virt_addr >> 10) & 3; - break; - case TLB_LARGEPAGE: - subpage = (virt_addr >> 14) & 3; - break; - case TLB_SECTION: - subpage = 3; - break; - default: - assert (0); - subpage = 0; /* cleans a warning */ - } - ap = (tlb->perms >> (subpage * 2 + 4)) & 3; - if (!check_perms (state, ap, read)) { - if (tlb->mapping == TLB_SECTION) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } -#endif - } else { /* access == 3 */ - /* manager access - don't check perms */ - } - return NO_FAULT; -} -#endif - -#if 0 -fault_t -mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr) -#endif - -/* ap: AP bits value. - * sop: section or page description 0:section 1:page - */ -fault_t -mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop) -{ - { - /* walk the translation tables */ - ARMword l1addr, l1desc; - if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) { - l1addr = state->mmu.translation_table_base1; - l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3; - } else { - l1addr = state->mmu.translation_table_base0; - l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3; - } - - /* l1desc = mem_read_word (state, l1addr); */ - if (state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, l1addr, &l1desc, 4); - else - l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc); - - #if 0 - if (virt_addr == 0xc000d2bc) { - printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); - printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); - printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); - printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); - // exit(-1); - } - #endif - switch (l1desc & 3) { - case 0: - case 3: - /* - * according to Figure 3-9 Sequence for checking faults in arm manual, - * section translation fault should be returned here. - */ - { - return SECTION_TRANSLATION_FAULT; - } - case 1: - /* coarse page table */ - { - ARMword l2addr, l2desc; - - - l2addr = l1desc & 0xFFFFFC00; - l2addr = (l2addr | - ((virt_addr & 0x000FF000) >> 10)) & - ~3; - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, l2addr, &l2desc, 4); - else - l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc); - - /* chy 2003-09-02 for xscale */ - *ap = (l2desc >> 4) & 0x3; - *sop = 1; /* page */ - - switch (l2desc & 3) { - case 0: - return PAGE_TRANSLATION_FAULT; - break; - case 1: - *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF); - break; - case 2: - case 3: - *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF); - break; - - } - } - break; - case 2: - /* section */ - - *ap = (l1desc >> 10) & 3; - *sop = 0; /* section */ - #if 0 - if (virt_addr == 0xc000d2bc) { - printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); - printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); - printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); - printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); -// printf("l2addr is %x l2desc is %x\n", l2addr, l2desc); - printf("ap is %x, sop is %x\n", *ap, *sop); - printf("mode is %d\n", state->Mode); -// exit(-1); - } - #endif - - if (l1desc & 0x30000) - *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF); - else - *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF); - break; - } - } - return NO_FAULT; -} - - -static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, - ARMword data, ARMword datatype); -static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, - ARMword *data, ARMword datatype); - -int -arm1176jzf_s_mmu_init (ARMul_State *state) -{ - state->mmu.control = 0x50078; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - state->mmu.context_id = 0; - state->mmu.thread_uro_id = 0; - //invalidate_all_tlb(state); - - return No_exp; -} - -void -arm1176jzf_s_mmu_exit (ARMul_State *state) -{ -} - - -static fault_t -arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) -{ - fault_t fault; - int c; /* cache bit */ - ARMword pa; /* physical addr */ - ARMword perm; /* physical addr access permissions */ - int ap, sop; - - static int debug_count = 0; /* used for debug */ - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - if (MMU_Enabled) { -// printf("MMU enabled.\n"); -// sleep(1); - /* align check */ - if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } else - va &= ~(WORD_SIZE - 1); - - /* translate tlb */ - fault = mmu_translate (state, va, &pa, &ap, &sop); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault); - return fault; - } - - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 1)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } - -#if 0 - /*check access */ - fault = check_access (state, va, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } -#endif - } - - /*if MMU disabled or C flag is set alloc cache */ - if (MMU_Disabled) { -// printf("MMU disabled.\n"); -// sleep(1); - pa = va; - } - if(state->space.conf_obj == NULL) - state->space.read(state->space.conf_obj, pa, instr, 4); - else - *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr); - - return NO_FAULT; -} - -static fault_t -arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data) -{ - /* ARMword temp,offset; */ - fault_t fault; - fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); - return fault; -} - -static fault_t -arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr, - ARMword *data) -{ - /* ARMword temp,offset; */ - fault_t fault; - fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); - return fault; -} - -static fault_t -arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data) -{ - return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, - ARMword datatype) -{ - fault_t fault; - ARMword pa, real_va, temp, offset; - ARMword perm; /* physical addr access permissions */ - int ap, sop; - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - real_va = va; - /* if MMU disabled, memory_read */ - if (MMU_Disabled) { -// printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va); -// sleep(1); - - /* *data = mem_read_word(state, va); */ - if (datatype == ARM_BYTE_TYPE) - /* *data = mem_read_byte (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 1); - else - *data = Memory::Read8(va); //mem_read_raw(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* *data = mem_read_halfword (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 2); - else - *data = Memory::Read16(va); //mem_read_raw(16, va, data); - else if (datatype == ARM_WORD_TYPE) - /* *data = mem_read_word (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 4); - else - *data = Memory::Read32(va); //mem_read_raw(32, va, data); - else { - ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); - } - - return NO_FAULT; - } -// printf("MMU enabled.\n"); -// sleep(1); - - /* align check */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - - /* va &= ~(WORD_SIZE - 1); */ - #if 0 - uint32_t page_base; - page_base = get_phys_page(state, va); - if((page_base & 0xFFF) == 0){ - pa = (page_base << 12) | (va & 0xFFF); - goto skip_translation; - } - #endif - /*translate va to tlb */ -#if 0 - fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb); -#endif - fault = mmu_translate (state, va, &pa, &ap, &sop); -#if 0 - if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){ - //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); - printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); - int i; - for(i = 0; i < 16; i++) - printf("Reg[%d]=0x%x\t", i, state->Reg[i]); - printf("\n"); - } -#endif - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - //printf("mmu read fault at %x\n", va); - //printf("fault is %d\n", fault); - return fault; - } -// printf("va is %x pa is %x\n", va, pa); - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 1)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } -#if 0 - /*check access permission */ - fault = check_access (state, va, tlb, 1); - if (fault) - return fault; -#endif - - //insert_tlb(state, va, pa); -skip_translation: - /* *data = mem_read_word(state, pa); */ - if (datatype == ARM_BYTE_TYPE) { - /* *data = mem_read_byte (state, pa | (real_va & 3)); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1); - else - *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data); - /* mem_read_raw(32, pa | (real_va & 3), data); */ - } else if (datatype == ARM_HALFWORD_TYPE) { - /* *data = mem_read_halfword (state, pa | (real_va & 2)); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2); - else - *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data); - /* mem_read_raw(32, pa | (real_va & 2), data); */ - } else if (datatype == ARM_WORD_TYPE) - /* *data = mem_read_word (state, pa); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa , data, 4); - else - *data = Memory::Read32(pa); //mem_read_raw(32, pa, data); - else { - ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); - } - if(0 && (va == 0x2869c)){ - printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr); - } - - /* ldrex or ldrexb */ - if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) || - ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){ - int rn = (state->CurrInstr & 0xF0000) >> 16; - if(state->Reg[rn] == va){ - add_exclusive_addr(state, pa | (real_va & 3)); - state->exclusive_access_state = 1; - } - } -#if 0 - if (state->pc == 0xc011a868) { - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); -// exit(-1); - } -#endif - - return NO_FAULT; -} - - -static fault_t -arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr, - ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); -} - - - -static fault_t -arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, - ARMword datatype) -{ - int b; - ARMword pa, real_va; - ARMword perm; /* physical addr access permissions */ - fault_t fault; - int ap, sop; - -#if 0 - /8 for sky_printk debugger.*/ - if (va == 0xffffffff) { - putchar((char)data); - return 0; - } - if (va == 0xBfffffff) { - putchar((char)data); - return 0; - } -#endif - - DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); - va = mmu_pid_va_map (va); - real_va = va; - - if (MMU_Disabled) { - /* mem_write_word(state, va, data); */ - if (datatype == ARM_BYTE_TYPE) - /* mem_write_byte (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 1); - else - Memory::Write8(va, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* mem_write_halfword (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 2); - else - Memory::Write16(va, data); - else if (datatype == ARM_WORD_TYPE) - /* mem_write_word (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 4); - else - Memory::Write32(va, data); - else { - ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype); - } - goto finished_write; - //return 0; - } - /*align check */ - /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - va &= ~(WORD_SIZE - 1); - #if 0 - uint32_t page_base; - page_base = get_phys_page(state, va); - if((page_base & 0xFFF) == 0){ - pa = (page_base << 12) | (va & 0xFFF); - goto skip_translation; - } - #endif - /*tlb translate */ - fault = mmu_translate (state, va, &pa, &ap, &sop); -#if 0 - if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){ - //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); - printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); - int i; - for(i = 0; i < 16; i++) - printf("Reg[%d]=0x%x\t", i, state->Reg[i]); - printf("\n"); - } -#endif - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - //printf("mmu write fault at %x\n", va); - return fault; - } -// printf("va is %x pa is %x\n", va, pa); - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 0)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } - -#if 0 - /* tlb check access */ - fault = check_access (state, va, tlb, 0); - if (fault) { - DEBUG_LOG(ARM11, "check_access\n"); - return fault; - } -#endif -#if 0 - if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) { - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - } -#endif -#if 0 - if (state->pc == 0xc011a878) { - printf("write pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); - exit(-1); - } -#endif - //insert_tlb(state, va, pa); -skip_translation: - /* strex */ - if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) || - ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){ - /* failed , the address is monitord now. */ - int dest_reg = (state->CurrInstr & 0xF000) >> 12; - if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){ - remove_exclusive(state, pa | (real_va & 3)); - state->Reg[dest_reg] = 0; - state->exclusive_access_state = 0; - } - else{ - state->Reg[dest_reg] = 1; - //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa); - return NO_FAULT; - } - } - - if (datatype == ARM_BYTE_TYPE) { - /* mem_write_byte (state, - (pa | (real_va & 3)), - data); - */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1); - else - Memory::Write8((pa | (real_va & 3)), data); - - } else if (datatype == ARM_HALFWORD_TYPE) - /* mem_write_halfword (state, - (pa | - (real_va & 2)), - data); - */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2); - else - Memory::Write16((pa | (real_va & 3)), data); - else if (datatype == ARM_WORD_TYPE) - /* mem_write_word (state, pa, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, pa, &data, 4); - else - Memory::Write32(pa, data); -#if 0 - if (state->NumInstrs > 236403) { - printf("write memory\n"); - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); - } -#endif -finished_write: -#if DIFF_WRITE - if(state->icounter > state->debug_icounter){ - if(state->CurrWrite >= 17 ){ - printf("Wrong write array, 0x%x", state->CurrWrite); - exit(-1); - } - uint32 record_data = data; - if(datatype == ARM_BYTE_TYPE) - record_data &= 0xFF; - if(datatype == ARM_HALFWORD_TYPE) - record_data &= 0xFFFF; - - state->WriteAddr[state->CurrWrite] = pa | (real_va & 3); - state->WriteData[state->CurrWrite] = record_data; - state->WritePc[state->CurrWrite] = state->Reg[15]; - state->CurrWrite++; - //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag); - } -#endif - - return NO_FAULT; -} - -ARMword -arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value) -{ - int creg = BITS (16, 19) & 0xf; - int OPC_1 = BITS (21, 23) & 0x7; - int OPC_2 = BITS (5, 7) & 0x7; - ARMword data; - - switch (creg) { - case MMU_ID: - if (OPC_2 == 0) { - data = state->cpu->cpu_val; - } else if (OPC_2 == 1) { - /* Cache type: - * 000 0110 1 000 101 110 0 10 000 101 110 0 10 - * */ - data = 0x0D172172; - } - break; - case MMU_CONTROL: - /* - * 6:3 read as 1 - * 10 read as 0 - * 18,16 read as 1 - * */ - data = (state->mmu.control | 0x50078) & 0xFFFFFBFF; - break; - case MMU_TRANSLATION_TABLE_BASE: -#if 0 - data = state->mmu.translation_table_base; -#endif - switch (OPC_2) { - case 0: - data = state->mmu.translation_table_base0; - break; - case 1: - data = state->mmu.translation_table_base1; - break; - case 2: - data = state->mmu.translation_table_ctrl; - break; - default: - printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2); - break; - } - break; - case MMU_DOMAIN_ACCESS_CONTROL: - data = state->mmu.domain_access_control; - break; - case MMU_FAULT_STATUS: - /* OPC_2 = 0: data FSR value - * */ - if (OPC_2 == 0) - data = state->mmu.fault_status; - if (OPC_2 == 1) - data = state->mmu.fault_statusi; - break; - case MMU_FAULT_ADDRESS: - data = state->mmu.fault_address; - break; - case MMU_PID: - //data = state->mmu.process_id; - if(OPC_2 == 0) - data = state->mmu.process_id; - else if(OPC_2 == 1) - data = state->mmu.context_id; - else if(OPC_2 == 3){ - data = state->mmu.thread_uro_id; - } - else{ - printf ("mmu_mcr read UNKNOWN - reg %d\n", creg); - } - //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr); - //exit(-1); - break; - default: - printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); - data = 0; - break; - } -/* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */ - *value = data; - return data; -} - - -static ARMword -arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value) -{ - int creg = BITS (16, 19) & 0xf; - int CRm = BITS (0, 3) & 0xf; - int OPC_1 = BITS (21, 23) & 0x7; - int OPC_2 = BITS (5, 7) & 0x7; - if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) { - switch (creg) { - case MMU_CONTROL: - /* - * 6:3 read as 1 - * 10 read as 0 - * 18,16 read as 1 - * */ - if(OPC_2 == 0) - state->mmu.control = (value | 0x50078) & 0xFFFFFBFF; - else if(OPC_2 == 1) - state->mmu.auxiliary_control = value; - else if(OPC_2 == 2) - state->mmu.coprocessor_access_control = value; - else - fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2); - break; - case MMU_TRANSLATION_TABLE_BASE: - switch (OPC_2) { - /* int i; */ - case 0: -#if 0 - /* TTBR0 */ - if (state->mmu.translation_table_ctrl & 0x7) { - for (i = 0; i <= state->mmu.translation_table_ctrl; i++) - state->mmu.translation_table_base0 &= ~(1 << (5 + i)); - } -#endif - state->mmu.translation_table_base0 = (value); - break; - case 1: -#if 0 - /* TTBR1 */ - if (state->mmu.translation_table_ctrl & 0x7) { - for (i = 0; i <= state->mmu.translation_table_ctrl; i++) - state->mmu.translation_table_base1 &= 1 << (5 + i); - } -#endif - state->mmu.translation_table_base1 = (value); - break; - case 2: - /* TTBC */ - state->mmu.translation_table_ctrl = value & 0x7; - break; - default: - printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2); - break; - } - //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - //invalidate_all_tlb(state); - break; - case MMU_DOMAIN_ACCESS_CONTROL: - /* printf("mmu_mcr wrote DACR "); */ - state->mmu.domain_access_control = value; - break; - - case MMU_FAULT_STATUS: - if (OPC_2 == 0) - state->mmu.fault_status = value & 0xFF; - if (OPC_2 == 1) { - printf("set fault status instr\n"); - } - break; - case MMU_FAULT_ADDRESS: - state->mmu.fault_address = value; - break; - - case MMU_CACHE_OPS: - break; - case MMU_TLB_OPS: - { - switch(CRm){ - case 5: /* ITLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - case 6: /* DTLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - case 7: /* Unified TLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm); - break; - } - //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr); - } - break; - case MMU_CACHE_LOCKDOWN: - /* - * FIXME: cache lock down*/ - break; - case MMU_TLB_LOCKDOWN: - printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - /* FIXME:tlb lock down */ - break; - case MMU_PID: - //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - //state->mmu.process_id = value; - /*0:24 should be zero. */ - //state->mmu.process_id = value & 0xfe000000; - if(OPC_2 == 0) - state->mmu.process_id = value; - else if(OPC_2 == 1) - state->mmu.context_id = value; - else if(OPC_2 == 3){ - state->mmu.thread_uro_id = value; - } - else{ - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - } - break; - - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - } - - return No_exp; -} - -///* teawater add for arm2x86 2005.06.19------------------------------------------- */ -//static int -//arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr, -// ARMword *phys_addr) -//{ -// fault_t fault; -// int ap, sop; -// -// ARMword perm; /* physical addr access permissions */ -// virt_addr = mmu_pid_va_map (virt_addr); -// if (MMU_Enabled) { -// -// /*align check */ -// if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { -// DEBUG_LOG(ARM11, "align\n"); -// return ALIGNMENT_FAULT; -// } else -// virt_addr &= ~(WORD_SIZE - 1); -// -// /*translate tlb */ -// fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop); -// if (fault) { -// DEBUG_LOG(ARM11, "translate\n"); -// return fault; -// } -// -// /* permission check */ -// if (!check_perms(state, ap, 1)) { -// if (sop == 0) { -// return SECTION_PERMISSION_FAULT; -// } else { -// return SUBPAGE_PERMISSION_FAULT; -// } -// } -//#if 0 -// /*check access */ -// fault = check_access (state, virt_addr, tlb, 1); -// if (fault) { -// DEBUG_LOG(ARM11, "check_fault\n"); -// return fault; -// } -//#endif -// } -// -// if (MMU_Disabled) { -// *phys_addr = virt_addr; -// } -// -// return 0; -//} - -/* AJ2D-------------------------------------------------------------------------- */ - -/*arm1176jzf-s mmu_ops_t*/ -mmu_ops_t arm1176jzf_s_mmu_ops = { - arm1176jzf_s_mmu_init, - arm1176jzf_s_mmu_exit, - arm1176jzf_s_mmu_read_byte, - arm1176jzf_s_mmu_write_byte, - arm1176jzf_s_mmu_read_halfword, - arm1176jzf_s_mmu_write_halfword, - arm1176jzf_s_mmu_read_word, - arm1176jzf_s_mmu_write_word, - arm1176jzf_s_mmu_load_instr, - arm1176jzf_s_mmu_mcr, - arm1176jzf_s_mmu_mrc -/* teawater add for arm2x86 2005.06.19------------------------------------------- */ -/* arm1176jzf_s_mmu_v2p_dbct, */ -/* AJ2D-------------------------------------------------------------------------- */ -}; diff --git a/src/core/src/arm/mmu/arm1176jzf_s_mmu.h b/src/core/src/arm/mmu/arm1176jzf_s_mmu.h deleted file mode 100644 index 299c6b46..00000000 --- a/src/core/src/arm/mmu/arm1176jzf_s_mmu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation. - - 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 -*/ - -#ifndef _ARM1176JZF_S_MMU_H_ -#define _ARM1176JZF_S_MMU_H_ - -#if 0 -typedef struct arm1176jzf-s_mmu_s -{ - tlb_t i_tlb; - cache_t i_cache; - - tlb_t d_tlb; - cache_t d_cache; - wb_t wb_t; -} arm1176jzf-s_mmu_t; -#endif -extern mmu_ops_t arm1176jzf_s_mmu_ops; - -ARMword -arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value); -#endif /*_ARM1176JZF_S_MMU_H_*/ diff --git a/src/core/src/arm/mmu/cache.h b/src/core/src/arm/mmu/cache.h deleted file mode 100644 index d308d9b8..00000000 --- a/src/core/src/arm/mmu/cache.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef _MMU_CACHE_H_ -#define _MMU_CACHE_H_ - -typedef struct cache_line_t -{ - ARMword tag; /* cache line align address | - bit2: last half dirty - bit1: first half dirty - bit0: cache valid flag - */ - ARMword pa; /*physical address */ - ARMword *data; /*array of cached data */ -} cache_line_t; -#define TAG_VALID_FLAG 0x00000001 -#define TAG_FIRST_HALF_DIRTY 0x00000002 -#define TAG_LAST_HALF_DIRTY 0x00000004 - -/*cache set association*/ -typedef struct cache_set_s -{ - cache_line_t *lines; - int cycle; -} cache_set_t; - -enum -{ - CACHE_WRITE_BACK, - CACHE_WRITE_THROUGH, -}; - -typedef struct cache_s -{ - int width; /*bytes in a line */ - int way; /*way of set asscociate */ - int set; /*num of set */ - int w_mode; /*write back or write through */ - //int a_mode; /*alloc mode: random or round-bin*/ - cache_set_t *sets; - /**/} cache_s; - -typedef struct cache_desc_s -{ - int width; - int way; - int set; - int w_mode; -// int a_mode; -} cache_desc_t; - - -/*virtual address to cache set index*/ -#define va_cache_set(va, cache_t) \ - (((va) / (cache_t)->width) & ((cache_t)->set - 1)) -/*virtual address to cahce line aligned*/ -#define va_cache_align(va, cache_t) \ - ((va) & ~((cache_t)->width - 1)) -/*virtaul address to cache line word index*/ -#define va_cache_index(va, cache_t) \ - (((va) & ((cache_t)->width - 1)) >> WORD_SHT) - -/*see Page 558 in arm manual*/ -/*set/index format value to cache set value*/ -#define index_cache_set(index, cache_t) \ - (((index) / (cache_t)->width) & ((cache_t)->set - 1)) - -/*************************cache********************/ -/* mmu cache init - * - * @cache_t :cache_t to init - * @width :cache line width in byte - * @way :way of each cache set - * @set :cache set num - * @w_mode :cache w_mode - * - * $ -1: error - * 0: sucess - */ -int -mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode); - -/* free a cache_t's inner data, the ptr self is not freed, - * when needed do like below: - * mmu_cache_exit(cache); - * free(cache_t); - * - * @cache_t : the cache_t to free - */ -void mmu_cache_exit (cache_s * cache_t); - -/* mmu cache search - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @va :virtual address - * - * $ NULL: no cache match - * cache :cache matched - * */ -cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t, - ARMword va); - -/* mmu cache search by set/index - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @index :set/index value. - * - * $ NULL: no cache match - * cache :cache matched - * */ - -cache_line_t *mmu_cache_search_by_index (ARMul_State * state, - cache_s * cache_t, ARMword index); - -/* mmu cache alloc - * - * @state :ARMul_State - * @cache_t :cache_t to alloc from - * @va :virtual address that require cache alloc, need not cache aligned - * @pa :physical address of va - * - * $ cache_alloced, always alloc OK - */ -cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, - ARMword va, ARMword pa); - -/* mmu_cache_write_back write cache data to memory - * - * @state: - * @cache_t :cache_t of the cache line - * @cache : cache line - */ -void -mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, - cache_line_t * cache); - -/* mmu_cache_clean: clean a cache of va in cache_t - * - * @state :ARMul_State - * @cache_t :cache_t to clean - * @va :virtaul address - */ -void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va); -void -mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index); - -/* mmu_cache_invalidate : invalidate a cache of va - * - * @state :ARMul_State - * @cache_t :cache_t to invalid - * @va :virt_addr to invalid - */ -void -mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va); - -void -mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index); - -void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t); - -void -mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa); - -cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t); - -#endif /*_MMU_CACHE_H_*/ diff --git a/src/core/src/arm/mmu/rb.h b/src/core/src/arm/mmu/rb.h deleted file mode 100644 index 7bf0ebb2..00000000 --- a/src/core/src/arm/mmu/rb.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _MMU_RB_H -#define _MMU_RB_H - -enum rb_type_t -{ - RB_INVALID = 0, //invalid - RB_1, //1 word - RB_4, //4 word - RB_8, //8 word -}; - -/*bytes of each rb_type*/ -extern ARMword rb_masks[]; - -#define RB_WORD_NUM 8 -typedef struct rb_entry_s -{ - ARMword data[RB_WORD_NUM]; //array to store data - ARMword va; //first word va - int type; //rb type - fault_t fault; //fault set by rb alloc -} rb_entry_t; - -typedef struct rb_s -{ - int num; - rb_entry_t *entrys; -} rb_s; - -/*mmu_rb_init - * @rb_t :rb_t to init - * @num :number of entry - * */ -int mmu_rb_init (rb_s * rb_t, int num); - -/*mmu_rb_exit*/ -void mmu_rb_exit (rb_s * rb_t); - - -/*mmu_rb_search - * @rb_t :rb_t to serach - * @va :va address to math - * - * $ NULL :not match - * NO-NULL: - * */ -rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va); - - -void mmu_rb_invalidate_entry (rb_s * rb_t, int i); -void mmu_rb_invalidate_all (rb_s * rb_t); -void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, - int type, ARMword va); - -#endif /*_MMU_RB_H_*/ diff --git a/src/core/src/arm/mmu/tlb.h b/src/core/src/arm/mmu/tlb.h deleted file mode 100644 index 938c0178..00000000 --- a/src/core/src/arm/mmu/tlb.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _MMU_TLB_H_ -#define _MMU_TLB_H_ - -typedef enum tlb_mapping_t -{ - TLB_INVALID = 0, - TLB_SMALLPAGE = 1, - TLB_LARGEPAGE = 2, - TLB_SECTION = 3, - TLB_ESMALLPAGE = 4, - TLB_TINYPAGE = 5 -} tlb_mapping_t; - -extern ARMword tlb_masks[]; - -/* Permissions bits in a TLB entry: - * - * 31 12 11 10 9 8 7 6 5 4 3 2 1 0 - * +-------------+-----+-----+-----+-----+---+---+-------+ - * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | | - * +-------------+-----+-----+-----+-----+---+---+-------+ - * - * 31 12 11 10 9 4 3 2 1 0 - * +-------------+-----+-----------------+---+---+-------+ - * Section: | | AP | | C | B | | - * +-------------+-----+-----------------+---+---+-------+ - */ - -/* -section: - section base address [31:20] - AP - table 8-2, page 8-8 - domain - C,B - -page: - page base address [31:16] or [31:12] - ap[3:0] - domain (from L1) - C,B -*/ - - -typedef struct tlb_entry_t -{ - ARMword virt_addr; - ARMword phys_addr; - ARMword perms; - ARMword domain; - tlb_mapping_t mapping; -} tlb_entry_t; - -typedef struct tlb_s -{ - int num; /*num of tlb entry */ - int cycle; /*current tlb cycle */ - tlb_entry_t *entrys; -} tlb_s; - - -#define tlb_c_flag(tlb) \ - ((tlb)->perms & 0x8) -#define tlb_b_flag(tlb) \ - ((tlb)->perms & 0x4) - -#define tlb_va_to_pa(tlb, va) \ -(\ - {\ - ARMword mask = tlb_masks[tlb->mapping]; \ - (tlb->phys_addr & mask) | (va & ~mask);\ - }\ -) - -fault_t -check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, - int read); - -fault_t -translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, - tlb_entry_t ** tlb); - -int mmu_tlb_init (tlb_s * tlb_t, int num); - -void mmu_tlb_exit (tlb_s * tlb_t); - -void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t); - -void -mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr); - -tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, - ARMword virt_addr); - -#endif /*_MMU_TLB_H_*/ diff --git a/src/core/src/arm/mmu/wb.h b/src/core/src/arm/mmu/wb.h deleted file mode 100644 index 8fb7de94..00000000 --- a/src/core/src/arm/mmu/wb.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _MMU_WB_H_ -#define _MMU_WB_H_ - -typedef struct wb_entry_s -{ - ARMword pa; //phy_addr - ARMbyte *data; //data - int nb; //number byte to write -} wb_entry_t; - -typedef struct wb_s -{ - int num; //number of wb_entry - int nb; //number of byte of each entry - int first; // - int last; // - int used; // - wb_entry_t *entrys; -} wb_s; - -typedef struct wb_desc_s -{ - int num; - int nb; -} wb_desc_t; - -/* wb_init - * @wb_t :wb_t to init - * @num :num of entrys - * @nw :num of word of each entry - * - * $ -1:error - * 0:ok - * */ -int mmu_wb_init (wb_s * wb_t, int num, int nb); - - -/* wb_exit - * @wb_t :wb_t to exit - * */ -void mmu_wb_exit (wb_s * wb); - - -/* wb_write_bytes :put bytess in Write Buffer - * @state: ARMul_State - * @wb_t: write buffer - * @pa: physical address - * @data: data ptr - * @n number of byte to write - * - * Note: write buffer merge is not implemented, can be done late - * */ -void -mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa, - ARMbyte * data, int n); - - -/* wb_drain_all - * @wb_t wb_t to drain - * */ -void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t); - -#endif /*_MMU_WB_H_*/ diff --git a/src/core/src/core.cpp b/src/core/src/core.cpp deleted file mode 100644 index 540b20f2..00000000 --- a/src/core/src/core.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "log.h" -#include "core.h" -#include "mem_map.h" -#include "hw/hw.h" -#include "arm/disassembler/arm_disasm.h" -#include "arm/interpreter/arm_interpreter.h" - -namespace Core { - -ARM_Disasm* g_disasm = NULL; ///< ARM disassembler -ARM_Interface* g_app_core = NULL; ///< ARM11 application core -ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core - -/// Run the core CPU loop -void RunLoop() { - // TODO(ShizZy): ImplementMe -} - -/// Step the CPU one instruction -void SingleStep() { - g_app_core->Step(); - HW::Update(); -} - -/// Halt the core -void Halt(const char *msg) { - // TODO(ShizZy): ImplementMe -} - -/// Kill the core -void Stop() { - // TODO(ShizZy): ImplementMe -} - -/// Initialize the core -int Init() { - NOTICE_LOG(MASTER_LOG, "Core initialized OK"); - - g_disasm = new ARM_Disasm(); - g_app_core = new ARM_Interpreter(); - g_sys_core = new ARM_Interpreter(); - - return 0; -} - -void Shutdown() { - delete g_disasm; - delete g_app_core; - delete g_sys_core; - - NOTICE_LOG(MASTER_LOG, "Core shutdown OK"); -} - -} // namespace diff --git a/src/core/src/core.h b/src/core/src/core.h deleted file mode 100644 index bae9f3e3..00000000 --- a/src/core/src/core.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "arm/arm_interface.h" -#include "arm/interpreter/armdefs.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace Core { - -extern ARM_Interface* g_app_core; ///< ARM11 application core -extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Start the core -void Start(); - -/// Run the core CPU loop -void RunLoop(); - -/// Step the CPU one instruction -void SingleStep(); - -/// Halt the core -void Halt(const char *msg); - -/// Kill the core -void Stop(); - -/// Initialize the core -int Init(); - -/// Shutdown the core -void Shutdown(); - -} // namespace diff --git a/src/core/src/core_timing.cpp b/src/core/src/core_timing.cpp deleted file mode 100644 index 78bbaafe..00000000 --- a/src/core/src/core_timing.cpp +++ /dev/null @@ -1,623 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include - -#include "msg_handler.h" -#include "std_mutex.h" -#include "atomic.h" -#include "core_timing.h" -#include "core.h" -#include "chunk_file.h" - -int g_clock_rate_arm11 = 268123480; - -// is this really necessary? -#define INITIAL_SLICE_LENGTH 20000 -#define MAX_SLICE_LENGTH 100000000 - -namespace CoreTiming -{ - -struct EventType -{ - EventType() {} - - EventType(TimedCallback cb, const char *n) - : callback(cb), name(n) {} - - TimedCallback callback; - const char *name; -}; - -std::vector event_types; - -struct BaseEvent -{ - s64 time; - u64 userdata; - int type; - // Event *next; -}; - -typedef LinkedListItem Event; - -Event *first; -Event *tsFirst; -Event *tsLast; - -// event pools -Event *eventPool = 0; -Event *eventTsPool = 0; -int allocatedTsEvents = 0; -// Optimization to skip MoveEvents when possible. -volatile u32 hasTsEvents = false; - -// Downcount has been moved to currentMIPS, to save a couple of clocks in every ARM JIT block -// as we can already reach that structure through a register. -int slicelength; - -MEMORY_ALIGNED16(s64) globalTimer; -s64 idledCycles; - -static std::recursive_mutex externalEventSection; - -// Warning: not included in save state. -void(*advanceCallback)(int cyclesExecuted) = NULL; - -void SetClockFrequencyMHz(int cpuMhz) -{ - g_clock_rate_arm11 = cpuMhz * 1000000; - // TODO: Rescale times of scheduled events? -} - -int GetClockFrequencyMHz() -{ - return g_clock_rate_arm11 / 1000000; -} - - -Event* GetNewEvent() -{ - if (!eventPool) - return new Event; - - Event* ev = eventPool; - eventPool = ev->next; - return ev; -} - -Event* GetNewTsEvent() -{ - allocatedTsEvents++; - - if (!eventTsPool) - return new Event; - - Event* ev = eventTsPool; - eventTsPool = ev->next; - return ev; -} - -void FreeEvent(Event* ev) -{ - ev->next = eventPool; - eventPool = ev; -} - -void FreeTsEvent(Event* ev) -{ - ev->next = eventTsPool; - eventTsPool = ev; - allocatedTsEvents--; -} - -int RegisterEvent(const char *name, TimedCallback callback) -{ - event_types.push_back(EventType(callback, name)); - return (int)event_types.size() - 1; -} - -void AntiCrashCallback(u64 userdata, int cyclesLate) -{ - ERROR_LOG(TIME, "Savestate broken: an unregistered event was called."); - Core::Halt("invalid timing events"); -} - -void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback) -{ - if (event_type >= (int)event_types.size()) - event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT")); - - event_types[event_type] = EventType(callback, name); -} - -void UnregisterAllEvents() -{ - if (first) - PanicAlert("Cannot unregister events with events pending"); - event_types.clear(); -} - -void Init() -{ - //currentMIPS->downcount = INITIAL_SLICE_LENGTH; - //slicelength = INITIAL_SLICE_LENGTH; - globalTimer = 0; - idledCycles = 0; - hasTsEvents = 0; -} - -void Shutdown() -{ - MoveEvents(); - ClearPendingEvents(); - UnregisterAllEvents(); - - while (eventPool) - { - Event *ev = eventPool; - eventPool = ev->next; - delete ev; - } - - std::lock_guard lk(externalEventSection); - while (eventTsPool) - { - Event *ev = eventTsPool; - eventTsPool = ev->next; - delete ev; - } -} - -u64 GetTicks() -{ - ERROR_LOG(TIME, "Unimplemented function!"); - return 0; - //return (u64)globalTimer + slicelength - currentMIPS->downcount; -} - -u64 GetIdleTicks() -{ - return (u64)idledCycles; -} - - -// This is to be called when outside threads, such as the graphics thread, wants to -// schedule things to be executed on the main thread. -void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata) -{ - std::lock_guard lk(externalEventSection); - Event *ne = GetNewTsEvent(); - ne->time = GetTicks() + cyclesIntoFuture; - ne->type = event_type; - ne->next = 0; - ne->userdata = userdata; - if (!tsFirst) - tsFirst = ne; - if (tsLast) - tsLast->next = ne; - tsLast = ne; - - Common::AtomicStoreRelease(hasTsEvents, 1); -} - -// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread -// in which case the event will get handled immediately, before returning. -void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) -{ - if (false) //Core::IsCPUThread()) - { - std::lock_guard lk(externalEventSection); - event_types[event_type].callback(userdata, 0); - } - else - ScheduleEvent_Threadsafe(0, event_type, userdata); -} - -void ClearPendingEvents() -{ - while (first) - { - Event *e = first->next; - FreeEvent(first); - first = e; - } -} - -void AddEventToQueue(Event* ne) -{ - Event* prev = NULL; - Event** pNext = &first; - for (;;) - { - Event*& next = *pNext; - if (!next || ne->time < next->time) - { - ne->next = next; - next = ne; - break; - } - prev = next; - pNext = &prev->next; - } -} - -// This must be run ONLY from within the cpu thread -// cyclesIntoFuture may be VERY inaccurate if called from anything else -// than Advance -void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) -{ - Event *ne = GetNewEvent(); - ne->userdata = userdata; - ne->type = event_type; - ne->time = GetTicks() + cyclesIntoFuture; - AddEventToQueue(ne); -} - -// Returns cycles left in timer. -s64 UnscheduleEvent(int event_type, u64 userdata) -{ - s64 result = 0; - if (!first) - return result; - while (first) - { - if (first->type == event_type && first->userdata == userdata) - { - result = first->time - globalTimer; - - Event *next = first->next; - FreeEvent(first); - first = next; - } - else - { - break; - } - } - if (!first) - return result; - Event *prev = first; - Event *ptr = prev->next; - while (ptr) - { - if (ptr->type == event_type && ptr->userdata == userdata) - { - result = ptr->time - globalTimer; - - prev->next = ptr->next; - FreeEvent(ptr); - ptr = prev->next; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } - - return result; -} - -s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) -{ - s64 result = 0; - std::lock_guard lk(externalEventSection); - if (!tsFirst) - return result; - while (tsFirst) - { - if (tsFirst->type == event_type && tsFirst->userdata == userdata) - { - result = tsFirst->time - globalTimer; - - Event *next = tsFirst->next; - FreeTsEvent(tsFirst); - tsFirst = next; - } - else - { - break; - } - } - if (!tsFirst) - { - tsLast = NULL; - return result; - } - - Event *prev = tsFirst; - Event *ptr = prev->next; - while (ptr) - { - if (ptr->type == event_type && ptr->userdata == userdata) - { - result = ptr->time - globalTimer; - - prev->next = ptr->next; - if (ptr == tsLast) - tsLast = prev; - FreeTsEvent(ptr); - ptr = prev->next; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } - - return result; -} - -// Warning: not included in save state. -void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted)) -{ - advanceCallback = callback; -} - -bool IsScheduled(int event_type) -{ - if (!first) - return false; - Event *e = first; - while (e) { - if (e->type == event_type) - return true; - e = e->next; - } - return false; -} - -void RemoveEvent(int event_type) -{ - if (!first) - return; - while (first) - { - if (first->type == event_type) - { - Event *next = first->next; - FreeEvent(first); - first = next; - } - else - { - break; - } - } - if (!first) - return; - Event *prev = first; - Event *ptr = prev->next; - while (ptr) - { - if (ptr->type == event_type) - { - prev->next = ptr->next; - FreeEvent(ptr); - ptr = prev->next; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } -} - -void RemoveThreadsafeEvent(int event_type) -{ - std::lock_guard lk(externalEventSection); - if (!tsFirst) - { - return; - } - while (tsFirst) - { - if (tsFirst->type == event_type) - { - Event *next = tsFirst->next; - FreeTsEvent(tsFirst); - tsFirst = next; - } - else - { - break; - } - } - if (!tsFirst) - { - tsLast = NULL; - return; - } - Event *prev = tsFirst; - Event *ptr = prev->next; - while (ptr) - { - if (ptr->type == event_type) - { - prev->next = ptr->next; - if (ptr == tsLast) - tsLast = prev; - FreeTsEvent(ptr); - ptr = prev->next; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } -} - -void RemoveAllEvents(int event_type) -{ - RemoveThreadsafeEvent(event_type); - RemoveEvent(event_type); -} - -//This raise only the events required while the fifo is processing data -void ProcessFifoWaitEvents() -{ - while (first) - { - if (first->time <= globalTimer) - { - // LOG(TIMER, "[Scheduler] %s (%lld, %lld) ", - // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time); - Event* evt = first; - first = first->next; - event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); - FreeEvent(evt); - } - else - { - break; - } - } -} - -void MoveEvents() -{ - Common::AtomicStoreRelease(hasTsEvents, 0); - - std::lock_guard lk(externalEventSection); - // Move events from async queue into main queue - while (tsFirst) - { - Event *next = tsFirst->next; - AddEventToQueue(tsFirst); - tsFirst = next; - } - tsLast = NULL; - - // Move free events to threadsafe pool - while (allocatedTsEvents > 0 && eventPool) - { - Event *ev = eventPool; - eventPool = ev->next; - ev->next = eventTsPool; - eventTsPool = ev; - allocatedTsEvents--; - } -} - -void Advance() -{ - ERROR_LOG(TIME, "Unimplemented function!"); - //int cyclesExecuted = slicelength - currentMIPS->downcount; - //globalTimer += cyclesExecuted; - //currentMIPS->downcount = slicelength; - - //if (Common::AtomicLoadAcquire(hasTsEvents)) - // MoveEvents(); - //ProcessFifoWaitEvents(); - - //if (!first) - //{ - // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000"); - // currentMIPS->downcount += 10000; - //} - //else - //{ - // slicelength = (int)(first->time - globalTimer); - // if (slicelength > MAX_SLICE_LENGTH) - // slicelength = MAX_SLICE_LENGTH; - // currentMIPS->downcount = slicelength; - //} - //if (advanceCallback) - // advanceCallback(cyclesExecuted); -} - -void LogPendingEvents() -{ - Event *ptr = first; - while (ptr) - { - //INFO_LOG(TIMER, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type); - ptr = ptr->next; - } -} - -void Idle(int maxIdle) -{ - ERROR_LOG(TIME, "Unimplemented function!"); - //int cyclesDown = currentMIPS->downcount; - //if (maxIdle != 0 && cyclesDown > maxIdle) - // cyclesDown = maxIdle; - - //if (first && cyclesDown > 0) - //{ - // int cyclesExecuted = slicelength - currentMIPS->downcount; - // int cyclesNextEvent = (int) (first->time - globalTimer); - - // if (cyclesNextEvent < cyclesExecuted + cyclesDown) - // { - // cyclesDown = cyclesNextEvent - cyclesExecuted; - // // Now, now... no time machines, please. - // if (cyclesDown < 0) - // cyclesDown = 0; - // } - //} - - //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f)); - - //idledCycles += cyclesDown; - //currentMIPS->downcount -= cyclesDown; - //if (currentMIPS->downcount == 0) - // currentMIPS->downcount = -1; -} - -std::string GetScheduledEventsSummary() -{ - Event *ptr = first; - std::string text = "Scheduled events\n"; - text.reserve(1000); - while (ptr) - { - unsigned int t = ptr->type; - if (t >= event_types.size()) - PanicAlert("Invalid event type"); // %i", t); - const char *name = event_types[ptr->type].name; - if (!name) - name = "[unknown]"; - char temp[512]; - sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); - text += temp; - ptr = ptr->next; - } - return text; -} - -void Event_DoState(PointerWrap &p, BaseEvent *ev) -{ - p.Do(*ev); -} - -void DoState(PointerWrap &p) -{ - std::lock_guard lk(externalEventSection); - - auto s = p.Section("CoreTiming", 1); - if (!s) - return; - - int n = (int)event_types.size(); - p.Do(n); - // These (should) be filled in later by the modules. - event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT")); - - p.DoLinkedList(first, (Event **)NULL); - p.DoLinkedList(tsFirst, &tsLast); - - p.Do(g_clock_rate_arm11); - p.Do(slicelength); - p.Do(globalTimer); - p.Do(idledCycles); -} - -} // namespace diff --git a/src/core/src/core_timing.h b/src/core/src/core_timing.h deleted file mode 100644 index b62acea6..00000000 --- a/src/core/src/core_timing.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -// This is a system to schedule events into the emulated machine's future. Time is measured -// in main CPU clock cycles. - -// To schedule an event, you first have to register its type. This is where you pass in the -// callback. You then schedule events using the type id you get back. - -// See HW/SystemTimers.cpp for the main part of Dolphin's usage of this scheduler. - -// The int cyclesLate that the callbacks get is how many cycles late it was. -// So to schedule a new event on a regular basis: -// inside callback: -// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") - -#include "common.h" - -class PointerWrap; - -extern int g_clock_rate_arm11; - -inline s64 msToCycles(int ms) { - return g_clock_rate_arm11 / 1000 * ms; -} - -inline s64 msToCycles(float ms) { - return (s64)(g_clock_rate_arm11 * ms * (0.001f)); -} - -inline s64 msToCycles(double ms) { - return (s64)(g_clock_rate_arm11 * ms * (0.001)); -} - -inline s64 usToCycles(float us) { - return (s64)(g_clock_rate_arm11 * us * (0.000001f)); -} - -inline s64 usToCycles(int us) { - return (g_clock_rate_arm11 / 1000000 * (s64)us); -} - -inline s64 usToCycles(s64 us) { - return (g_clock_rate_arm11 / 1000000 * us); -} - -inline s64 usToCycles(u64 us) { - return (s64)(g_clock_rate_arm11 / 1000000 * us); -} - -inline s64 cyclesToUs(s64 cycles) { - return cycles / (g_clock_rate_arm11 / 1000000); -} - -namespace CoreTiming { - -void Init(); -void Shutdown(); - -typedef void(*TimedCallback)(u64 userdata, int cyclesLate); - -u64 GetTicks(); -u64 GetIdleTicks(); - -// Returns the event_type identifier. -int RegisterEvent(const char *name, TimedCallback callback); -// For save states. -void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback); -void UnregisterAllEvents(); - -// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, -// when we implement state saves. -void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata = 0); -void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata = 0); -void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata = 0); -s64 UnscheduleEvent(int event_type, u64 userdata); -s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata); - -void RemoveEvent(int event_type); -void RemoveThreadsafeEvent(int event_type); -void RemoveAllEvents(int event_type); -bool IsScheduled(int event_type); -void Advance(); -void MoveEvents(); -void ProcessFifoWaitEvents(); - -// Pretend that the main CPU has executed enough cycles to reach the next event. -void Idle(int maxIdle = 0); - -// Clear all pending events. This should ONLY be done on exit or state load. -void ClearPendingEvents(); - -void LogPendingEvents(); - -// Warning: not included in save states. -void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted)); - -std::string GetScheduledEventsSummary(); - -void DoState(PointerWrap &p); - -void SetClockFrequencyMHz(int cpuMhz); -int GetClockFrequencyMHz(); -extern int slicelength; - -}; // namespace diff --git a/src/core/src/elf/elf_reader.cpp b/src/core/src/elf/elf_reader.cpp deleted file mode 100644 index aef7c13e..00000000 --- a/src/core/src/elf/elf_reader.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "common.h" -#include "mem_map.h" - -#include "elf/elf_reader.h" -//#include "Core/Debugger/Debugger_SymbolMap.h" -//#include "Core/HW/Memmap.h" -//#include "Core/PowerPC/PPCSymbolDB.h" - -//void bswap(Elf32_Word &w) {w = Common::swap32(w);} -//void bswap(Elf32_Half &w) {w = Common::swap16(w);} - -#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway - -static void byteswapHeader(Elf32_Ehdr &ELF_H) -{ - bswap(ELF_H.e_type); - bswap(ELF_H.e_machine); - bswap(ELF_H.e_ehsize); - bswap(ELF_H.e_phentsize); - bswap(ELF_H.e_phnum); - bswap(ELF_H.e_shentsize); - bswap(ELF_H.e_shnum); - bswap(ELF_H.e_shstrndx); - bswap(ELF_H.e_version); - bswap(ELF_H.e_entry); - bswap(ELF_H.e_phoff); - bswap(ELF_H.e_shoff); - bswap(ELF_H.e_flags); -} - -static void byteswapSegment(Elf32_Phdr &sec) -{ - bswap(sec.p_align); - bswap(sec.p_filesz); - bswap(sec.p_flags); - bswap(sec.p_memsz); - bswap(sec.p_offset); - bswap(sec.p_paddr); - bswap(sec.p_vaddr); - bswap(sec.p_type); -} - -static void byteswapSection(Elf32_Shdr &sec) -{ - bswap(sec.sh_addr); - bswap(sec.sh_addralign); - bswap(sec.sh_entsize); - bswap(sec.sh_flags); - bswap(sec.sh_info); - bswap(sec.sh_link); - bswap(sec.sh_name); - bswap(sec.sh_offset); - bswap(sec.sh_size); - bswap(sec.sh_type); -} - -ElfReader::ElfReader(void *ptr) -{ - base = (char*)ptr; - base32 = (u32 *)ptr; - header = (Elf32_Ehdr*)ptr; - byteswapHeader(*header); - - segments = (Elf32_Phdr *)(base + header->e_phoff); - sections = (Elf32_Shdr *)(base + header->e_shoff); - - //for (int i = 0; i < GetNumSegments(); i++) - //{ - // byteswapSegment(segments[i]); - //} - - //for (int i = 0; i < GetNumSections(); i++) - //{ - // byteswapSection(sections[i]); - //} - entryPoint = header->e_entry; -} - -const char *ElfReader::GetSectionName(int section) const -{ - if (sections[section].sh_type == SHT_NULL) - return nullptr; - - int nameOffset = sections[section].sh_name; - char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); - - if (ptr) - return ptr + nameOffset; - else - return nullptr; -} - -bool ElfReader::LoadInto(u32 vaddr) -{ - DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); - -// sectionOffsets = new u32[GetNumSections()]; -// sectionAddrs = new u32[GetNumSections()]; - - // Should we relocate? - bRelocate = (header->e_type != ET_EXEC); - - if (bRelocate) - { - DEBUG_LOG(MASTER_LOG,"Relocatable module"); - entryPoint += vaddr; - } - else - { - DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); - } - - INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); - - // First pass : Get the bits into RAM - u32 segmentVAddr[32]; - - u32 baseAddress = bRelocate?vaddr:0; - - for (int i = 0; i < header->e_phnum; i++) - { - Elf32_Phdr *p = segments + i; - - INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); - - if (p->p_type == PT_LOAD) - { - segmentVAddr[i] = baseAddress + p->p_vaddr; - u32 writeAddr = segmentVAddr[i]; - - const u8 *src = GetSegmentPtr(i); - u8 *dst = Memory::GetPointer(writeAddr); - u32 srcSize = p->p_filesz; - u32 dstSize = p->p_memsz; - u32 *s = (u32*)src; - u32 *d = (u32*)dst; - for (int j = 0; j < (int)(srcSize + 3) / 4; j++) - { - *d++ = /*_byteswap_ulong*/(*s++); - } - if (srcSize < dstSize) - { - //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss - } - INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); - } - } - - /* - LOG(MASTER_LOG,"%i sections:", header->e_shnum); - - for (int i=0; ish_addr + baseAddress; - sectionOffsets[i] = writeAddr - vaddr; - sectionAddrs[i] = writeAddr; - - if (s->sh_flags & SHF_ALLOC) - { - LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size); - - } - else - { - LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags); - } - } -*/ - INFO_LOG(MASTER_LOG,"Done loading."); - return true; -} - -SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const -{ - for (int i = firstSection; i < header->e_shnum; i++) - { - const char *secname = GetSectionName(i); - - if (secname != nullptr && strcmp(name, secname) == 0) - return i; - } - return -1; -} - -/* TODO(bunnei): The following is verbatim from Dolphin - needs to be updated for this project: - -bool ElfReader::LoadSymbols() -{ - bool hasSymbols = false; - SectionID sec = GetSectionByName(".symtab"); - if (sec != -1) - { - int stringSection = sections[sec].sh_link; - const char *stringBase = (const char *)GetSectionDataPtr(stringSection); - - //We have a symbol table! - Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); - int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); - for (int sym = 0; sym < numSymbols; sym++) - { - int size = Common::swap32(symtab[sym].st_size); - if (size == 0) - continue; - - // int bind = symtab[sym].st_info >> 4; - int type = symtab[sym].st_info & 0xF; - int sectionIndex = Common::swap16(symtab[sym].st_shndx); - int value = Common::swap32(symtab[sym].st_value); - const char *name = stringBase + Common::swap32(symtab[sym].st_name); - if (bRelocate) - value += sectionAddrs[sectionIndex]; - - int symtype = Symbol::SYMBOL_DATA; - switch (type) - { - case STT_OBJECT: - symtype = Symbol::SYMBOL_DATA; break; - case STT_FUNC: - symtype = Symbol::SYMBOL_FUNCTION; break; - default: - continue; - } - g_symbolDB.AddKnownSymbol(value, size, name, symtype); - hasSymbols = true; - } - } - g_symbolDB.Index(); - return hasSymbols; -} -*/ diff --git a/src/core/src/elf/elf_reader.h b/src/core/src/elf/elf_reader.h deleted file mode 100644 index 9393a589..00000000 --- a/src/core/src/elf/elf_reader.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "elf/elf_types.h" - -enum KnownElfTypes -{ - KNOWNELF_PSP = 0, - KNOWNELF_DS = 1, - KNOWNELF_GBA = 2, - KNOWNELF_GC = 3, -}; - -typedef int SectionID; - -class ElfReader -{ -private: - char *base; - u32 *base32; - - Elf32_Ehdr *header; - Elf32_Phdr *segments; - Elf32_Shdr *sections; - - u32 *sectionAddrs; - bool bRelocate; - u32 entryPoint; - -public: - ElfReader(void *ptr); - ~ElfReader() { } - - u32 Read32(int off) const { return base32[off>>2]; } - - // Quick accessors - ElfType GetType() const { return (ElfType)(header->e_type); } - ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } - u32 GetEntryPoint() const { return entryPoint; } - u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadInto(u32 vaddr); - bool LoadSymbols(); - - int GetNumSegments() const { return (int)(header->e_phnum); } - int GetNumSections() const { return (int)(header->e_shnum); } - const u8 *GetPtr(int offset) const { return (u8*)base + offset; } - const char *GetSectionName(int section) const; - const u8 *GetSectionDataPtr(int section) const - { - if (section < 0 || section >= header->e_shnum) - return nullptr; - if (sections[section].sh_type != SHT_NOBITS) - return GetPtr(sections[section].sh_offset); - else - return nullptr; - } - bool IsCodeSection(int section) const - { - return sections[section].sh_type == SHT_PROGBITS; - } - const u8 *GetSegmentPtr(int segment) - { - return GetPtr(segments[segment].p_offset); - } - u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } - int GetSectionSize(SectionID section) const { return sections[section].sh_size; } - SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found - - bool DidRelocate() { - return bRelocate; - } -}; diff --git a/src/core/src/elf/elf_types.h b/src/core/src/elf/elf_types.h deleted file mode 100644 index f1bf3db7..00000000 --- a/src/core/src/elf/elf_types.h +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -// ELF Header Constants - -// File type -enum ElfType -{ - ET_NONE = 0, - ET_REL = 1, - ET_EXEC = 2, - ET_DYN = 3, - ET_CORE = 4, - ET_LOPROC = 0xFF00, - ET_HIPROC = 0xFFFF, -}; - -// Machine/Architecture -enum ElfMachine -{ - EM_NONE = 0, - EM_M32 = 1, - EM_SPARC = 2, - EM_386 = 3, - EM_68K = 4, - EM_88K = 5, - EM_860 = 7, - EM_MIPS = 8 -}; - -// File version -#define EV_NONE 0 -#define EV_CURRENT 1 - -// Identification index -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_PAD 7 -#define EI_NIDENT 16 - -// Magic number -#define ELFMAG0 0x7F -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' - -// File class -#define ELFCLASSNONE 0 -#define ELFCLASS32 1 -#define ELFCLASS64 2 - -// Encoding -#define ELFDATANONE 0 -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - - - -// Sections constants - -// Section indexes -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xFF00 -#define SHN_LOPROC 0xFF00 -#define SHN_HIPROC 0xFF1F -#define SHN_ABS 0xFFF1 -#define SHN_COMMON 0xFFF2 -#define SHN_HIRESERVE 0xFFFF - -// Section types -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7FFFFFFF -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xFFFFFFFF - -// Custom section types -#define SHT_PSPREL 0x700000a0 - - -// Section flags -enum ElfSectionFlags -{ - SHF_WRITE = 0x1, - SHF_ALLOC = 0x2, - SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xF0000000, -}; - -// Symbol binding -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 -#define STB_LOPROC 13 -#define STB_HIPROC 15 - -// Symbol types -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_LOPROC 13 -#define STT_HIPROC 15 - -// Undefined name -#define STN_UNDEF 0 - -// Relocation types -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GOT32 3 -#define R_386_PLT32 4 -#define R_386_COPY 5 -#define R_386_GLOB_DAT 6 -#define R_386_JMP_SLOT 7 -#define R_386_RELATIVE 8 -#define R_386_GOTOFF 9 -#define R_386_GOTPC 10 - -// Segment types -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7FFFFFFF - -// Segment flags -#define PF_X 1 -#define PF_W 2 -#define PF_R 4 - -// Dynamic Array Tags -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7FFFFFFF - -typedef unsigned int Elf32_Addr; -typedef unsigned short Elf32_Half; -typedef unsigned int Elf32_Off; -typedef signed int Elf32_Sword; -typedef unsigned int Elf32_Word; - - -// ELF file header -struct Elf32_Ehdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -// Section header -struct Elf32_Shdr -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -// Segment header -struct Elf32_Phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -}; - -// Symbol table entry -struct Elf32_Sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -}; - -#define ELF32_ST_BIND(i) ((i)>>4) -#define ELF32_ST_TYPE(i) ((i)&0xf) -#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) - -// Relocation entries -struct Elf32_Rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -}; - -struct Elf32_Rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -}; - -#define ELF32_R_SYM(i) ((i)>>8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) - - -struct Elf32_Dyn -{ - Elf32_Sword d_tag; - union - { - Elf32_Word d_val; - Elf32_Addr d_ptr; - } d_un; -}; diff --git a/src/core/src/file_sys/directory_file_system.cpp b/src/core/src/file_sys/directory_file_system.cpp deleted file mode 100644 index 29369eec..00000000 --- a/src/core/src/file_sys/directory_file_system.cpp +++ /dev/null @@ -1,671 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "chunk_file.h" -#include "file_util.h" -#include "directory_file_system.h" -//#include "ISOFileSystem.h" -//#include "Core/HLE/sceKernel.h" -//#include "file/zip_read.h" -#include "utf8.h" - -#if EMU_PLATFORM == PLATFORM_WINDOWS -#include -#include -#else -#include -#include -#include -#include -#endif - -#if HOST_IS_CASE_SENSITIVE -static bool FixFilenameCase(const std::string &path, std::string &filename) -{ - // Are we lucky? - if (File::Exists(path + filename)) - return true; - - size_t filenameSize = filename.size(); // size in bytes, not characters - for (size_t i = 0; i < filenameSize; i++) - { - filename[i] = tolower(filename[i]); - } - - //TODO: lookup filename in cache for "path" - - struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; } diren; - struct dirent_large; - struct dirent *result = NULL; - - DIR *dirp = opendir(path.c_str()); - if (!dirp) - return false; - - bool retValue = false; - - while (!readdir_r(dirp, (dirent*) &diren, &result) && result) - { - if (strlen(result->d_name) != filenameSize) - continue; - - size_t i; - for (i = 0; i < filenameSize; i++) - { - if (filename[i] != tolower(result->d_name[i])) - break; - } - - if (i < filenameSize) - continue; - - filename = result->d_name; - retValue = true; - } - - closedir(dirp); - - return retValue; -} - -bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior) -{ - size_t len = path.size(); - - if (len == 0) - return true; - - if (path[len - 1] == '/') - { - len--; - - if (len == 0) - return true; - } - - std::string fullPath; - fullPath.reserve(basePath.size() + len + 1); - fullPath.append(basePath); - - size_t start = 0; - while (start < len) - { - size_t i = path.find('/', start); - if (i == std::string::npos) - i = len; - - if (i > start) - { - std::string component = path.substr(start, i - start); - - // Fix case and stop on nonexistant path component - if (FixFilenameCase(fullPath, component) == false) { - // Still counts as success if partial matches allowed or if this - // is the last component and only the ones before it are required - return (behavior == FPC_PARTIAL_ALLOWED || (behavior == FPC_PATH_MUST_EXIST && i >= len)); - } - - path.replace(start, i - start, component); - - fullPath.append(component); - fullPath.append(1, '/'); - } - - start = i + 1; - } - - return true; -} - -#endif - -std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath) -{ - if (localpath.empty()) - return basePath; - - if (localpath[0] == '/') - localpath.erase(0,1); - //Convert slashes -#ifdef _WIN32 - for (size_t i = 0; i < localpath.size(); i++) { - if (localpath[i] == '/') - localpath[i] = '\\'; - } -#endif - return basePath + localpath; -} - -bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, FileAccess access) -{ -#if HOST_IS_CASE_SENSITIVE - if (access & (FILEACCESS_APPEND|FILEACCESS_CREATE|FILEACCESS_WRITE)) - { - DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); - if ( ! FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST) ) - return false; // or go on and attempt (for a better error code than just 0?) - } - // else we try fopen first (in case we're lucky) before simulating case insensitivity -#endif - - std::string fullName = GetLocalPath(basePath,fileName); - INFO_LOG(FILESYS,"Actually opening %s", fullName.c_str()); - - //TODO: tests, should append seek to end of file? seeking in a file opened for append? -#ifdef _WIN32 - // Convert parameters to Windows permissions and access - DWORD desired = 0; - DWORD sharemode = 0; - DWORD openmode = 0; - if (access & FILEACCESS_READ) { - desired |= GENERIC_READ; - sharemode |= FILE_SHARE_READ; - } - if (access & FILEACCESS_WRITE) { - desired |= GENERIC_WRITE; - sharemode |= FILE_SHARE_WRITE; - } - if (access & FILEACCESS_CREATE) { - openmode = OPEN_ALWAYS; - } else { - openmode = OPEN_EXISTING; - } - //Let's do it! - hFile = CreateFile(ConvertUTF8ToWString(fullName).c_str(), desired, sharemode, 0, openmode, 0, 0); - bool success = hFile != INVALID_HANDLE_VALUE; -#else - // Convert flags in access parameter to fopen access mode - const char *mode = NULL; - if (access & FILEACCESS_APPEND) { - if (access & FILEACCESS_READ) - mode = "ab+"; // append+read, create if needed - else - mode = "ab"; // append only, create if needed - } else if (access & FILEACCESS_WRITE) { - if (access & FILEACCESS_READ) { - // FILEACCESS_CREATE is ignored for read only, write only, and append - // because C++ standard fopen's nonexistant file creation can only be - // customized for files opened read+write - if (access & FILEACCESS_CREATE) - mode = "wb+"; // read+write, create if needed - else - mode = "rb+"; // read+write, but don't create - } else { - mode = "wb"; // write only, create if needed - } - } else { // neither write nor append, so default to read only - mode = "rb"; // read only, don't create - } - - hFile = fopen(fullName.c_str(), mode); - bool success = hFile != 0; -#endif - -#if HOST_IS_CASE_SENSITIVE - if (!success && - !(access & FILEACCESS_APPEND) && - !(access & FILEACCESS_CREATE) && - !(access & FILEACCESS_WRITE)) - { - if ( ! FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) ) - return 0; // or go on and attempt (for a better error code than just 0?) - fullName = GetLocalPath(basePath,fileName); - const char* fullNameC = fullName.c_str(); - - DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullNameC, fileName.c_str()); - - // And try again with the correct case this time -#ifdef _WIN32 - hFile = CreateFile(fullNameC, desired, sharemode, 0, openmode, 0, 0); - success = hFile != INVALID_HANDLE_VALUE; -#else - hFile = fopen(fullNameC, mode); - success = hFile != 0; -#endif - } -#endif - - return success; -} - -size_t DirectoryFileHandle::Read(u8* pointer, s64 size) -{ - size_t bytesRead = 0; -#ifdef _WIN32 - ::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0); -#else - bytesRead = fread(pointer, 1, size, hFile); -#endif - return bytesRead; -} - -size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) -{ - size_t bytesWritten = 0; -#ifdef _WIN32 - ::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0); -#else - bytesWritten = fwrite(pointer, 1, size, hFile); -#endif - return bytesWritten; -} - -size_t DirectoryFileHandle::Seek(s32 position, FileMove type) -{ -#ifdef _WIN32 - DWORD moveMethod = 0; - switch (type) { - case FILEMOVE_BEGIN: moveMethod = FILE_BEGIN; break; - case FILEMOVE_CURRENT: moveMethod = FILE_CURRENT; break; - case FILEMOVE_END: moveMethod = FILE_END; break; - } - DWORD newPos = SetFilePointer(hFile, (LONG)position, 0, moveMethod); - return newPos; -#else - int moveMethod = 0; - switch (type) { - case FILEMOVE_BEGIN: moveMethod = SEEK_SET; break; - case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break; - case FILEMOVE_END: moveMethod = SEEK_END; break; - } - fseek(hFile, position, moveMethod); - return ftell(hFile); -#endif -} - -void DirectoryFileHandle::Close() -{ -#ifdef _WIN32 - if (hFile != (HANDLE)-1) - CloseHandle(hFile); -#else - if (hFile != 0) - fclose(hFile); -#endif -} - -DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) { - File::CreateFullPath(basePath); - hAlloc = _hAlloc; -} - -DirectoryFileSystem::~DirectoryFileSystem() { - for (auto iter = entries.begin(); iter != entries.end(); ++iter) { - iter->second.hFile.Close(); - } -} - -std::string DirectoryFileSystem::GetLocalPath(std::string localpath) { - if (localpath.empty()) - return basePath; - - if (localpath[0] == '/') - localpath.erase(0,1); - //Convert slashes -#ifdef _WIN32 - for (size_t i = 0; i < localpath.size(); i++) { - if (localpath[i] == '/') - localpath[i] = '\\'; - } -#endif - return basePath + localpath; -} - -bool DirectoryFileSystem::MkDir(const std::string &dirname) { -#if HOST_IS_CASE_SENSITIVE - // Must fix case BEFORE attempting, because MkDir would create - // duplicate (different case) directories - - std::string fixedCase = dirname; - if ( ! FixPathCase(basePath,fixedCase, FPC_PARTIAL_ALLOWED) ) - return false; - - return File::CreateFullPath(GetLocalPath(fixedCase)); -#else - return File::CreateFullPath(GetLocalPath(dirname)); -#endif -} - -bool DirectoryFileSystem::RmDir(const std::string &dirname) { - std::string fullName = GetLocalPath(dirname); - -#if HOST_IS_CASE_SENSITIVE - // Maybe we're lucky? - if (File::DeleteDirRecursively(fullName)) - return true; - - // Nope, fix case and try again - fullName = dirname; - if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) ) - return false; // or go on and attempt (for a better error code than just false?) - - fullName = GetLocalPath(fullName); -#endif - -/*#ifdef _WIN32 - return RemoveDirectory(fullName.c_str()) == TRUE; -#else - return 0 == rmdir(fullName.c_str()); -#endif*/ - return File::DeleteDirRecursively(fullName); -} - -int DirectoryFileSystem::RenameFile(const std::string &from, const std::string &to) { - std::string fullTo = to; - - // Rename ignores the path (even if specified) on to. - size_t chop_at = to.find_last_of('/'); - if (chop_at != to.npos) - fullTo = to.substr(chop_at + 1); - - // Now put it in the same directory as from. - size_t dirname_end = from.find_last_of('/'); - if (dirname_end != from.npos) - fullTo = from.substr(0, dirname_end + 1) + fullTo; - - // At this point, we should check if the paths match and give an already exists error. - if (from == fullTo) - return -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS; - - std::string fullFrom = GetLocalPath(from); - -#if HOST_IS_CASE_SENSITIVE - // In case TO should overwrite a file with different case - if ( ! FixPathCase(basePath,fullTo, FPC_PATH_MUST_EXIST) ) - return -1; // or go on and attempt (for a better error code than just false?) -#endif - - fullTo = GetLocalPath(fullTo); - const char * fullToC = fullTo.c_str(); - -#ifdef _WIN32 - bool retValue = (MoveFile(ConvertUTF8ToWString(fullFrom).c_str(), ConvertUTF8ToWString(fullToC).c_str()) == TRUE); -#else - bool retValue = (0 == rename(fullFrom.c_str(), fullToC)); -#endif - -#if HOST_IS_CASE_SENSITIVE - if (! retValue) - { - // May have failed due to case sensitivity on FROM, so try again - fullFrom = from; - if ( ! FixPathCase(basePath,fullFrom, FPC_FILE_MUST_EXIST) ) - return -1; // or go on and attempt (for a better error code than just false?) - fullFrom = GetLocalPath(fullFrom); - -#ifdef _WIN32 - retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE); -#else - retValue = (0 == rename(fullFrom.c_str(), fullToC)); -#endif - } -#endif - - // TODO: Better error codes. - return retValue ? 0 : -1;//SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS; -} - -bool DirectoryFileSystem::RemoveFile(const std::string &filename) { - std::string fullName = GetLocalPath(filename); -#ifdef _WIN32 - bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE); -#else - bool retValue = (0 == unlink(fullName.c_str())); -#endif - -#if HOST_IS_CASE_SENSITIVE - if (! retValue) - { - // May have failed due to case sensitivity, so try again - fullName = filename; - if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) ) - return false; // or go on and attempt (for a better error code than just false?) - fullName = GetLocalPath(fullName); - -#ifdef _WIN32 - retValue = (::DeleteFileA(fullName.c_str()) == TRUE); -#else - retValue = (0 == unlink(fullName.c_str())); -#endif - } -#endif - - return retValue; -} - -u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { - OpenFileEntry entry; - bool success = entry.hFile.Open(basePath,filename,access); - - if (!success) { -#ifdef _WIN32 - ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access); -#else - ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, access = %i", (int)access); -#endif - //wwwwaaaaahh!! - return 0; - } else { -#ifdef _WIN32 - if (access & FILEACCESS_APPEND) - entry.hFile.Seek(0,FILEMOVE_END); -#endif - - u32 newHandle = hAlloc->GetNewHandle(); - entries[newHandle] = entry; - - return newHandle; - } -} - -void DirectoryFileSystem::CloseFile(u32 handle) { - EntryMap::iterator iter = entries.find(handle); - if (iter != entries.end()) { - hAlloc->FreeHandle(handle); - iter->second.hFile.Close(); - entries.erase(iter); - } else { - //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle); - } -} - -bool DirectoryFileSystem::OwnsHandle(u32 handle) { - EntryMap::iterator iter = entries.find(handle); - return (iter != entries.end()); -} - -size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { - EntryMap::iterator iter = entries.find(handle); - if (iter != entries.end()) - { - size_t bytesRead = iter->second.hFile.Read(pointer,size); - return bytesRead; - } else { - //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle); - return 0; - } -} - -size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { - EntryMap::iterator iter = entries.find(handle); - if (iter != entries.end()) - { - size_t bytesWritten = iter->second.hFile.Write(pointer,size); - return bytesWritten; - } else { - //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot write to file that hasn't been opened: %08x", handle); - return 0; - } -} - -size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { - EntryMap::iterator iter = entries.find(handle); - if (iter != entries.end()) { - return iter->second.hFile.Seek(position,type); - } else { - //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle); - return 0; - } -} - -FileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { - FileInfo x; - x.name = filename; - - std::string fullName = GetLocalPath(filename); - if (! File::Exists(fullName)) { -#if HOST_IS_CASE_SENSITIVE - if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST)) - return x; - fullName = GetLocalPath(filename); - - if (! File::Exists(fullName)) - return x; -#else - return x; -#endif - } - x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; - x.exists = true; - - if (x.type != FILETYPE_DIRECTORY) - { -#ifdef _WIN32 - struct _stat64i32 s; - _wstat64i32(ConvertUTF8ToWString(fullName).c_str(), &s); -#else - struct stat s; - stat(fullName.c_str(), &s); -#endif - - x.size = File::GetSize(fullName); - x.access = s.st_mode & 0x1FF; - localtime_r((time_t*)&s.st_atime,&x.atime); - localtime_r((time_t*)&s.st_ctime,&x.ctime); - localtime_r((time_t*)&s.st_mtime,&x.mtime); - } - - return x; -} - -bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { - outpath = GetLocalPath(inpath); - return true; -} - -#ifdef _WIN32 -#define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL - -static void tmFromFiletime(tm &dest, FILETIME &src) -{ - u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; - u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; - - time_t t = (time_t) (from_1970_us / 1000000UL); - localtime_r(&t, &dest); -} -#endif - -std::vector DirectoryFileSystem::GetDirListing(std::string path) { - std::vector myVector; -#ifdef _WIN32 - WIN32_FIND_DATA findData; - HANDLE hFind; - - std::string w32path = GetLocalPath(path) + "\\*.*"; - - hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData); - - if (hFind == INVALID_HANDLE_VALUE) { - return myVector; //the empty list - } - - while (true) { - FileInfo entry; - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - entry.type = FILETYPE_DIRECTORY; - else - entry.type = FILETYPE_NORMAL; - - // TODO: Make this more correct? - entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777; - // TODO: is this just for .. or all subdirectories? Need to add a directory to the test - // to find out. Also why so different than the old test results? - if (!wcscmp(findData.cFileName, L"..") ) - entry.size = 4096; - else - entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); - entry.name = ConvertWStringToUTF8(findData.cFileName); - tmFromFiletime(entry.atime, findData.ftLastAccessTime); - tmFromFiletime(entry.ctime, findData.ftCreationTime); - tmFromFiletime(entry.mtime, findData.ftLastWriteTime); - myVector.push_back(entry); - - int retval = FindNextFile(hFind, &findData); - if (!retval) - break; - } -#else - dirent *dirp; - std::string localPath = GetLocalPath(path); - DIR *dp = opendir(localPath.c_str()); - -#if HOST_IS_CASE_SENSITIVE - if(dp == NULL && FixPathCase(basePath,path, FPC_FILE_MUST_EXIST)) { - // May have failed due to case sensitivity, try again - localPath = GetLocalPath(path); - dp = opendir(localPath.c_str()); - } -#endif - - if (dp == NULL) { - ERROR_LOG(FILESYS,"Error opening directory %s\n",path.c_str()); - return myVector; - } - - while ((dirp = readdir(dp)) != NULL) { - FileInfo entry; - struct stat s; - std::string fullName = GetLocalPath(path) + "/"+dirp->d_name; - stat(fullName.c_str(), &s); - if (S_ISDIR(s.st_mode)) - entry.type = FILETYPE_DIRECTORY; - else - entry.type = FILETYPE_NORMAL; - entry.access = s.st_mode & 0x1FF; - entry.name = dirp->d_name; - entry.size = s.st_size; - localtime_r((time_t*)&s.st_atime,&entry.atime); - localtime_r((time_t*)&s.st_ctime,&entry.ctime); - localtime_r((time_t*)&s.st_mtime,&entry.mtime); - myVector.push_back(entry); - } - closedir(dp); -#endif - return myVector; -} - -void DirectoryFileSystem::DoState(PointerWrap &p) { - if (!entries.empty()) { - p.SetError(p.ERROR_WARNING); - ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); - } -} diff --git a/src/core/src/file_sys/directory_file_system.h b/src/core/src/file_sys/directory_file_system.h deleted file mode 100644 index a11331a2..00000000 --- a/src/core/src/file_sys/directory_file_system.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#ifndef CORE_FILE_SYS_DIRECTORY_H_ -#define CORE_FILE_SYS_DIRECTORY_H_ - -// TODO: Remove the Windows-specific code, FILE is fine there too. - -#include - -#include "file_sys.h" - -#ifdef _WIN32 -typedef void * HANDLE; -#endif - -#if defined(__APPLE__) - -#if TARGET_OS_IPHONE -#define HOST_IS_CASE_SENSITIVE 1 -#elif TARGET_IPHONE_SIMULATOR -#define HOST_IS_CASE_SENSITIVE 0 -#else -// Mac OSX case sensitivity defaults off, but is user configurable (when -// creating a filesytem), so assume the worst: -#define HOST_IS_CASE_SENSITIVE 1 -#endif - -#elif defined(_WIN32) || defined(__SYMBIAN32__) -#define HOST_IS_CASE_SENSITIVE 0 - -#else // Android, Linux, BSD (and the rest?) -#define HOST_IS_CASE_SENSITIVE 1 - -#endif - -#if HOST_IS_CASE_SENSITIVE -enum FixPathCaseBehavior { - FPC_FILE_MUST_EXIST, // all path components must exist (rmdir, move from) - FPC_PATH_MUST_EXIST, // all except the last one must exist - still tries to fix last one (fopen, move to) - FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive) -}; - -bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior); -#endif - -struct DirectoryFileHandle -{ -#ifdef _WIN32 - HANDLE hFile; -#else - FILE* hFile; -#endif - DirectoryFileHandle() - { -#ifdef _WIN32 - hFile = (HANDLE)-1; -#else - hFile = 0; -#endif - } - - std::string GetLocalPath(std::string& basePath, std::string localpath); - bool Open(std::string& basePath, std::string& fileName, FileAccess access); - size_t Read(u8* pointer, s64 size); - size_t Write(const u8* pointer, s64 size); - size_t Seek(s32 position, FileMove type); - void Close(); -}; - -class DirectoryFileSystem : public IFileSystem { -public: - DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); - ~DirectoryFileSystem(); - - void DoState(PointerWrap &p); - std::vector GetDirListing(std::string path); - u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL); - void CloseFile(u32 handle); - size_t ReadFile(u32 handle, u8 *pointer, s64 size); - size_t WriteFile(u32 handle, const u8 *pointer, s64 size); - size_t SeekFile(u32 handle, s32 position, FileMove type); - FileInfo GetFileInfo(std::string filename); - bool OwnsHandle(u32 handle); - - bool MkDir(const std::string &dirname); - bool RmDir(const std::string &dirname); - int RenameFile(const std::string &from, const std::string &to); - bool RemoveFile(const std::string &filename); - bool GetHostPath(const std::string &inpath, std::string &outpath); - -private: - struct OpenFileEntry { - DirectoryFileHandle hFile; - }; - - typedef std::map EntryMap; - EntryMap entries; - std::string basePath; - IHandleAllocator *hAlloc; - - // In case of Windows: Translate slashes, etc. - std::string GetLocalPath(std::string localpath); -}; - -// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts. -// Very inefficient - always load the whole file on open. -class VFSFileSystem : public IFileSystem { -public: - VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); - ~VFSFileSystem(); - - void DoState(PointerWrap &p); - std::vector GetDirListing(std::string path); - u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL); - void CloseFile(u32 handle); - size_t ReadFile(u32 handle, u8 *pointer, s64 size); - size_t WriteFile(u32 handle, const u8 *pointer, s64 size); - size_t SeekFile(u32 handle, s32 position, FileMove type); - FileInfo GetFileInfo(std::string filename); - bool OwnsHandle(u32 handle); - - bool MkDir(const std::string &dirname); - bool RmDir(const std::string &dirname); - int RenameFile(const std::string &from, const std::string &to); - bool RemoveFile(const std::string &filename); - bool GetHostPath(const std::string &inpath, std::string &outpath); - -private: - struct OpenFileEntry { - u8 *fileData; - size_t size; - size_t seekPos; - }; - - typedef std::map EntryMap; - EntryMap entries; - std::string basePath; - IHandleAllocator *hAlloc; - - std::string GetLocalPath(std::string localpath); -}; - -#endif // CORE_FILE_SYS_DIRECTORY_H_ diff --git a/src/core/src/file_sys/file_sys.h b/src/core/src/file_sys/file_sys.h deleted file mode 100644 index b27e36c8..00000000 --- a/src/core/src/file_sys/file_sys.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "common.h" -#include "chunk_file.h" - -enum FileAccess { - FILEACCESS_NONE=0, - FILEACCESS_READ=1, - FILEACCESS_WRITE=2, - FILEACCESS_APPEND=4, - FILEACCESS_CREATE=8 -}; - -enum FileMove { - FILEMOVE_BEGIN=0, - FILEMOVE_CURRENT=1, - FILEMOVE_END=2 -}; - -enum FileType { - FILETYPE_NORMAL=1, - FILETYPE_DIRECTORY=2 -}; - - -class IHandleAllocator { -public: - virtual ~IHandleAllocator() {} - virtual u32 GetNewHandle() = 0; - virtual void FreeHandle(u32 handle) = 0; -}; - -class SequentialHandleAllocator : public IHandleAllocator { -public: - SequentialHandleAllocator() : handle_(1) {} - virtual u32 GetNewHandle() { return handle_++; } - virtual void FreeHandle(u32 handle) {} -private: - int handle_; -}; - -struct FileInfo { - FileInfo() - : size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0) {} - - void DoState(PointerWrap &p) { - auto s = p.Section("FileInfo", 1); - if (!s) - return; - - p.Do(name); - p.Do(size); - p.Do(access); - p.Do(exists); - p.Do(type); - p.Do(atime); - p.Do(ctime); - p.Do(mtime); - p.Do(isOnSectorSystem); - p.Do(startSector); - p.Do(numSectors); - p.Do(sectorSize); - } - - std::string name; - s64 size; - u32 access; //unix 777 - bool exists; - FileType type; - - tm atime; - tm ctime; - tm mtime; - - bool isOnSectorSystem; - u32 startSector; - u32 numSectors; - u32 sectorSize; -}; - - -class IFileSystem { -public: - virtual ~IFileSystem() {} - - virtual void DoState(PointerWrap &p) = 0; - virtual std::vector GetDirListing(std::string path) = 0; - virtual u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) = 0; - virtual void CloseFile(u32 handle) = 0; - virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size) = 0; - virtual size_t WriteFile(u32 handle, const u8 *pointer, s64 size) = 0; - virtual size_t SeekFile(u32 handle, s32 position, FileMove type) = 0; - virtual FileInfo GetFileInfo(std::string filename) = 0; - virtual bool OwnsHandle(u32 handle) = 0; - virtual bool MkDir(const std::string &dirname) = 0; - virtual bool RmDir(const std::string &dirname) = 0; - virtual int RenameFile(const std::string &from, const std::string &to) = 0; - virtual bool RemoveFile(const std::string &filename) = 0; - virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0; -}; - - -class EmptyFileSystem : public IFileSystem { -public: - virtual void DoState(PointerWrap &p) {} - std::vector GetDirListing(std::string path) {std::vector vec; return vec;} - u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) {return 0;} - void CloseFile(u32 handle) {} - size_t ReadFile(u32 handle, u8 *pointer, s64 size) {return 0;} - size_t WriteFile(u32 handle, const u8 *pointer, s64 size) {return 0;} - size_t SeekFile(u32 handle, s32 position, FileMove type) {return 0;} - FileInfo GetFileInfo(std::string filename) {FileInfo f; return f;} - bool OwnsHandle(u32 handle) {return false;} - virtual bool MkDir(const std::string &dirname) {return false;} - virtual bool RmDir(const std::string &dirname) {return false;} - virtual int RenameFile(const std::string &from, const std::string &to) {return -1;} - virtual bool RemoveFile(const std::string &filename) {return false;} - virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;} -}; - - diff --git a/src/core/src/file_sys/meta_file_system.cpp b/src/core/src/file_sys/meta_file_system.cpp deleted file mode 100644 index f86c3cb1..00000000 --- a/src/core/src/file_sys/meta_file_system.cpp +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include -#include "string_util.h" -#include "file_sys/meta_file_system.h" -//#include "Core/HLE/sceKernelThread.h" -//#include "Core/Reporting.h" - -static bool ApplyPathStringToComponentsVector(std::vector &vector, const std::string &pathString) -{ - size_t len = pathString.length(); - size_t start = 0; - - while (start < len) - { - size_t i = pathString.find('/', start); - if (i == std::string::npos) - i = len; - - if (i > start) - { - std::string component = pathString.substr(start, i - start); - if (component != ".") - { - if (component == "..") - { - if (vector.size() != 0) - { - vector.pop_back(); - } - else - { - // The PSP silently ignores attempts to .. to parent of root directory - WARN_LOG(FILESYS, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str()); - } - } - else - { - vector.push_back(component); - } - } - } - - start = i + 1; - } - - return true; -} - -/* - * Changes relative paths to absolute, removes ".", "..", and trailing "/" - * "drive:./blah" is absolute (ignore the dot) and "/blah" is relative (because it's missing "drive:") - * babel (and possibly other games) use "/directoryThatDoesNotExist/../directoryThatExists/filename" - */ -static bool RealPath(const std::string ¤tDirectory, const std::string &inPath, std::string &outPath) -{ - size_t inLen = inPath.length(); - if (inLen == 0) - { - WARN_LOG(FILESYS, "RealPath: inPath is empty"); - outPath = currentDirectory; - return true; - } - - size_t inColon = inPath.find(':'); - if (inColon + 1 == inLen) - { - // There's nothing after the colon, e.g. umd0: - this is perfectly valid. - outPath = inPath; - return true; - } - - bool relative = (inColon == std::string::npos); - - std::string prefix, inAfterColon; - std::vector cmpnts; // path components - size_t outPathCapacityGuess = inPath.length(); - - if (relative) - { - size_t curDirLen = currentDirectory.length(); - if (curDirLen == 0) - { - ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str()); - return false; - } - - size_t curDirColon = currentDirectory.find(':'); - if (curDirColon == std::string::npos) - { - ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str()); - return false; - } - if (curDirColon + 1 == curDirLen) - { - ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str()); - } - else - { - const std::string curDirAfter = currentDirectory.substr(curDirColon + 1); - if (! ApplyPathStringToComponentsVector(cmpnts, curDirAfter) ) - { - ERROR_LOG(FILESYS,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str()); - return false; - } - - outPathCapacityGuess += curDirLen; - } - - prefix = currentDirectory.substr(0, curDirColon + 1); - inAfterColon = inPath; - } - else - { - prefix = inPath.substr(0, inColon + 1); - inAfterColon = inPath.substr(inColon + 1); - } - - // Special case: "disc0:" is different from "disc0:/", so keep track of the single slash. - if (inAfterColon == "/") - { - outPath = prefix + inAfterColon; - return true; - } - - if (! ApplyPathStringToComponentsVector(cmpnts, inAfterColon) ) - { - WARN_LOG(FILESYS, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str()); - return false; - } - - outPath.clear(); - outPath.reserve(outPathCapacityGuess); - - outPath.append(prefix); - - size_t numCmpnts = cmpnts.size(); - for (size_t i = 0; i < numCmpnts; i++) - { - outPath.append(1, '/'); - outPath.append(cmpnts[i]); - } - - return true; -} - -IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) -{ - std::lock_guard guard(lock); - for (size_t i = 0; i < fileSystems.size(); i++) - { - if (fileSystems[i].system->OwnsHandle(handle)) - return fileSystems[i].system; //got it! - } - //none found? - return 0; -} - -bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) -{ - std::lock_guard guard(lock); - std::string realpath; - - // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) - // appears to mean the current directory on the UMD. Let's just assume the current directory. - std::string inpath = _inpath; - if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) { - INFO_LOG(FILESYS, "Host0 path detected, stripping: %s", inpath.c_str()); - inpath = inpath.substr(strlen("host0:")); - } - - const std::string *currentDirectory = &startingDirectory; - - _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread"); - - int currentThread = 0;//__KernelGetCurThread(); - currentDir_t::iterator it = currentDir.find(currentThread); - if (it == currentDir.end()) - { - //Attempt to emulate SCE_KERNEL_ERROR_NOCWD / 8002032C: may break things requiring fixes elsewhere - if (inpath.find(':') == std::string::npos /* means path is relative */) - { - lastOpenError = -1;//SCE_KERNEL_ERROR_NOCWD; - WARN_LOG(FILESYS, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); - } - } - else - { - currentDirectory = &(it->second); - } - - if ( RealPath(*currentDirectory, inpath, realpath) ) - { - for (size_t i = 0; i < fileSystems.size(); i++) - { - size_t prefLen = fileSystems[i].prefix.size(); - if (strncasecmp(fileSystems[i].prefix.c_str(), realpath.c_str(), prefLen) == 0) - { - outpath = realpath.substr(prefLen); - *system = &(fileSystems[i]); - - INFO_LOG(FILESYS, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); - - return true; - } - } - } - - DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); - return false; -} - -void MetaFileSystem::Mount(std::string prefix, IFileSystem *system) -{ - std::lock_guard guard(lock); - MountPoint x; - x.prefix = prefix; - x.system = system; - fileSystems.push_back(x); -} - -void MetaFileSystem::Unmount(std::string prefix, IFileSystem *system) -{ - std::lock_guard guard(lock); - MountPoint x; - x.prefix = prefix; - x.system = system; - fileSystems.erase(std::remove(fileSystems.begin(), fileSystems.end(), x), fileSystems.end()); -} - -void MetaFileSystem::Shutdown() -{ - std::lock_guard guard(lock); - current = 6; - - // Ownership is a bit convoluted. Let's just delete everything once. - - std::set toDelete; - for (size_t i = 0; i < fileSystems.size(); i++) { - toDelete.insert(fileSystems[i].system); - } - - for (auto iter = toDelete.begin(); iter != toDelete.end(); ++iter) - { - delete *iter; - } - - fileSystems.clear(); - currentDir.clear(); - startingDirectory = ""; -} - -u32 MetaFileSystem::OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename) -{ - std::lock_guard guard(lock); - u32 h = OpenFile(filename, access, devicename); - error = lastOpenError; - return h; -} - -u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) -{ - std::lock_guard guard(lock); - lastOpenError = 0; - std::string of; - MountPoint *mount; - if (MapFilePath(filename, of, &mount)) - { - return mount->system->OpenFile(of, access, mount->prefix.c_str()); - } - else - { - return 0; - } -} - -FileInfo MetaFileSystem::GetFileInfo(std::string filename) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(filename, of, &system)) - { - return system->GetFileInfo(of); - } - else - { - FileInfo bogus; // TODO - return bogus; - } -} - -bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(inpath, of, &system)) { - return system->GetHostPath(of, outpath); - } else { - return false; - } -} - -std::vector MetaFileSystem::GetDirListing(std::string path) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(path, of, &system)) - { - return system->GetDirListing(of); - } - else - { - std::vector empty; - return empty; - } -} - -void MetaFileSystem::ThreadEnded(int threadID) -{ - std::lock_guard guard(lock); - currentDir.erase(threadID); -} - -int MetaFileSystem::ChDir(const std::string &dir) -{ - std::lock_guard guard(lock); - // Retain the old path and fail if the arg is 1023 bytes or longer. - if (dir.size() >= 1023) - return -1;//SCE_KERNEL_ERROR_NAMETOOLONG; - - _assert_msg_(FILESYS, false, "must implement equiv of __KernelGetCurThread"); - - int curThread = 0; //__KernelGetCurThread(); - - std::string of; - MountPoint *mountPoint; - if (MapFilePath(dir, of, &mountPoint)) - { - currentDir[curThread] = mountPoint->prefix + of; - return 0; - } - else - { - for (size_t i = 0; i < fileSystems.size(); i++) - { - const std::string &prefix = fileSystems[i].prefix; - if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0) - { - // The PSP is completely happy with invalid current dirs as long as they have a valid device. - WARN_LOG(FILESYS, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str()); - currentDir[curThread] = dir; - return 0; - } - } - - WARN_LOG(FILESYS, "ChDir failed to map device for \"%s\", failing", dir.c_str()); - return -1;//SCE_KERNEL_ERROR_NODEV; - } -} - -bool MetaFileSystem::MkDir(const std::string &dirname) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(dirname, of, &system)) - { - return system->MkDir(of); - } - else - { - return false; - } -} - -bool MetaFileSystem::RmDir(const std::string &dirname) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(dirname, of, &system)) - { - return system->RmDir(of); - } - else - { - return false; - } -} - -int MetaFileSystem::RenameFile(const std::string &from, const std::string &to) -{ - std::lock_guard guard(lock); - std::string of; - std::string rf; - IFileSystem *osystem; - IFileSystem *rsystem = NULL; - if (MapFilePath(from, of, &osystem)) - { - // If it's a relative path, it seems to always use from's filesystem. - if (to.find(":/") != to.npos) - { - if (!MapFilePath(to, rf, &rsystem)) - return -1; - } - else - { - rf = to; - rsystem = osystem; - } - - if (osystem != rsystem) - return -1;//SCE_KERNEL_ERROR_XDEV; - - return osystem->RenameFile(of, rf); - } - else - { - return -1; - } -} - -bool MetaFileSystem::RemoveFile(const std::string &filename) -{ - std::lock_guard guard(lock); - std::string of; - IFileSystem *system; - if (MapFilePath(filename, of, &system)) - { - return system->RemoveFile(of); - } - else - { - return false; - } -} - -void MetaFileSystem::CloseFile(u32 handle) -{ - std::lock_guard guard(lock); - IFileSystem *sys = GetHandleOwner(handle); - if (sys) - sys->CloseFile(handle); -} - -size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) -{ - std::lock_guard guard(lock); - IFileSystem *sys = GetHandleOwner(handle); - if (sys) - return sys->ReadFile(handle,pointer,size); - else - return 0; -} - -size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) -{ - std::lock_guard guard(lock); - IFileSystem *sys = GetHandleOwner(handle); - if (sys) - return sys->WriteFile(handle,pointer,size); - else - return 0; -} - -size_t MetaFileSystem::SeekFile(u32 handle, s32 position, FileMove type) -{ - std::lock_guard guard(lock); - IFileSystem *sys = GetHandleOwner(handle); - if (sys) - return sys->SeekFile(handle,position,type); - else - return 0; -} - -void MetaFileSystem::DoState(PointerWrap &p) -{ - std::lock_guard guard(lock); - - auto s = p.Section("MetaFileSystem", 1); - if (!s) - return; - - p.Do(current); - - // Save/load per-thread current directory map - p.Do(currentDir); - - u32 n = (u32) fileSystems.size(); - p.Do(n); - if (n != (u32) fileSystems.size()) - { - p.SetError(p.ERROR_FAILURE); - ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match."); - return; - } - - for (u32 i = 0; i < n; ++i) - fileSystems[i].system->DoState(p); -} - diff --git a/src/core/src/file_sys/meta_file_system.h b/src/core/src/file_sys/meta_file_system.h deleted file mode 100644 index 0de23d49..00000000 --- a/src/core/src/file_sys/meta_file_system.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "std_mutex.h" -#include "file_sys.h" - -class MetaFileSystem : public IHandleAllocator, public IFileSystem -{ -private: - u32 current; - struct MountPoint - { - std::string prefix; - IFileSystem *system; - - bool operator == (const MountPoint &other) const - { - return prefix == other.prefix && system == other.system; - } - }; - std::vector fileSystems; - - typedef std::map currentDir_t; - currentDir_t currentDir; - - std::string startingDirectory; - int lastOpenError; - std::recursive_mutex lock; - -public: - MetaFileSystem() - { - current = 6; // what? - } - - void Mount(std::string prefix, IFileSystem *system); - void Unmount(std::string prefix, IFileSystem *system); - - void ThreadEnded(int threadID); - - void Shutdown(); - - u32 GetNewHandle() {return current++;} - void FreeHandle(u32 handle) {} - - virtual void DoState(PointerWrap &p); - - IFileSystem *GetHandleOwner(u32 handle); - bool MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system); - - inline bool MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system) - { - MountPoint *mountPoint; - if (MapFilePath(_inpath, outpath, &mountPoint)) - { - *system = mountPoint->system; - return true; - } - - return false; - } - - // Only possible if a file system is a DirectoryFileSystem or similar. - bool GetHostPath(const std::string &inpath, std::string &outpath); - - std::vector GetDirListing(std::string path); - u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL); - u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL); - void CloseFile(u32 handle); - size_t ReadFile(u32 handle, u8 *pointer, s64 size); - size_t WriteFile(u32 handle, const u8 *pointer, s64 size); - size_t SeekFile(u32 handle, s32 position, FileMove type); - FileInfo GetFileInfo(std::string filename); - bool OwnsHandle(u32 handle) {return false;} - inline size_t GetSeekPos(u32 handle) - { - return SeekFile(handle, 0, FILEMOVE_CURRENT); - } - - virtual int ChDir(const std::string &dir); - - virtual bool MkDir(const std::string &dirname); - virtual bool RmDir(const std::string &dirname); - virtual int RenameFile(const std::string &from, const std::string &to); - virtual bool RemoveFile(const std::string &filename); - - // TODO: void IoCtl(...) - - void SetStartingDirectory(const std::string &dir) { - std::lock_guard guard(lock); - startingDirectory = dir; - } -}; diff --git a/src/core/src/hw/hw.cpp b/src/core/src/hw/hw.cpp deleted file mode 100644 index 57be4d6a..00000000 --- a/src/core/src/hw/hw.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "log.h" -#include "hw/hw.h" -#include "hw/hw_lcd.h" - -namespace HW { - -template -inline void Read(T &var, const u32 addr) { - NOTICE_LOG(HW, "Hardware read from address %08X", addr); -} - -template -inline void Write(u32 addr, const T data) { - NOTICE_LOG(HW, "Hardware write to address %08X", addr); -} - -// Explicitly instantiate template functions because we aren't defining this in the header: - -template void Read(u64 &var, const u32 addr); -template void Read(u32 &var, const u32 addr); -template void Read(u16 &var, const u32 addr); -template void Read(u8 &var, const u32 addr); - -template void Write(u32 addr, const u64 data); -template void Write(u32 addr, const u32 data); -template void Write(u32 addr, const u16 data); -template void Write(u32 addr, const u8 data); - -/// Update hardware -void Update() { - LCD::Update(); -} - -/// Initialize hardware -void Init() { - LCD::Init(); - NOTICE_LOG(HW, "Hardware initialized OK"); -} - -/// Shutdown hardware -void Shutdown() { - NOTICE_LOG(HW, "Hardware shutdown OK"); -} - -} \ No newline at end of file diff --git a/src/core/src/hw/hw.h b/src/core/src/hw/hw.h deleted file mode 100644 index 5b0cc8c8..00000000 --- a/src/core/src/hw/hw.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common_types.h" - -namespace HW { - -template -inline void Read(T &var, const u32 addr); - -template -inline void Write(u32 addr, const T data); - -/// Update hardware -void Update(); - -/// Initialize hardware -void Init(); - -/// Shutdown hardware -void Shutdown(); - -} // namespace diff --git a/src/core/src/hw/hw_lcd.cpp b/src/core/src/hw/hw_lcd.cpp deleted file mode 100644 index ad346c79..00000000 --- a/src/core/src/hw/hw_lcd.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "log.h" -#include "core.h" -#include "hw_lcd.h" -#include "video_core.h" - -namespace LCD { - -static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second - -u64 g_last_ticks = 0; ///< Last CPU ticks - -template -inline void Read(T &var, const u32 addr) { -} - -template -inline void Write(u32 addr, const T data) { -} - -/// Update hardware -void Update() { - u64 current_ticks = Core::g_app_core->GetTicks(); - - if ((current_ticks - g_last_ticks) >= kFrameTicks) { - g_last_ticks = current_ticks; - VideoCore::g_renderer->SwapBuffers(); - } -} - -/// Initialize hardware -void Init() { - g_last_ticks = Core::g_app_core->GetTicks(); - NOTICE_LOG(LCD, "LCD initialized OK"); -} - -/// Shutdown hardware -void Shutdown() { - NOTICE_LOG(LCD, "LCD shutdown OK"); -} - -} // namespace diff --git a/src/core/src/hw/hw_lcd.h b/src/core/src/hw/hw_lcd.h deleted file mode 100644 index 30e347cc..00000000 --- a/src/core/src/hw/hw_lcd.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common_types.h" - -namespace LCD { - -enum { - TOP_ASPECT_X = 0x5, - TOP_ASPECT_Y = 0x3, - - TOP_HEIGHT = 240, - TOP_WIDTH = 400, - BOTTOM_WIDTH = 320, - - FRAMEBUFFER_SEL = 0x20184E59, - TOP_LEFT_FRAME1 = 0x20184E60, - TOP_LEFT_FRAME2 = 0x201CB370, - TOP_RIGHT_FRAME1 = 0x20282160, - TOP_RIGHT_FRAME2 = 0x202C8670, - SUB_FRAME1 = 0x202118E0, - SUB_FRAME2 = 0x20249CF0, -}; - -template -inline void Read(T &var, const u32 addr); - -template -inline void Write(u32 addr, const T data); - -/// Update hardware -void Update(); - -/// Initialize hardware -void Init(); - -/// Shutdown hardware -void Shutdown(); - - -} // namespace diff --git a/src/core/src/loader.cpp b/src/core/src/loader.cpp deleted file mode 100644 index 5d039dc9..00000000 --- a/src/core/src/loader.cpp +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "file_util.h" -#include "loader.h" -#include "system.h" -#include "core.h" -#include "file_sys/directory_file_system.h" -#include "elf/elf_reader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Loads an extracted CXI from a directory -bool LoadDirectory_CXI(std::string &filename) { - std::string full_path = filename; - std::string path, file, extension; - SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); -#if EMU_PLATFORM == PLATFORM_WINDOWS - path = ReplaceAll(path, "/", "\\"); -#endif - DirectoryFileSystem *fs = new DirectoryFileSystem(&System::g_ctr_file_system, path); - System::g_ctr_file_system.Mount("fs:", fs); - - std::string final_name = "fs:/" + file + extension; - File::IOFile f(filename, "rb"); - - if (f.IsOpen()) { - // TODO(ShizZy): read here to memory.... - } - ERROR_LOG(TIME, "Unimplemented function!"); - return true; -} - -/// Loads a CTR ELF file -bool Load_ELF(std::string &filename) { - std::string full_path = filename; - std::string path, file, extension; - SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); -#if EMU_PLATFORM == PLATFORM_WINDOWS - path = ReplaceAll(path, "/", "\\"); -#endif - File::IOFile f(filename, "rb"); - - if (f.IsOpen()) { - u64 size = f.GetSize(); - u8* buffer = new u8[size]; - ElfReader* elf_reader = NULL; - - f.ReadBytes(buffer, size); - - elf_reader = new ElfReader(buffer); - elf_reader->LoadInto(0x00100000); - - Core::g_app_core->SetPC(elf_reader->GetEntryPoint()); - - delete[] buffer; - delete elf_reader; - } else { - return false; - } - f.Close(); - - return true; -} - -namespace Loader { - -bool IsBootableDirectory() { - ERROR_LOG(TIME, "Unimplemented function!"); - return true; -} - -/** - * Identifies the type of a bootable file - * @param filename String filename of bootable file - * @todo (ShizZy) this function sucks... make it actually check file contents etc. - * @return FileType of file - */ -FileType IdentifyFile(std::string &filename) { - if (filename.size() == 0) { - ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); - return FILETYPE_ERROR; - } - std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; - - if (File::IsDirectory(filename)) { - if (IsBootableDirectory()) { - return FILETYPE_DIRECTORY_CXI; - } - else { - return FILETYPE_NORMAL_DIRECTORY; - } - } - else if (!strcasecmp(extension.c_str(), ".elf")) { - return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".zip")) { - return FILETYPE_ARCHIVE_ZIP; - } - else if (!strcasecmp(extension.c_str(), ".rar")) { - return FILETYPE_ARCHIVE_RAR; - } - else if (!strcasecmp(extension.c_str(), ".r00")) { - return FILETYPE_ARCHIVE_RAR; - } - else if (!strcasecmp(extension.c_str(), ".r01")) { - return FILETYPE_ARCHIVE_RAR; - } - return FILETYPE_UNKNOWN; -} - -/** - * Identifies and loads a bootable file - * @param filename String filename of bootable file - * @param error_string Point to string to put error message if an error has occurred - * @return True on success, otherwise false - */ -bool LoadFile(std::string &filename, std::string *error_string) { - INFO_LOG(LOADER, "Identifying file..."); - - // Note that this can modify filename! - switch (IdentifyFile(filename)) { - - case FILETYPE_CTR_ELF: - return Load_ELF(filename); - - case FILETYPE_DIRECTORY_CXI: - return LoadDirectory_CXI(filename); - - case FILETYPE_ERROR: - ERROR_LOG(LOADER, "Could not read file"); - *error_string = "Error reading file"; - break; - - case FILETYPE_ARCHIVE_RAR: -#ifdef WIN32 - *error_string = "RAR file detected (Require WINRAR)"; -#else - *error_string = "RAR file detected (Require UnRAR)"; -#endif - break; - - case FILETYPE_ARCHIVE_ZIP: -#ifdef WIN32 - *error_string = "ZIP file detected (Require WINRAR)"; -#else - *error_string = "ZIP file detected (Require UnRAR)"; -#endif - break; - - case FILETYPE_NORMAL_DIRECTORY: - ERROR_LOG(LOADER, "Just a directory."); - *error_string = "Just a directory."; - break; - - case FILETYPE_UNKNOWN_BIN: - case FILETYPE_UNKNOWN_ELF: - case FILETYPE_UNKNOWN: - default: - ERROR_LOG(LOADER, "Failed to identify file"); - *error_string = "Failed to identify file"; - break; - } - return false; -} - -} // namespace \ No newline at end of file diff --git a/src/core/src/loader.h b/src/core/src/loader.h deleted file mode 100644 index 46525fcf..00000000 --- a/src/core/src/loader.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace Loader { - -enum FileType { - FILETYPE_ERROR, - - FILETYPE_CTR_CCI, - FILETYPE_CTR_CIA, - FILETYPE_CTR_CXI, - FILETYPE_CTR_ELF, - - FILETYPE_DIRECTORY_CXI, - - FILETYPE_UNKNOWN_BIN, - FILETYPE_UNKNOWN_ELF, - - FILETYPE_ARCHIVE_RAR, - FILETYPE_ARCHIVE_ZIP, - - FILETYPE_NORMAL_DIRECTORY, - - FILETYPE_UNKNOWN -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Identifies the type of a bootable file - * @param filename String filename of bootable file - * @return FileType of file - */ -FileType IdentifyFile(std::string &filename); - -/** - * Identifies and loads a bootable file - * @param filename String filename of bootable file - * @param error_string Point to string to put error message if an error has occurred - * @return True on success, otherwise false - */ -bool LoadFile(std::string &filename, std::string *error_string); - -} // namespace diff --git a/src/core/src/mem_map.cpp b/src/core/src/mem_map.cpp deleted file mode 100644 index 96f77d32..00000000 --- a/src/core/src/mem_map.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "mem_arena.h" - -#include "mem_map.h" -#include "core.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace Memory { - - -u8* g_base = NULL; ///< The base pointer to the auto-mirrored arena. - -MemArena g_arena; ///< The MemArena class - -u8* g_bootrom = NULL; ///< Bootrom physical memory -u8* g_fcram = NULL; ///< Main memory (FCRAM) pointer -u8* g_vram = NULL; ///< Video memory (VRAM) pointer -u8* g_scratchpad = NULL; ///< Scratchpad memory - Used for main thread stack - -u8* g_physical_bootrom = NULL; ///< Bootrom physical memory -u8* g_uncached_bootrom = NULL; - -u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM) -u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) -u8* g_physical_scratchpad = NULL; ///< Scratchpad memory used for main thread stack - -// We don't declare the IO region in here since its handled by other means. -static MemoryView g_views[] = { - { &g_vram, &g_physical_vram, MEM_VRAM_VADDR, MEM_VRAM_SIZE, 0 }, - { &g_fcram, &g_physical_fcram, MEM_FCRAM_VADDR, MEM_FCRAM_SIZE, MV_IS_PRIMARY_RAM }, -}; - -/*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}, - - // TODO: There are a few swizzled mirrors of VRAM, not sure about the best way to - // implement those. -};*/ - -static const int kNumMemViews = sizeof(g_views) / sizeof(MemoryView); ///< Number of mem views - -void Init() { - int flags = 0; - - for (size_t i = 0; i < ARRAY_SIZE(g_views); i++) { - if (g_views[i].flags & MV_IS_PRIMARY_RAM) - g_views[i].size = MEM_FCRAM_SIZE; - } - - g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena); - - g_scratchpad = new u8[MEM_SCRATCHPAD_SIZE]; - - NOTICE_LOG(MEMMAP, "Memory system initialized. RAM at %p (mirror at 0 @ %p)", g_fcram, - g_physical_fcram); -} - -void Shutdown() { - u32 flags = 0; - MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena); - - g_arena.ReleaseSpace(); - delete[] g_scratchpad; - - g_base = NULL; - g_scratchpad = NULL; - - NOTICE_LOG(MEMMAP, "Memory system shut down."); -} - -} // namespace diff --git a/src/core/src/mem_map.h b/src/core/src/mem_map.h deleted file mode 100644 index ad5abd16..00000000 --- a/src/core/src/mem_map.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "common.h" -#include "common_types.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -enum { - MEM_BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size - MEM_MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size - MEM_VRAM_SIZE = 0x00600000, ///< VRAM size - MEM_DSP_SIZE = 0x00080000, ///< DSP memory size - MEM_AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size - MEM_FCRAM_SIZE = 0x08000000, ///< FCRAM size... Really 0x07E00000, but power of 2 - // works much better - MEM_SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader - - MEM_VRAM_MASK = 0x007FFFFF, - MEM_FCRAM_MASK = (MEM_FCRAM_SIZE - 1), ///< FCRAM mask - MEM_SCRATCHPAD_MASK = (MEM_SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask - - MEM_FCRAM_PADDR = 0x20000000, ///< FCRAM physical address - MEM_FCRAM_PADDR_END = (MEM_FCRAM_PADDR + MEM_FCRAM_SIZE), ///< FCRAM end of physical space - MEM_FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address - MEM_FCRAM_VADDR_END = (MEM_FCRAM_VADDR + MEM_FCRAM_SIZE), ///< FCRAM end of virtual space - - MEM_VRAM_VADDR = 0x1F000000, - MEM_SCRATCHPAD_VADDR = (0x10000000 - MEM_SCRATCHPAD_SIZE), ///< Scratchpad virtual address -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace Memory { - -// 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_fcram; ///< Main memory -extern u8* g_vram; ///< Video memory (VRAM) -extern u8* g_scratchpad; ///< Stack memory - -void Init(); -void Shutdown(); - -u8 Read8(const u32 addr); -u16 Read16(const u32 addr); -u32 Read32(const u32 addr); - -u32 Read8_ZX(const u32 addr); -u32 Read16_ZX(const u32 addr); - -void Write8(const u32 addr, const u8 data); -void Write16(const u32 addr, const u16 data); -void Write32(const u32 addr, const u32 data); - -u8* GetPointer(const u32 Address); - -} // namespace diff --git a/src/core/src/mem_map_funcs.cpp b/src/core/src/mem_map_funcs.cpp deleted file mode 100644 index 7d8ae291..00000000 --- a/src/core/src/mem_map_funcs.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" - -#include "mem_map.h" -#include "hw/hw.h" - -namespace Memory { - -template -inline void _Read(T &var, const u32 addr) { - // 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 - - // Hardware I/O register reads - // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space - if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { - HW::Read(var, addr); - - // FCRAM virtual address reads - } else if ((addr & 0x3E000000) == 0x08000000) { - var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); - - // Scratchpad memory - } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { - var = *((const T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK]); - - /*else if ((addr & 0x3F800000) == 0x04000000) { - var = *((const T*)&m_pVRAM[addr & VRAM_MASK]); - }*/ - - // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. - // Until we progress far enough along, we'll accept all physical address reads here. I think - // that this is typically a corner-case from usermode software unless they are trying to do - // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. - } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { - var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); - - } else { - _assert_msg_(MEMMAP, false, "unknown memory read"); - } -} - -template -inline void _Write(u32 addr, const T data) { - - // Hardware I/O register writes - // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space - if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { - HW::Write(addr, data); - - // ExeFS:/.code is loaded here: - } else if ((addr & 0xFFF00000) == 0x00100000) { - // TODO(ShizZy): This is dumb... handle correctly. From 3DBrew: - // http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions - // The ExeFS:/.code is loaded here, executables must be loaded to the 0x00100000 region when - // the exheader "special memory" flag is clear. The 0x03F00000-byte size restriction only - // applies when this flag is clear. Executables are usually loaded to 0x14000000 when the - // exheader "special memory" flag is set, however this address can be arbitrary. - *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; - - // Scratchpad memory - } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { - *(T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK] = data; - - // Heap mapped by ControlMemory: - } else if ((addr & 0x3E000000) == 0x08000000) { - // TODO(ShizZy): Writes to this virtual address should be put in physical memory at FCRAM + GSP - // heap size... the following is writing to FCRAM + 0, which is actually supposed to be the - // application's GSP heap - *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; - - } else if ((addr & 0xFF000000) == 0x14000000) { - _assert_msg_(MEMMAP, false, "umimplemented write to GSP heap"); - } else if ((addr & 0xFFF00000) == 0x1EC00000) { - _assert_msg_(MEMMAP, false, "umimplemented write to IO registers"); - } else if ((addr & 0xFF000000) == 0x1F000000) { - _assert_msg_(MEMMAP, false, "umimplemented write to VRAM"); - } else if ((addr & 0xFFF00000) == 0x1FF00000) { - _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); - } else if ((addr & 0xFFFF0000) == 0x1FF80000) { - _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); - } else if ((addr & 0xFFFFF000) == 0x1FF81000) { - _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); - - // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. - // Until we progress far enough along, we'll accept all physical address writes here. I think - // that this is typically a corner-case from usermode software unless they are trying to do - // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. - } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { - *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; - - // Error out... - } else { - _assert_msg_(MEMMAP, false, "unknown memory write"); - } -} - -bool IsValidAddress(const u32 addr) { - if ((addr & 0x3E000000) == 0x08000000) { - return true; - } else if ((addr & 0x3F800000) == 0x04000000) { - return true; - } else if ((addr & 0xBFFF0000) == 0x00010000) { - return true; - } else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + MEM_FCRAM_MASK) { - return true; - } else { - return false; - } -} - -u8 *GetPointer(const u32 addr) { - // TODO(bunnei): Just a stub for now... ImplementMe! - if ((addr & 0x3E000000) == 0x08000000) { - return g_fcram + (addr & MEM_FCRAM_MASK); - - // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. - // Until we progress far enough along, we'll accept all physical address reads here. I think - // that this is typically a corner-case from usermode software unless they are trying to do - // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. - } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { - return g_fcram + (addr & MEM_FCRAM_MASK); - - //else if ((addr & 0x3F800000) == 0x04000000) { - // return g_vram + (addr & MEM_VRAM_MASK); - //} - //else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + g_MemorySize) { - // return m_pRAM + (addr & g_MemoryMask); - //} - } else { - //ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); - ERROR_LOG(MEMMAP, "Unknown GetPointer %08x", addr); - static bool reported = false; - //if (!reported) { - // Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); - // reported = true; - //} - //if (!g_Config.bIgnoreBadMemAccess) { - // Core_EnableStepping(true); - // host->SetDebugMode(true); - //} - return 0; - } -} - -u8 Read8(const u32 addr) { - u8 _var = 0; - _Read(_var, addr); - return (u8)_var; -} - -u16 Read16(const u32 addr) { - u16_le _var = 0; - _Read(_var, addr); - return (u16)_var; -} - -u32 Read32(const u32 addr) { - u32_le _var = 0; - _Read(_var, addr); - return _var; -} - -u64 Read64(const u32 addr) { - u64_le _var = 0; - _Read(_var, addr); - return _var; -} - -u32 Read8_ZX(const u32 addr) { - return (u32)Read8(addr); -} - -u32 Read16_ZX(const u32 addr) { - return (u32)Read16(addr); -} - -void Write8(const u32 addr, const u8 data) { - _Write(addr, data); -} - -void Write16(const u32 addr, const u16 data) { - _Write(addr, data); -} - -void Write32(const u32 addr, const u32 data) { - _Write(addr, data); -} - -void Write64(const u32 addr, const u64 data) { - _Write(addr, data); -} - -} // namespace diff --git a/src/core/src/system.cpp b/src/core/src/system.cpp deleted file mode 100644 index 1fc272d7..00000000 --- a/src/core/src/system.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "core.h" -#include "hw/hw.h" -#include "core_timing.h" -#include "mem_map.h" -#include "system.h" -#include "video_core.h" - -namespace System { - -volatile State g_state; -MetaFileSystem g_ctr_file_system; - -void UpdateState(State state) { -} - -void Init(EmuWindow* emu_window) { - Core::Init(); - Memory::Init(); - HW::Init(); - CoreTiming::Init(); - VideoCore::Init(emu_window); -} - -void RunLoopFor(int cycles) { - RunLoopUntil(CoreTiming::GetTicks() + cycles); -} - -void RunLoopUntil(u64 global_cycles) { -} - -void Shutdown() { - Core::Shutdown(); - HW::Shutdown(); - VideoCore::Shutdown(); - g_ctr_file_system.Shutdown(); -} - -} // namespace diff --git a/src/core/src/system.h b/src/core/src/system.h deleted file mode 100644 index 8e94e525..00000000 --- a/src/core/src/system.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "emu_window.h" -#include "file_sys/meta_file_system.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace System { - -// State of the full emulator -typedef enum { - 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 -} State; - -extern volatile State g_state; -extern MetaFileSystem g_ctr_file_system; - -void UpdateState(State state); -void Init(EmuWindow* emu_window); -void RunLoopFor(int cycles); -void RunLoopUntil(u64 global_cycles); -void Shutdown(); - -}; diff --git a/src/core/system.cpp b/src/core/system.cpp new file mode 100644 index 00000000..1fc272d7 --- /dev/null +++ b/src/core/system.cpp @@ -0,0 +1,42 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "core.h" +#include "hw/hw.h" +#include "core_timing.h" +#include "mem_map.h" +#include "system.h" +#include "video_core.h" + +namespace System { + +volatile State g_state; +MetaFileSystem g_ctr_file_system; + +void UpdateState(State state) { +} + +void Init(EmuWindow* emu_window) { + Core::Init(); + Memory::Init(); + HW::Init(); + CoreTiming::Init(); + VideoCore::Init(emu_window); +} + +void RunLoopFor(int cycles) { + RunLoopUntil(CoreTiming::GetTicks() + cycles); +} + +void RunLoopUntil(u64 global_cycles) { +} + +void Shutdown() { + Core::Shutdown(); + HW::Shutdown(); + VideoCore::Shutdown(); + g_ctr_file_system.Shutdown(); +} + +} // namespace diff --git a/src/core/system.h b/src/core/system.h new file mode 100644 index 00000000..8e94e525 --- /dev/null +++ b/src/core/system.h @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "emu_window.h" +#include "file_sys/meta_file_system.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace System { + +// State of the full emulator +typedef enum { + 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 +} State; + +extern volatile State g_state; +extern MetaFileSystem g_ctr_file_system; + +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/renderer_base.h b/src/video_core/renderer_base.h new file mode 100644 index 00000000..94748d69 --- /dev/null +++ b/src/video_core/renderer_base.h @@ -0,0 +1,58 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" +#include "hash.h" + +class RendererBase { +public: + + /// Used to reference a framebuffer + enum kFramebuffer { + kFramebuffer_VirtualXFB = 0, + kFramebuffer_EFB, + kFramebuffer_Texture + }; + + RendererBase() : m_current_fps(0), m_current_frame(0) { + } + + ~RendererBase() { + } + + /// Swap buffers (render frame) + virtual void SwapBuffers() = 0; + + /** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ + virtual void SetWindow(EmuWindow* window) = 0; + + /// Initialize the renderer + virtual void Init() = 0; + + /// Shutdown the renderer + virtual void ShutDown() = 0; + + // Getter/setter functions: + // ------------------------ + + f32 GetCurrentframe() const { + return m_current_fps; + } + + int current_frame() const { + return m_current_frame; + } + +protected: + f32 m_current_fps; ///< Current framerate, should be set by the renderer + int m_current_frame; ///< Current frame, should be set by the renderer + +private: + DISALLOW_COPY_AND_ASSIGN(RendererBase); +}; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp new file mode 100644 index 00000000..6010bcbc --- /dev/null +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -0,0 +1,279 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "mem_map.h" +#include "video_core.h" +#include "renderer_opengl/renderer_opengl.h" + + +/// RendererOpenGL constructor +RendererOpenGL::RendererOpenGL() { + memset(m_fbo, 0, sizeof(m_fbo)); + memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); + memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); + + m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); + m_resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; + + m_xfb_texture_top = 0; + m_xfb_texture_bottom = 0; + + m_xfb_top = 0; + m_xfb_bottom = 0; +} + +/// RendererOpenGL destructor +RendererOpenGL::~RendererOpenGL() { +} + +/// Swap buffers (render frame) +void RendererOpenGL::SwapBuffers() { + // EFB->XFB copy + // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some + // register write We're also treating both framebuffers as a single one in OpenGL. + Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); + RenderXFB(framebuffer_size, framebuffer_size); + + // XFB->Window copy + RenderFramebuffer(); + + // Swap buffers + m_render_window->PollEvents(); + m_render_window->SwapBuffers(); + + // Switch back to EFB and clear + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); +} + +/** + * Helper function to flip framebuffer from left-to-right to top-to-bottom + * @param addr Address of framebuffer in RAM + * @param out Pointer to output buffer with flipped framebuffer + * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei + */ +void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) { + u8* in = Memory::GetPointer(addr); + for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { + for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { + int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) + - (3 * y + 3); + int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); + + out[out_coord + 0] = in[in_coord + 0]; + out[out_coord + 1] = in[in_coord + 1]; + out[out_coord + 2] = in[in_coord + 2]; + } + } +} + +/** + * Renders external framebuffer (XFB) + * @param src_rect Source rectangle in XFB to copy + * @param dst_rect Destination rectangle in output framebuffer to copy to + */ +void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) { + + FlipFramebuffer(0x20282160, m_xfb_top_flipped); + FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped); + + // Blit the top framebuffer + // ------------------------ + + // Update textures with contents of XFB in RAM - top + glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, + GL_RGB, GL_UNSIGNED_BYTE, m_xfb_top_flipped); + glBindTexture(GL_TEXTURE_2D, 0); + + // Render target is destination framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); + glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); + + // Render source is our EFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Blit + glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, + dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // Blit the bottom framebuffer + // --------------------------- + + // Update textures with contents of XFB in RAM - bottom + glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, + GL_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); + glBindTexture(GL_TEXTURE_2D, 0); + + // Render target is destination framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); + glViewport(0, 0, + VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); + + // Render source is our EFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Blit + int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; + glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, + offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +} + +/// Initialize the FBO +void RendererOpenGL::InitFramebuffer() { + // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as + // separate framebuffers + + // Init the FBOs + // ------------- + + glGenFramebuffers(kMaxFramebuffers, m_fbo); // Generate primary framebuffer + glGenRenderbuffers(kMaxFramebuffers, m_fbo_rbo); // Generate primary RBOs + glGenRenderbuffers(kMaxFramebuffers, m_fbo_depth_buffers); // Generate primary depth buffer + + for (int i = 0; i < kMaxFramebuffers; i++) { + // Generate color buffer storage + glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, + VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); + + // Generate depth buffer storage + glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, + VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); + + // Attach the buffers + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[i]); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, m_fbo_depth_buffers[i]); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, m_fbo_rbo[i]); + + // Check for completeness + if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) { + NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i); + } else { + ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); + exit(1); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) + + // Initialize framebuffer textures + // ------------------------------- + + // Create XFB textures + glGenTextures(1, &m_xfb_texture_top); + glGenTextures(1, &m_xfb_texture_bottom); + + // Alocate video memorry for XFB textures + glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // Create the FBO and attach color/depth textures + glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + m_xfb_texture_top, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + m_xfb_texture_bottom, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +/// Blit the FBO to the OpenGL default framebuffer +void RendererOpenGL::RenderFramebuffer() { + // Render target is default framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glViewport(0, 0, m_resolution_width, m_resolution_height); + + // Render source is our XFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Blit + glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, + m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + // Update the FPS count + UpdateFramerate(); + + // Rebind EFB + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); + + m_current_frame++; +} + +/// Updates the framerate +void RendererOpenGL::UpdateFramerate() { +} + +/** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ +void RendererOpenGL::SetWindow(EmuWindow* window) { + m_render_window = window; +} + +/// Initialize the renderer +void RendererOpenGL::Init() { + m_render_window->MakeCurrent(); + glShadeModel(GL_SMOOTH); + + + glStencilFunc(GL_ALWAYS, 0, 0); + glBlendFunc(GL_ONE, GL_ONE); + + glViewport(0, 0, m_resolution_width, m_resolution_height); + + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + + glScissor(0, 0, m_resolution_width, m_resolution_height); + glClearDepth(1.0f); + + GLenum err = glewInit(); + if (GLEW_OK != err) { + ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", + glewGetErrorString(err)); + exit(-1); + } + + // Initialize everything else + // -------------------------- + + InitFramebuffer(); + + NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); +} + +/// Shutdown the renderer +void RendererOpenGL::ShutDown() { +} diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h new file mode 100644 index 00000000..86dc7b70 --- /dev/null +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -0,0 +1,91 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common.h" +#include "emu_window.h" + +#include "renderer_base.h" + + +class RendererOpenGL : virtual public RendererBase { +public: + + static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers + + RendererOpenGL(); + ~RendererOpenGL(); + + /// Swap buffers (render frame) + void SwapBuffers(); + + /** + * Renders external framebuffer (XFB) + * @param src_rect Source rectangle in XFB to copy + * @param dst_rect Destination rectangle in output framebuffer to copy to + */ + void RenderXFB(const Rect& src_rect, const Rect& dst_rect); + + /** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ + void SetWindow(EmuWindow* window); + + /// Initialize the renderer + void Init(); + + /// Shutdown the renderer + void ShutDown(); + +private: + + /// Initialize the FBO + void InitFramebuffer(); + + // Blit the FBO to the OpenGL default framebuffer + void RenderFramebuffer(); + + /// Updates the framerate + void UpdateFramerate(); + + /** + * Helper function to flip framebuffer from left-to-right to top-to-bottom + * @param addr Address of framebuffer in RAM + * @param out Pointer to output buffer with flipped framebuffer + * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei + */ + void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out); + + + EmuWindow* m_render_window; ///< Handle to render window + u32 m_last_mode; ///< Last render mode + + int m_resolution_width; ///< Current resolution width + int m_resolution_height; ///< Current resolution height + + // Framebuffers + // ------------ + + GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects + GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects + GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects + + GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture + GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture + + GLuint m_xfb_top; ///< GL handle to top framebuffer + GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer + + // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom + // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: + + u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; + u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; + + DISALLOW_COPY_AND_ASSIGN(RendererOpenGL); +}; \ No newline at end of file diff --git a/src/video_core/src/renderer_base.h b/src/video_core/src/renderer_base.h deleted file mode 100644 index 94748d69..00000000 --- a/src/video_core/src/renderer_base.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" -#include "hash.h" - -class RendererBase { -public: - - /// Used to reference a framebuffer - enum kFramebuffer { - kFramebuffer_VirtualXFB = 0, - kFramebuffer_EFB, - kFramebuffer_Texture - }; - - RendererBase() : m_current_fps(0), m_current_frame(0) { - } - - ~RendererBase() { - } - - /// Swap buffers (render frame) - virtual void SwapBuffers() = 0; - - /** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ - virtual void SetWindow(EmuWindow* window) = 0; - - /// Initialize the renderer - virtual void Init() = 0; - - /// Shutdown the renderer - virtual void ShutDown() = 0; - - // Getter/setter functions: - // ------------------------ - - f32 GetCurrentframe() const { - return m_current_fps; - } - - int current_frame() const { - return m_current_frame; - } - -protected: - f32 m_current_fps; ///< Current framerate, should be set by the renderer - int m_current_frame; ///< Current frame, should be set by the renderer - -private: - DISALLOW_COPY_AND_ASSIGN(RendererBase); -}; diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.cpp b/src/video_core/src/renderer_opengl/renderer_opengl.cpp deleted file mode 100644 index 6010bcbc..00000000 --- a/src/video_core/src/renderer_opengl/renderer_opengl.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "mem_map.h" -#include "video_core.h" -#include "renderer_opengl/renderer_opengl.h" - - -/// RendererOpenGL constructor -RendererOpenGL::RendererOpenGL() { - memset(m_fbo, 0, sizeof(m_fbo)); - memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); - memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); - - m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); - m_resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; - - m_xfb_texture_top = 0; - m_xfb_texture_bottom = 0; - - m_xfb_top = 0; - m_xfb_bottom = 0; -} - -/// RendererOpenGL destructor -RendererOpenGL::~RendererOpenGL() { -} - -/// Swap buffers (render frame) -void RendererOpenGL::SwapBuffers() { - // EFB->XFB copy - // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some - // register write We're also treating both framebuffers as a single one in OpenGL. - Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); - RenderXFB(framebuffer_size, framebuffer_size); - - // XFB->Window copy - RenderFramebuffer(); - - // Swap buffers - m_render_window->PollEvents(); - m_render_window->SwapBuffers(); - - // Switch back to EFB and clear - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); -} - -/** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param addr Address of framebuffer in RAM - * @param out Pointer to output buffer with flipped framebuffer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei - */ -void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) { - u8* in = Memory::GetPointer(addr); - for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { - for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { - int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) - - (3 * y + 3); - int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); - - out[out_coord + 0] = in[in_coord + 0]; - out[out_coord + 1] = in[in_coord + 1]; - out[out_coord + 2] = in[in_coord + 2]; - } - } -} - -/** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to - */ -void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) { - - FlipFramebuffer(0x20282160, m_xfb_top_flipped); - FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped); - - // Blit the top framebuffer - // ------------------------ - - // Update textures with contents of XFB in RAM - top - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - GL_RGB, GL_UNSIGNED_BYTE, m_xfb_top_flipped); - glBindTexture(GL_TEXTURE_2D, 0); - - // Render target is destination framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); - - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // Blit - glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, - dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, - GL_COLOR_BUFFER_BIT, GL_LINEAR); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - // Blit the bottom framebuffer - // --------------------------- - - // Update textures with contents of XFB in RAM - bottom - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - GL_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); - glBindTexture(GL_TEXTURE_2D, 0); - - // Render target is destination framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glViewport(0, 0, - VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); - - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // Blit - int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; - glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, - offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, - GL_COLOR_BUFFER_BIT, GL_LINEAR); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); -} - -/// Initialize the FBO -void RendererOpenGL::InitFramebuffer() { - // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as - // separate framebuffers - - // Init the FBOs - // ------------- - - glGenFramebuffers(kMaxFramebuffers, m_fbo); // Generate primary framebuffer - glGenRenderbuffers(kMaxFramebuffers, m_fbo_rbo); // Generate primary RBOs - glGenRenderbuffers(kMaxFramebuffers, m_fbo_depth_buffers); // Generate primary depth buffer - - for (int i = 0; i < kMaxFramebuffers; i++) { - // Generate color buffer storage - glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, - VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); - - // Generate depth buffer storage - glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, - VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); - - // Attach the buffers - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[i]); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, m_fbo_depth_buffers[i]); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, m_fbo_rbo[i]); - - // Check for completeness - if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) { - NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i); - } else { - ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); - exit(1); - } - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) - - // Initialize framebuffer textures - // ------------------------------- - - // Create XFB textures - glGenTextures(1, &m_xfb_texture_top); - glGenTextures(1, &m_xfb_texture_bottom); - - // Alocate video memorry for XFB textures - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - - // Create the FBO and attach color/depth textures - glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_xfb_texture_top, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_xfb_texture_bottom, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -/// Blit the FBO to the OpenGL default framebuffer -void RendererOpenGL::RenderFramebuffer() { - // Render target is default framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glViewport(0, 0, m_resolution_width, m_resolution_height); - - // Render source is our XFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // Blit - glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, - m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - // Update the FPS count - UpdateFramerate(); - - // Rebind EFB - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); - - m_current_frame++; -} - -/// Updates the framerate -void RendererOpenGL::UpdateFramerate() { -} - -/** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ -void RendererOpenGL::SetWindow(EmuWindow* window) { - m_render_window = window; -} - -/// Initialize the renderer -void RendererOpenGL::Init() { - m_render_window->MakeCurrent(); - glShadeModel(GL_SMOOTH); - - - glStencilFunc(GL_ALWAYS, 0, 0); - glBlendFunc(GL_ONE, GL_ONE); - - glViewport(0, 0, m_resolution_width, m_resolution_height); - - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDepthFunc(GL_LEQUAL); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - - glScissor(0, 0, m_resolution_width, m_resolution_height); - glClearDepth(1.0f); - - GLenum err = glewInit(); - if (GLEW_OK != err) { - ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", - glewGetErrorString(err)); - exit(-1); - } - - // Initialize everything else - // -------------------------- - - InitFramebuffer(); - - NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); -} - -/// Shutdown the renderer -void RendererOpenGL::ShutDown() { -} diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.h b/src/video_core/src/renderer_opengl/renderer_opengl.h deleted file mode 100644 index 86dc7b70..00000000 --- a/src/video_core/src/renderer_opengl/renderer_opengl.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common.h" -#include "emu_window.h" - -#include "renderer_base.h" - - -class RendererOpenGL : virtual public RendererBase { -public: - - static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers - - RendererOpenGL(); - ~RendererOpenGL(); - - /// Swap buffers (render frame) - void SwapBuffers(); - - /** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to - */ - void RenderXFB(const Rect& src_rect, const Rect& dst_rect); - - /** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ - void SetWindow(EmuWindow* window); - - /// Initialize the renderer - void Init(); - - /// Shutdown the renderer - void ShutDown(); - -private: - - /// Initialize the FBO - void InitFramebuffer(); - - // Blit the FBO to the OpenGL default framebuffer - void RenderFramebuffer(); - - /// Updates the framerate - void UpdateFramerate(); - - /** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param addr Address of framebuffer in RAM - * @param out Pointer to output buffer with flipped framebuffer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei - */ - void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out); - - - EmuWindow* m_render_window; ///< Handle to render window - u32 m_last_mode; ///< Last render mode - - int m_resolution_width; ///< Current resolution width - int m_resolution_height; ///< Current resolution height - - // Framebuffers - // ------------ - - GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects - GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects - GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects - - GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture - GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture - - GLuint m_xfb_top; ///< GL handle to top framebuffer - GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer - - // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom - // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: - - u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; - u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; - - DISALLOW_COPY_AND_ASSIGN(RendererOpenGL); -}; \ No newline at end of file diff --git a/src/video_core/src/utils.cpp b/src/video_core/src/utils.cpp deleted file mode 100644 index a6dd1e02..00000000 --- a/src/video_core/src/utils.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include - -#include "utils.h" - -namespace VideoCore { - -/** - * Dumps a texture to TGA - * @param filename String filename to dump texture to - * @param width Width of texture in pixels - * @param height Height of texture in pixels - * @param raw_data Raw RGBA8 texture data to dump - * @todo This should be moved to some general purpose/common code - */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data) { - TGAHeader hdr; - FILE* fout; - u8 r, g, b; - - memset(&hdr, 0, sizeof(hdr)); - hdr.datatypecode = 2; // uncompressed RGB - hdr.bitsperpixel = 24; // 24 bpp - hdr.width = width; - hdr.height = height; - - fout = fopen(filename.c_str(), "wb"); - fwrite(&hdr, sizeof(TGAHeader), 1, fout); - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - r = raw_data[(4 * (i * width)) + (4 * j) + 0]; - g = raw_data[(4 * (i * width)) + (4 * j) + 1]; - b = raw_data[(4 * (i * width)) + (4 * j) + 2]; - putc(b, fout); - putc(g, fout); - putc(r, fout); - } - } - fclose(fout); -} - -} // namespace diff --git a/src/video_core/src/utils.h b/src/video_core/src/utils.h deleted file mode 100644 index c417342e..00000000 --- a/src/video_core/src/utils.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common_types.h" - -namespace FormatPrecision { - -/// Adjust RGBA8 color with RGBA6 precision -static inline u32 rgba8_with_rgba6(u32 src) { - u32 color = src; - color &= 0xFCFCFCFC; - color |= (color >> 6) & 0x03030303; - return color; -} - -/// Adjust RGBA8 color with RGB565 precision -static inline u32 rgba8_with_rgb565(u32 src) { - u32 color = (src & 0xF8FCF8); - color |= (color >> 5) & 0x070007; - color |= (color >> 6) & 0x000300; - color |= 0xFF000000; - return color; -} - -/// Adjust Z24 depth value with Z16 precision -static inline u32 z24_with_z16(u32 src) { - return (src & 0xFFFF00) | (src >> 16); -} - -} // namespace - -namespace VideoCore { - -/// Structure for the TGA texture format (for dumping) -struct TGAHeader { - char idlength; - char colourmaptype; - char datatypecode; - short int colourmaporigin; - short int colourmaplength; - short int x_origin; - short int y_origin; - short width; - short height; - char bitsperpixel; - char imagedescriptor; -}; - -/** - * Dumps a texture to TGA - * @param filename String filename to dump texture to - * @param width Width of texture in pixels - * @param height Height of texture in pixels - * @param raw_data Raw RGBA8 texture data to dump - * @todo This should be moved to some general purpose/common code - */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data); - -} // namespace diff --git a/src/video_core/src/video_core.cpp b/src/video_core/src/video_core.cpp deleted file mode 100644 index 6c0c415f..00000000 --- a/src/video_core/src/video_core.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "emu_window.h" -#include "log.h" - -#include "core.h" - -#include "video_core.h" -#include "renderer_base.h" -#include "renderer_opengl/renderer_opengl.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace - -namespace VideoCore { - -EmuWindow* g_emu_window = NULL; ///< Frontend emulator window -RendererBase* g_renderer = NULL; ///< Renderer plugin -int g_current_frame = 0; - -/// Start the video core -void Start() { - if (g_emu_window == NULL) { - ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); - } -} - -/// Initialize the video core -void Init(EmuWindow* emu_window) { - g_emu_window = emu_window; - g_emu_window->MakeCurrent(); - g_renderer = new RendererOpenGL(); - g_renderer->SetWindow(g_emu_window); - g_renderer->Init(); - - g_current_frame = 0; - - NOTICE_LOG(VIDEO, "initialized ok"); -} - -/// Shutdown the video core -void Shutdown() { - delete g_renderer; -} - -} // namespace diff --git a/src/video_core/src/video_core.h b/src/video_core/src/video_core.h deleted file mode 100644 index 19bf49dd..00000000 --- a/src/video_core/src/video_core.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" -#include "emu_window.h" -#include "renderer_base.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace - -namespace VideoCore { - -// 3DS Video Constants -// ------------------- - -static const int kScreenTopWidth = 400; ///< 3DS top screen width -static const int kScreenTopHeight = 240; ///< 3DS top screen height -static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width -static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height - -// Video core renderer -// --------------------- - -extern RendererBase* g_renderer; ///< Renderer plugin -extern int g_current_frame; ///< Current frame - -/// Start the video core -void Start(); - -/// Initialize the video core -void Init(EmuWindow* emu_window); - -/// Shutdown the video core -void Shutdown(); - -} // namespace diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp new file mode 100644 index 00000000..a6dd1e02 --- /dev/null +++ b/src/video_core/utils.cpp @@ -0,0 +1,46 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "utils.h" + +namespace VideoCore { + +/** + * Dumps a texture to TGA + * @param filename String filename to dump texture to + * @param width Width of texture in pixels + * @param height Height of texture in pixels + * @param raw_data Raw RGBA8 texture data to dump + * @todo This should be moved to some general purpose/common code + */ +void DumpTGA(std::string filename, int width, int height, u8* raw_data) { + TGAHeader hdr; + FILE* fout; + u8 r, g, b; + + memset(&hdr, 0, sizeof(hdr)); + hdr.datatypecode = 2; // uncompressed RGB + hdr.bitsperpixel = 24; // 24 bpp + hdr.width = width; + hdr.height = height; + + fout = fopen(filename.c_str(), "wb"); + fwrite(&hdr, sizeof(TGAHeader), 1, fout); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + r = raw_data[(4 * (i * width)) + (4 * j) + 0]; + g = raw_data[(4 * (i * width)) + (4 * j) + 1]; + b = raw_data[(4 * (i * width)) + (4 * j) + 2]; + putc(b, fout); + putc(g, fout); + putc(r, fout); + } + } + fclose(fout); +} + +} // namespace diff --git a/src/video_core/utils.h b/src/video_core/utils.h new file mode 100644 index 00000000..c417342e --- /dev/null +++ b/src/video_core/utils.h @@ -0,0 +1,64 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common_types.h" + +namespace FormatPrecision { + +/// Adjust RGBA8 color with RGBA6 precision +static inline u32 rgba8_with_rgba6(u32 src) { + u32 color = src; + color &= 0xFCFCFCFC; + color |= (color >> 6) & 0x03030303; + return color; +} + +/// Adjust RGBA8 color with RGB565 precision +static inline u32 rgba8_with_rgb565(u32 src) { + u32 color = (src & 0xF8FCF8); + color |= (color >> 5) & 0x070007; + color |= (color >> 6) & 0x000300; + color |= 0xFF000000; + return color; +} + +/// Adjust Z24 depth value with Z16 precision +static inline u32 z24_with_z16(u32 src) { + return (src & 0xFFFF00) | (src >> 16); +} + +} // namespace + +namespace VideoCore { + +/// Structure for the TGA texture format (for dumping) +struct TGAHeader { + char idlength; + char colourmaptype; + char datatypecode; + short int colourmaporigin; + short int colourmaplength; + short int x_origin; + short int y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; +}; + +/** + * Dumps a texture to TGA + * @param filename String filename to dump texture to + * @param width Width of texture in pixels + * @param height Height of texture in pixels + * @param raw_data Raw RGBA8 texture data to dump + * @todo This should be moved to some general purpose/common code + */ +void DumpTGA(std::string filename, int width, int height, u8* raw_data); + +} // namespace diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp new file mode 100644 index 00000000..6c0c415f --- /dev/null +++ b/src/video_core/video_core.cpp @@ -0,0 +1,49 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "emu_window.h" +#include "log.h" + +#include "core.h" + +#include "video_core.h" +#include "renderer_base.h" +#include "renderer_opengl/renderer_opengl.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Video Core namespace + +namespace VideoCore { + +EmuWindow* g_emu_window = NULL; ///< Frontend emulator window +RendererBase* g_renderer = NULL; ///< Renderer plugin +int g_current_frame = 0; + +/// Start the video core +void Start() { + if (g_emu_window == NULL) { + ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); + } +} + +/// Initialize the video core +void Init(EmuWindow* emu_window) { + g_emu_window = emu_window; + g_emu_window->MakeCurrent(); + g_renderer = new RendererOpenGL(); + g_renderer->SetWindow(g_emu_window); + g_renderer->Init(); + + g_current_frame = 0; + + NOTICE_LOG(VIDEO, "initialized ok"); +} + +/// Shutdown the video core +void Shutdown() { + delete g_renderer; +} + +} // namespace diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h new file mode 100644 index 00000000..19bf49dd --- /dev/null +++ b/src/video_core/video_core.h @@ -0,0 +1,39 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" +#include "emu_window.h" +#include "renderer_base.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Video Core namespace + +namespace VideoCore { + +// 3DS Video Constants +// ------------------- + +static const int kScreenTopWidth = 400; ///< 3DS top screen width +static const int kScreenTopHeight = 240; ///< 3DS top screen height +static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width +static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height + +// Video core renderer +// --------------------- + +extern RendererBase* g_renderer; ///< Renderer plugin +extern int g_current_frame; ///< Current frame + +/// Start the video core +void Start(); + +/// Initialize the video core +void Init(EmuWindow* emu_window); + +/// Shutdown the video core +void Shutdown(); + +} // namespace -- cgit v1.2.3