From 4d8ec1960f99f4ee43feac8987454489295d41a8 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Sun, 1 Mar 2015 21:28:09 -0800 Subject: [PATCH] Switched from lazyusf to lazyusf2 --- .../lazyusf/lazyusf.xcodeproj/project.pbxproj | 1343 +- Frameworks/lazyusf/lazyusf/ai/ai_controller.c | 240 + Frameworks/lazyusf/lazyusf/ai/ai_controller.h | 91 + Frameworks/lazyusf/lazyusf/api/api_export.ver | 70 + Frameworks/lazyusf/lazyusf/api/callbacks.c | 77 + Frameworks/lazyusf/lazyusf/api/callbacks.h | 41 + Frameworks/lazyusf/lazyusf/api/m64p_common.h | 90 + Frameworks/lazyusf/lazyusf/api/m64p_config.h | 252 + .../lazyusf/lazyusf/api/m64p_debugger.h | 202 + .../lazyusf/lazyusf/api/m64p_frontend.h | 141 + Frameworks/lazyusf/lazyusf/api/m64p_plugin.h | 273 + Frameworks/lazyusf/lazyusf/api/m64p_types.h | 365 + Frameworks/lazyusf/lazyusf/api/m64p_vidext.h | 154 + Frameworks/lazyusf/lazyusf/audio.c | 89 - Frameworks/lazyusf/lazyusf/audio.h | 12 - Frameworks/lazyusf/lazyusf/audiolib.c | 271 - Frameworks/lazyusf/lazyusf/audiolib.h | 60 - Frameworks/lazyusf/lazyusf/config.h | 63 - Frameworks/lazyusf/lazyusf/cpu.c | 604 - Frameworks/lazyusf/lazyusf/cpu.h | 95 - Frameworks/lazyusf/lazyusf/cpu_hle.c | 161 - Frameworks/lazyusf/lazyusf/cpu_hle.h | 27 - Frameworks/lazyusf/lazyusf/dma.c | 183 - Frameworks/lazyusf/lazyusf/dma.h | 34 - Frameworks/lazyusf/lazyusf/exception.c | 158 - Frameworks/lazyusf/lazyusf/exception.h | 75 - Frameworks/lazyusf/lazyusf/interpreter_cpu.c | 799 -- Frameworks/lazyusf/lazyusf/interpreter_cpu.h | 37 - Frameworks/lazyusf/lazyusf/interpreter_ops.c | 1342 -- Frameworks/lazyusf/lazyusf/interpreter_ops.h | 206 - Frameworks/lazyusf/lazyusf/main.c | 37 - Frameworks/lazyusf/lazyusf/main.h | 6 - Frameworks/lazyusf/lazyusf/main/list.h | 127 + Frameworks/lazyusf/lazyusf/main/main.c | 185 + Frameworks/lazyusf/lazyusf/main/main.h | 48 + Frameworks/lazyusf/lazyusf/main/rom.c | 133 + Frameworks/lazyusf/lazyusf/main/rom.h | 92 + Frameworks/lazyusf/lazyusf/main/savestates.c | 639 + Frameworks/lazyusf/lazyusf/main/savestates.h | 31 + Frameworks/lazyusf/lazyusf/main/util.c | 186 + Frameworks/lazyusf/lazyusf/main/util.h | 213 + Frameworks/lazyusf/lazyusf/main/version.h | 39 + Frameworks/lazyusf/lazyusf/memory.c | 839 -- Frameworks/lazyusf/lazyusf/memory.h | 64 - Frameworks/lazyusf/lazyusf/memory/memory.c | 1257 ++ Frameworks/lazyusf/lazyusf/memory/memory.h | 106 + Frameworks/lazyusf/lazyusf/opcode.h | 274 - Frameworks/lazyusf/lazyusf/os.c | 285 - Frameworks/lazyusf/lazyusf/os.h | 89 - Frameworks/lazyusf/lazyusf/osal/preproc.h | 6 + Frameworks/lazyusf/lazyusf/pi/cart_rom.c | 91 + Frameworks/lazyusf/lazyusf/pi/cart_rom.h | 53 + Frameworks/lazyusf/lazyusf/pi/pi_controller.c | 249 + Frameworks/lazyusf/lazyusf/pi/pi_controller.h | 81 + Frameworks/lazyusf/lazyusf/pif.c | 99 - Frameworks/lazyusf/lazyusf/pif.h | 29 - .../lazyusf/lazyusf/r4300/cached_interp.c | 567 + .../lazyusf/lazyusf/r4300/cached_interp.h | 44 + Frameworks/lazyusf/lazyusf/r4300/cp0.c | 70 + Frameworks/lazyusf/lazyusf/r4300/cp0.h | 61 + Frameworks/lazyusf/lazyusf/r4300/cp1.c | 110 + Frameworks/lazyusf/lazyusf/r4300/cp1.h | 31 + .../lazyusf/lazyusf/r4300/empty_dynarec.c | 1052 ++ Frameworks/lazyusf/lazyusf/r4300/exception.c | 149 + Frameworks/lazyusf/lazyusf/r4300/exception.h | 31 + Frameworks/lazyusf/lazyusf/r4300/fpu.h | 465 + .../lazyusf/lazyusf/r4300/instr_counters.c | 105 + .../lazyusf/lazyusf/r4300/instr_counters.h | 29 + .../lazyusf/lazyusf/r4300/interpreter.def | 79 + .../lazyusf/r4300/interpreter_cop0.def | 137 + .../lazyusf/r4300/interpreter_cop1.def | 708 + .../lazyusf/r4300/interpreter_r4300.def | 800 ++ .../lazyusf/r4300/interpreter_regimm.def | 29 + .../lazyusf/r4300/interpreter_special.def | 408 + .../lazyusf/lazyusf/r4300/interpreter_tlb.def | 250 + Frameworks/lazyusf/lazyusf/r4300/interupt.c | 601 + Frameworks/lazyusf/lazyusf/r4300/interupt.h | 60 + Frameworks/lazyusf/lazyusf/r4300/macros.h | 63 + .../lazyusf/lazyusf/r4300/mi_controller.c | 136 + .../lazyusf/lazyusf/r4300/mi_controller.h | 71 + .../lazyusf/r4300/new_dynarec/assem_arm.c | 4575 +++++++ .../lazyusf/r4300/new_dynarec/assem_arm.h | 48 + .../lazyusf/r4300/new_dynarec/assem_x86.c | 4436 ++++++ .../lazyusf/r4300/new_dynarec/assem_x86.h | 32 + .../lazyusf/r4300/new_dynarec/linkage_arm.S | 1227 ++ .../lazyusf/r4300/new_dynarec/linkage_x86.S | 929 ++ .../lazyusf/r4300/new_dynarec/linkage_x86.asm | 873 ++ .../lazyusf/r4300/new_dynarec/new_dynarec.c | 11143 ++++++++++++++++ .../lazyusf/r4300/new_dynarec/new_dynarec.h | 44 + Frameworks/lazyusf/lazyusf/r4300/ops.h | 327 + .../lazyusf/lazyusf/r4300/pure_interp.c | 746 ++ .../lazyusf/lazyusf/r4300/pure_interp.h | 27 + Frameworks/lazyusf/lazyusf/r4300/r4300.c | 349 + Frameworks/lazyusf/lazyusf/r4300/r4300.h | 52 + Frameworks/lazyusf/lazyusf/r4300/r4300_core.c | 35 + Frameworks/lazyusf/lazyusf/r4300/r4300_core.h | 39 + Frameworks/lazyusf/lazyusf/r4300/recomp.c | 2577 ++++ Frameworks/lazyusf/lazyusf/r4300/recomp.h | 114 + Frameworks/lazyusf/lazyusf/r4300/recomph.h | 294 + Frameworks/lazyusf/lazyusf/r4300/reset.c | 55 + Frameworks/lazyusf/lazyusf/r4300/reset.h | 30 + Frameworks/lazyusf/lazyusf/r4300/tlb.c | 109 + Frameworks/lazyusf/lazyusf/r4300/tlb.h | 59 + .../lazyusf/lazyusf/r4300/x86/assemble.c | 132 + .../lazyusf/lazyusf/r4300/x86/assemble.h | 851 ++ .../lazyusf/r4300/x86/assemble_struct.h | 33 + Frameworks/lazyusf/lazyusf/r4300/x86/gbc.c | 282 + Frameworks/lazyusf/lazyusf/r4300/x86/gcop0.c | 47 + Frameworks/lazyusf/lazyusf/r4300/x86/gcop1.c | 140 + .../lazyusf/lazyusf/r4300/x86/gcop1_d.c | 609 + .../lazyusf/lazyusf/r4300/x86/gcop1_l.c | 59 + .../lazyusf/lazyusf/r4300/x86/gcop1_s.c | 608 + .../lazyusf/lazyusf/r4300/x86/gcop1_w.c | 61 + Frameworks/lazyusf/lazyusf/r4300/x86/gr4300.c | 2034 +++ .../lazyusf/lazyusf/r4300/x86/gregimm.c | 582 + .../lazyusf/lazyusf/r4300/x86/gspecial.c | 1167 ++ Frameworks/lazyusf/lazyusf/r4300/x86/gtlb.c | 81 + .../lazyusf/lazyusf/r4300/x86/interpret.h | 239 + .../lazyusf/lazyusf/r4300/x86/regcache.c | 843 ++ .../lazyusf/lazyusf/r4300/x86/regcache.h | 48 + Frameworks/lazyusf/lazyusf/r4300/x86/rjump.c | 164 + .../lazyusf/lazyusf/r4300/x86_64/assemble.c | 201 + .../lazyusf/lazyusf/r4300/x86_64/assemble.h | 1197 ++ .../lazyusf/r4300/x86_64/assemble_struct.h | 34 + Frameworks/lazyusf/lazyusf/r4300/x86_64/gbc.c | 305 + .../lazyusf/lazyusf/r4300/x86_64/gcop0.c | 56 + .../lazyusf/lazyusf/r4300/x86_64/gcop1.c | 163 + .../lazyusf/lazyusf/r4300/x86_64/gcop1_d.c | 719 + .../lazyusf/lazyusf/r4300/x86_64/gcop1_l.c | 70 + .../lazyusf/lazyusf/r4300/x86_64/gcop1_s.c | 718 + .../lazyusf/lazyusf/r4300/x86_64/gcop1_w.c | 72 + .../lazyusf/lazyusf/r4300/x86_64/gr4300.c | 2260 ++++ .../lazyusf/lazyusf/r4300/x86_64/gregimm.c | 611 + .../lazyusf/lazyusf/r4300/x86_64/gspecial.c | 1078 ++ .../lazyusf/lazyusf/r4300/x86_64/gtlb.c | 101 + .../lazyusf/lazyusf/r4300/x86_64/interpret.h | 240 + .../lazyusf/lazyusf/r4300/x86_64/regcache.c | 625 + .../lazyusf/lazyusf/r4300/x86_64/regcache.h | 47 + .../lazyusf/lazyusf/r4300/x86_64/rjump.c | 111 + Frameworks/lazyusf/lazyusf/rdp/rdp_core.c | 148 + Frameworks/lazyusf/lazyusf/rdp/rdp_core.h | 91 + Frameworks/lazyusf/lazyusf/registers.c | 145 - Frameworks/lazyusf/lazyusf/registers.h | 378 - Frameworks/lazyusf/lazyusf/ri/rdram.c | 118 + Frameworks/lazyusf/lazyusf/ri/rdram.h | 77 + .../lazyusf/lazyusf/ri/rdram_detection_hack.c | 47 + .../lazyusf/lazyusf/ri/rdram_detection_hack.h | 27 + Frameworks/lazyusf/lazyusf/ri/ri_controller.c | 64 + Frameworks/lazyusf/lazyusf/ri/ri_controller.h | 65 + Frameworks/lazyusf/lazyusf/rsp.h | 11 - Frameworks/lazyusf/lazyusf/rsp/rsp.c | 109 - Frameworks/lazyusf/lazyusf/rsp/rsp_core.c | 364 + Frameworks/lazyusf/lazyusf/rsp/rsp_core.h | 110 + Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c | 16 +- Frameworks/lazyusf/lazyusf/rsp_lle/bench.c | 227 + .../lazyusf/lazyusf/{rsp => rsp_lle}/config.h | 0 .../lazyusf/{rsp => rsp_lle}/execute.h | 30 +- .../lazyusf/lazyusf/{rsp => rsp_lle}/matrix.h | 0 Frameworks/lazyusf/lazyusf/rsp_lle/rsp.c | 109 + .../lazyusf/lazyusf/{rsp => rsp_lle}/rsp.h | 4 +- Frameworks/lazyusf/lazyusf/rsp_lle/rsp_lle.h | 6 + .../lazyusf/lazyusf/{rsp => rsp_lle}/su.h | 166 +- .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/cf.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/clamp.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/divrom.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/shuffle.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vabs.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vadd.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vaddc.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vand.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vch.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vcl.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vcr.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/veq.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vge.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vlt.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmacf.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmacq.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmacu.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmadh.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmadl.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmadm.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmadn.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmov.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmrg.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmudh.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmudl.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmudm.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmudn.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmulf.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vmulu.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vnand.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vne.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vnop.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vnor.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vnxor.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vor.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrcp.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrcph.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrcpl.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrsq.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrsqh.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vrsql.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vsaw.h | 10 +- .../lazyusf/{rsp => rsp_lle}/vu/vsub.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vsubc.h | 0 .../lazyusf/lazyusf/{rsp => rsp_lle}/vu/vu.h | 0 .../lazyusf/{rsp => rsp_lle}/vu/vxor.h | 0 Frameworks/lazyusf/lazyusf/si/cic.c | 65 + Frameworks/lazyusf/lazyusf/si/cic.h | 42 + .../lazyusf/lazyusf/si/game_controller.c | 143 + .../lazyusf/lazyusf/si/game_controller.h | 46 + .../lazyusf/lazyusf/si/n64_cic_nus_6105.c | 120 + .../lazyusf/lazyusf/si/n64_cic_nus_6105.h | 98 + Frameworks/lazyusf/lazyusf/si/pif.c | 238 + Frameworks/lazyusf/lazyusf/si/pif.h | 76 + Frameworks/lazyusf/lazyusf/si/si_controller.c | 159 + Frameworks/lazyusf/lazyusf/si/si_controller.h | 73 + Frameworks/lazyusf/lazyusf/tlb.c | 195 - Frameworks/lazyusf/lazyusf/tlb.h | 105 - Frameworks/lazyusf/lazyusf/types.h | 72 - Frameworks/lazyusf/lazyusf/usf.c | 254 - Frameworks/lazyusf/lazyusf/usf/barray.c | 189 + Frameworks/lazyusf/lazyusf/usf/barray.h | 41 + Frameworks/lazyusf/lazyusf/usf/resampler.c | 328 + Frameworks/lazyusf/lazyusf/usf/resampler.h | 42 + Frameworks/lazyusf/lazyusf/usf/usf.c | 470 + Frameworks/lazyusf/lazyusf/{ => usf}/usf.h | 24 + Frameworks/lazyusf/lazyusf/usf/usf_internal.h | 484 + Frameworks/lazyusf/lazyusf/usf_internal.h | 155 - Frameworks/lazyusf/lazyusf/vi/vi_controller.c | 118 + Frameworks/lazyusf/lazyusf/vi/vi_controller.h | 76 + .../HighlyComplete/HCDecoder.mm | 16 +- 233 files changed, 61579 insertions(+), 7949 deletions(-) create mode 100644 Frameworks/lazyusf/lazyusf/ai/ai_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/ai/ai_controller.h create mode 100644 Frameworks/lazyusf/lazyusf/api/api_export.ver create mode 100644 Frameworks/lazyusf/lazyusf/api/callbacks.c create mode 100644 Frameworks/lazyusf/lazyusf/api/callbacks.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_common.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_config.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_debugger.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_frontend.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_plugin.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_types.h create mode 100644 Frameworks/lazyusf/lazyusf/api/m64p_vidext.h delete mode 100644 Frameworks/lazyusf/lazyusf/audio.c delete mode 100644 Frameworks/lazyusf/lazyusf/audio.h delete mode 100644 Frameworks/lazyusf/lazyusf/audiolib.c delete mode 100644 Frameworks/lazyusf/lazyusf/audiolib.h delete mode 100644 Frameworks/lazyusf/lazyusf/config.h delete mode 100644 Frameworks/lazyusf/lazyusf/cpu.c delete mode 100644 Frameworks/lazyusf/lazyusf/cpu.h delete mode 100644 Frameworks/lazyusf/lazyusf/cpu_hle.c delete mode 100644 Frameworks/lazyusf/lazyusf/cpu_hle.h delete mode 100644 Frameworks/lazyusf/lazyusf/dma.c delete mode 100644 Frameworks/lazyusf/lazyusf/dma.h delete mode 100644 Frameworks/lazyusf/lazyusf/exception.c delete mode 100644 Frameworks/lazyusf/lazyusf/exception.h delete mode 100644 Frameworks/lazyusf/lazyusf/interpreter_cpu.c delete mode 100644 Frameworks/lazyusf/lazyusf/interpreter_cpu.h delete mode 100644 Frameworks/lazyusf/lazyusf/interpreter_ops.c delete mode 100644 Frameworks/lazyusf/lazyusf/interpreter_ops.h delete mode 100644 Frameworks/lazyusf/lazyusf/main.c delete mode 100644 Frameworks/lazyusf/lazyusf/main.h create mode 100644 Frameworks/lazyusf/lazyusf/main/list.h create mode 100644 Frameworks/lazyusf/lazyusf/main/main.c create mode 100644 Frameworks/lazyusf/lazyusf/main/main.h create mode 100644 Frameworks/lazyusf/lazyusf/main/rom.c create mode 100644 Frameworks/lazyusf/lazyusf/main/rom.h create mode 100644 Frameworks/lazyusf/lazyusf/main/savestates.c create mode 100644 Frameworks/lazyusf/lazyusf/main/savestates.h create mode 100644 Frameworks/lazyusf/lazyusf/main/util.c create mode 100644 Frameworks/lazyusf/lazyusf/main/util.h create mode 100644 Frameworks/lazyusf/lazyusf/main/version.h delete mode 100644 Frameworks/lazyusf/lazyusf/memory.c delete mode 100644 Frameworks/lazyusf/lazyusf/memory.h create mode 100644 Frameworks/lazyusf/lazyusf/memory/memory.c create mode 100644 Frameworks/lazyusf/lazyusf/memory/memory.h delete mode 100644 Frameworks/lazyusf/lazyusf/opcode.h delete mode 100644 Frameworks/lazyusf/lazyusf/os.c delete mode 100644 Frameworks/lazyusf/lazyusf/os.h create mode 100644 Frameworks/lazyusf/lazyusf/pi/cart_rom.c create mode 100644 Frameworks/lazyusf/lazyusf/pi/cart_rom.h create mode 100644 Frameworks/lazyusf/lazyusf/pi/pi_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/pi/pi_controller.h delete mode 100644 Frameworks/lazyusf/lazyusf/pif.c delete mode 100644 Frameworks/lazyusf/lazyusf/pif.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cached_interp.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cached_interp.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cp0.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cp0.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cp1.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/cp1.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/empty_dynarec.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/exception.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/exception.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/fpu.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/instr_counters.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/instr_counters.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_cop0.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_cop1.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_r4300.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_regimm.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_special.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interpreter_tlb.def create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interupt.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/interupt.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/macros.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/mi_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/mi_controller.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_arm.S create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.S create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.asm create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/ops.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/pure_interp.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/pure_interp.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/r4300.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/r4300.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/r4300_core.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/r4300_core.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/recomp.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/recomp.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/recomph.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/reset.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/reset.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/tlb.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/tlb.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/assemble.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/assemble.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/assemble_struct.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gbc.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop0.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop1.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_d.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_l.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_s.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_w.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gr4300.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gregimm.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gspecial.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/gtlb.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/interpret.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/regcache.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/regcache.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86/rjump.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble_struct.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gbc.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop0.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_d.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_l.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_s.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_w.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gr4300.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gregimm.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gspecial.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/gtlb.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/interpret.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/regcache.c create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/regcache.h create mode 100644 Frameworks/lazyusf/lazyusf/r4300/x86_64/rjump.c create mode 100644 Frameworks/lazyusf/lazyusf/rdp/rdp_core.c create mode 100644 Frameworks/lazyusf/lazyusf/rdp/rdp_core.h delete mode 100644 Frameworks/lazyusf/lazyusf/registers.c delete mode 100644 Frameworks/lazyusf/lazyusf/registers.h create mode 100644 Frameworks/lazyusf/lazyusf/ri/rdram.c create mode 100644 Frameworks/lazyusf/lazyusf/ri/rdram.h create mode 100644 Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.c create mode 100644 Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.h create mode 100644 Frameworks/lazyusf/lazyusf/ri/ri_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/ri/ri_controller.h delete mode 100644 Frameworks/lazyusf/lazyusf/rsp.h delete mode 100644 Frameworks/lazyusf/lazyusf/rsp/rsp.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp/rsp_core.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp/rsp_core.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_lle/bench.c rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/config.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/execute.h (95%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/matrix.h (100%) create mode 100644 Frameworks/lazyusf/lazyusf/rsp_lle/rsp.c rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/rsp.h (97%) create mode 100644 Frameworks/lazyusf/lazyusf/rsp_lle/rsp_lle.h rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/su.h (92%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/cf.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/clamp.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/divrom.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/shuffle.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vabs.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vadd.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vaddc.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vand.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vch.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vcl.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vcr.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/veq.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vge.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vlt.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmacf.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmacq.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmacu.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmadh.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmadl.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmadm.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmadn.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmov.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmrg.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmudh.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmudl.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmudm.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmudn.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmulf.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vmulu.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vnand.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vne.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vnop.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vnor.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vnxor.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vor.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrcp.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrcph.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrcpl.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrsq.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrsqh.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vrsql.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vsaw.h (90%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vsub.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vsubc.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vu.h (100%) rename Frameworks/lazyusf/lazyusf/{rsp => rsp_lle}/vu/vxor.h (100%) create mode 100644 Frameworks/lazyusf/lazyusf/si/cic.c create mode 100644 Frameworks/lazyusf/lazyusf/si/cic.h create mode 100644 Frameworks/lazyusf/lazyusf/si/game_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/si/game_controller.h create mode 100644 Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.c create mode 100644 Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.h create mode 100644 Frameworks/lazyusf/lazyusf/si/pif.c create mode 100644 Frameworks/lazyusf/lazyusf/si/pif.h create mode 100644 Frameworks/lazyusf/lazyusf/si/si_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/si/si_controller.h delete mode 100644 Frameworks/lazyusf/lazyusf/tlb.c delete mode 100644 Frameworks/lazyusf/lazyusf/tlb.h delete mode 100644 Frameworks/lazyusf/lazyusf/types.h delete mode 100644 Frameworks/lazyusf/lazyusf/usf.c create mode 100644 Frameworks/lazyusf/lazyusf/usf/barray.c create mode 100644 Frameworks/lazyusf/lazyusf/usf/barray.h create mode 100644 Frameworks/lazyusf/lazyusf/usf/resampler.c create mode 100644 Frameworks/lazyusf/lazyusf/usf/resampler.h create mode 100644 Frameworks/lazyusf/lazyusf/usf/usf.c rename Frameworks/lazyusf/lazyusf/{ => usf}/usf.h (66%) create mode 100644 Frameworks/lazyusf/lazyusf/usf/usf_internal.h delete mode 100644 Frameworks/lazyusf/lazyusf/usf_internal.h create mode 100644 Frameworks/lazyusf/lazyusf/vi/vi_controller.c create mode 100644 Frameworks/lazyusf/lazyusf/vi/vi_controller.h diff --git a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj index 1f8cfb0a3..2f859b198 100644 --- a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj +++ b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj @@ -7,233 +7,397 @@ objects = { /* Begin PBXBuildFile section */ - 8319EF191A219846009DD5C4 /* cpu_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8319EF171A219846009DD5C4 /* cpu_hle.c */; }; - 8319EF1A1A219846009DD5C4 /* cpu_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8319EF181A219846009DD5C4 /* cpu_hle.h */; }; - 8319EF1D1A2198B9009DD5C4 /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 8319EF1B1A2198B9009DD5C4 /* os.c */; }; - 8319EF1E1A2198B9009DD5C4 /* os.h in Headers */ = {isa = PBXBuildFile; fileRef = 8319EF1C1A2198B9009DD5C4 /* os.h */; }; - 8319EF211A219BE7009DD5C4 /* audiolib.c in Sources */ = {isa = PBXBuildFile; fileRef = 8319EF1F1A219BE7009DD5C4 /* audiolib.c */; }; - 8319EF221A219BE7009DD5C4 /* audiolib.h in Headers */ = {isa = PBXBuildFile; fileRef = 8319EF201A219BE7009DD5C4 /* audiolib.h */; }; - 8378416A18C6E56B002C4FE5 /* alist.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415418C6E56B002C4FE5 /* alist.c */; }; - 8378416B18C6E56B002C4FE5 /* alist.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415518C6E56B002C4FE5 /* alist.h */; }; - 8378416C18C6E56B002C4FE5 /* alist_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415618C6E56B002C4FE5 /* alist_audio.c */; }; - 8378416E18C6E56B002C4FE5 /* alist_naudio.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415818C6E56B002C4FE5 /* alist_naudio.c */; }; - 8378416F18C6E56B002C4FE5 /* alist_nead.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415918C6E56B002C4FE5 /* alist_nead.c */; }; - 8378417018C6E56B002C4FE5 /* arithmetics.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415A18C6E56B002C4FE5 /* arithmetics.h */; }; - 8378417318C6E56B002C4FE5 /* cicx105.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415D18C6E56B002C4FE5 /* cicx105.c */; }; - 8378417518C6E56B002C4FE5 /* jpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415F18C6E56B002C4FE5 /* jpeg.c */; }; - 8378417B18C6E56B002C4FE5 /* mp3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416518C6E56B002C4FE5 /* mp3.c */; }; - 8378417C18C6E56B002C4FE5 /* musyx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416618C6E56B002C4FE5 /* musyx.c */; }; - 837841C018C847B2002C4FE5 /* audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 837841B818C847B2002C4FE5 /* audio.c */; }; - 837841C118C847B2002C4FE5 /* audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 837841B918C847B2002C4FE5 /* audio.h */; }; - 837841C418C847B2002C4FE5 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 837841BC18C847B2002C4FE5 /* memory.c */; }; - 837841C518C847B2002C4FE5 /* memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 837841BD18C847B2002C4FE5 /* memory.h */; }; - 837841C618C847B2002C4FE5 /* plugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 837841BE18C847B2002C4FE5 /* plugin.c */; }; - 83A2249218CAC28500FE4173 /* hle_external.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A2248E18CAC28500FE4173 /* hle_external.h */; }; - 83A2249318CAC28500FE4173 /* hle_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A2248F18CAC28500FE4173 /* hle_internal.h */; }; - 83A2249418CAC28500FE4173 /* hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A2249018CAC28500FE4173 /* hle.c */; }; - 83A2249518CAC28500FE4173 /* hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A2249118CAC28500FE4173 /* hle.h */; }; - 83C8B6AB18AF58080071B040 /* audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B65918AF58080071B040 /* audio.c */; }; - 83C8B6AC18AF58080071B040 /* audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65A18AF58080071B040 /* audio.h */; }; - 83C8B6AD18AF58080071B040 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65B18AF58080071B040 /* config.h */; }; - 83C8B6AE18AF58080071B040 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B65C18AF58080071B040 /* cpu.c */; }; - 83C8B6AF18AF58080071B040 /* cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65D18AF58080071B040 /* cpu.h */; }; - 83C8B6B018AF58080071B040 /* dma.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B65E18AF58080071B040 /* dma.c */; }; - 83C8B6B118AF58080071B040 /* dma.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65F18AF58080071B040 /* dma.h */; }; - 83C8B6B218AF58080071B040 /* exception.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66018AF58080071B040 /* exception.c */; }; - 83C8B6B318AF58080071B040 /* exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66118AF58080071B040 /* exception.h */; }; - 83C8B6B418AF58080071B040 /* interpreter_cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66218AF58080071B040 /* interpreter_cpu.c */; }; - 83C8B6B518AF58080071B040 /* interpreter_cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66318AF58080071B040 /* interpreter_cpu.h */; }; - 83C8B6B618AF58080071B040 /* interpreter_ops.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66418AF58080071B040 /* interpreter_ops.c */; }; - 83C8B6B718AF58080071B040 /* interpreter_ops.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66518AF58080071B040 /* interpreter_ops.h */; }; - 83C8B6B818AF58080071B040 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66618AF58080071B040 /* main.c */; }; - 83C8B6B918AF58080071B040 /* main.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66718AF58080071B040 /* main.h */; }; - 83C8B6BA18AF58080071B040 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66818AF58080071B040 /* memory.c */; }; - 83C8B6BB18AF58080071B040 /* memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66918AF58080071B040 /* memory.h */; }; - 83C8B6BC18AF58080071B040 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66A18AF58080071B040 /* opcode.h */; }; - 83C8B6BD18AF58080071B040 /* pif.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66B18AF58080071B040 /* pif.c */; }; - 83C8B6BE18AF58080071B040 /* pif.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66C18AF58080071B040 /* pif.h */; }; - 83C8B6BF18AF58080071B040 /* registers.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B66D18AF58080071B040 /* registers.c */; }; - 83C8B6C018AF58080071B040 /* registers.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B66E18AF58080071B040 /* registers.h */; }; - 83C8B6C118AF58080071B040 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67018AF58080071B040 /* config.h */; }; - 83C8B6C218AF58080071B040 /* execute.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67118AF58080071B040 /* execute.h */; }; - 83C8B6C318AF58080071B040 /* rsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B67218AF58080071B040 /* rsp.c */; }; - 83C8B6C418AF58080071B040 /* rsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67318AF58080071B040 /* rsp.h */; }; - 83C8B6C518AF58080071B040 /* su.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67418AF58080071B040 /* su.h */; }; - 83C8B6C618AF58080071B040 /* cf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67618AF58080071B040 /* cf.h */; }; - 83C8B6C718AF58080071B040 /* clamp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67718AF58080071B040 /* clamp.h */; }; - 83C8B6C818AF58080071B040 /* divrom.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67818AF58080071B040 /* divrom.h */; }; - 83C8B6C918AF58080071B040 /* shuffle.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67918AF58080071B040 /* shuffle.h */; }; - 83C8B6CA18AF58080071B040 /* vabs.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67A18AF58080071B040 /* vabs.h */; }; - 83C8B6CB18AF58080071B040 /* vadd.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67B18AF58080071B040 /* vadd.h */; }; - 83C8B6CC18AF58080071B040 /* vaddc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67C18AF58080071B040 /* vaddc.h */; }; - 83C8B6CD18AF58080071B040 /* vand.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67D18AF58080071B040 /* vand.h */; }; - 83C8B6CE18AF58080071B040 /* vch.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67E18AF58080071B040 /* vch.h */; }; - 83C8B6CF18AF58080071B040 /* vcl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B67F18AF58080071B040 /* vcl.h */; }; - 83C8B6D018AF58080071B040 /* vcr.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68018AF58080071B040 /* vcr.h */; }; - 83C8B6D118AF58080071B040 /* veq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68118AF58080071B040 /* veq.h */; }; - 83C8B6D218AF58080071B040 /* vge.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68218AF58080071B040 /* vge.h */; }; - 83C8B6D318AF58080071B040 /* vlt.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68318AF58080071B040 /* vlt.h */; }; - 83C8B6D418AF58080071B040 /* vmacf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68418AF58080071B040 /* vmacf.h */; }; - 83C8B6D518AF58080071B040 /* vmacq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68518AF58080071B040 /* vmacq.h */; }; - 83C8B6D618AF58080071B040 /* vmacu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68618AF58080071B040 /* vmacu.h */; }; - 83C8B6D718AF58080071B040 /* vmadh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68718AF58080071B040 /* vmadh.h */; }; - 83C8B6D818AF58080071B040 /* vmadl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68818AF58080071B040 /* vmadl.h */; }; - 83C8B6D918AF58080071B040 /* vmadm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68918AF58080071B040 /* vmadm.h */; }; - 83C8B6DA18AF58080071B040 /* vmadn.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68A18AF58080071B040 /* vmadn.h */; }; - 83C8B6DB18AF58080071B040 /* vmov.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68B18AF58080071B040 /* vmov.h */; }; - 83C8B6DC18AF58080071B040 /* vmrg.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68C18AF58080071B040 /* vmrg.h */; }; - 83C8B6DD18AF58080071B040 /* vmudh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68D18AF58080071B040 /* vmudh.h */; }; - 83C8B6DE18AF58080071B040 /* vmudl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68E18AF58080071B040 /* vmudl.h */; }; - 83C8B6DF18AF58080071B040 /* vmudm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B68F18AF58080071B040 /* vmudm.h */; }; - 83C8B6E018AF58080071B040 /* vmudn.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69018AF58080071B040 /* vmudn.h */; }; - 83C8B6E118AF58080071B040 /* vmulf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69118AF58080071B040 /* vmulf.h */; }; - 83C8B6E218AF58080071B040 /* vmulu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69218AF58080071B040 /* vmulu.h */; }; - 83C8B6E318AF58080071B040 /* vnand.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69318AF58080071B040 /* vnand.h */; }; - 83C8B6E418AF58080071B040 /* vne.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69418AF58080071B040 /* vne.h */; }; - 83C8B6E518AF58080071B040 /* vnop.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69518AF58080071B040 /* vnop.h */; }; - 83C8B6E618AF58080071B040 /* vnor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69618AF58080071B040 /* vnor.h */; }; - 83C8B6E718AF58080071B040 /* vnxor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69718AF58080071B040 /* vnxor.h */; }; - 83C8B6E818AF58080071B040 /* vor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69818AF58080071B040 /* vor.h */; }; - 83C8B6E918AF58080071B040 /* vrcp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69918AF58080071B040 /* vrcp.h */; }; - 83C8B6EA18AF58090071B040 /* vrcph.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69A18AF58080071B040 /* vrcph.h */; }; - 83C8B6EB18AF58090071B040 /* vrcpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69B18AF58080071B040 /* vrcpl.h */; }; - 83C8B6EC18AF58090071B040 /* vrsq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69C18AF58080071B040 /* vrsq.h */; }; - 83C8B6ED18AF58090071B040 /* vrsqh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69D18AF58080071B040 /* vrsqh.h */; }; - 83C8B6EE18AF58090071B040 /* vrsql.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69E18AF58080071B040 /* vrsql.h */; }; - 83C8B6EF18AF58090071B040 /* vsaw.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B69F18AF58080071B040 /* vsaw.h */; }; - 83C8B6F018AF58090071B040 /* vsub.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A018AF58080071B040 /* vsub.h */; }; - 83C8B6F118AF58090071B040 /* vsubc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A118AF58080071B040 /* vsubc.h */; }; - 83C8B6F218AF58090071B040 /* vu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A218AF58080071B040 /* vu.h */; }; - 83C8B6F318AF58090071B040 /* vxor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A318AF58080071B040 /* vxor.h */; }; - 83C8B6F418AF58090071B040 /* rsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A418AF58080071B040 /* rsp.h */; }; - 83C8B6F518AF58090071B040 /* tlb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B6A518AF58080071B040 /* tlb.c */; }; - 83C8B6F618AF58090071B040 /* tlb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A618AF58080071B040 /* tlb.h */; }; - 83C8B6F718AF58090071B040 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A718AF58080071B040 /* types.h */; }; - 83C8B6F818AF58090071B040 /* usf_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6A818AF58080071B040 /* usf_internal.h */; }; - 83C8B6F918AF58090071B040 /* usf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B6A918AF58080071B040 /* usf.c */; }; - 83C8B6FA18AF58090071B040 /* usf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B6AA18AF58080071B040 /* usf.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8379B58A1AA4237E00F28A95 /* barray.c in Sources */ = {isa = PBXBuildFile; fileRef = 8379B5881AA4237E00F28A95 /* barray.c */; }; + 8379B58B1AA4237E00F28A95 /* barray.h in Headers */ = {isa = PBXBuildFile; fileRef = 8379B5891AA4237E00F28A95 /* barray.h */; }; + 83C0787C1A9B544300ABBB67 /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0787A1A9B544300ABBB67 /* resampler.c */; }; + 83C0787D1A9B544300ABBB67 /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C0787B1A9B544300ABBB67 /* resampler.h */; }; 83CA14741A987E91005E7ED4 /* preproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA146E1A987E91005E7ED4 /* preproc.h */; }; 83CA14751A987E91005E7ED4 /* dbg_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14701A987E91005E7ED4 /* dbg_decoder.c */; }; 83CA14761A987E91005E7ED4 /* dbg_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14711A987E91005E7ED4 /* dbg_decoder.h */; }; 83CA14771A987E91005E7ED4 /* dbg_decoder_local.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14721A987E91005E7ED4 /* dbg_decoder_local.h */; }; 83CA14781A987E91005E7ED4 /* dbg_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14731A987E91005E7ED4 /* dbg_types.h */; }; - 83FBECBA18ECE86B00311448 /* ucodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FBECB918ECE86B00311448 /* ucodes.h */; }; + 83CA15621A988138005E7ED4 /* ai_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA147A1A988137005E7ED4 /* ai_controller.c */; }; + 83CA15631A988138005E7ED4 /* ai_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA147B1A988137005E7ED4 /* ai_controller.h */; }; + 83CA15641A988138005E7ED4 /* api_export.ver in Resources */ = {isa = PBXBuildFile; fileRef = 83CA147D1A988137005E7ED4 /* api_export.ver */; }; + 83CA15651A988138005E7ED4 /* callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA147E1A988137005E7ED4 /* callbacks.c */; }; + 83CA15661A988138005E7ED4 /* callbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA147F1A988137005E7ED4 /* callbacks.h */; }; + 83CA15671A988138005E7ED4 /* m64p_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14801A988137005E7ED4 /* m64p_common.h */; }; + 83CA15681A988138005E7ED4 /* m64p_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14811A988137005E7ED4 /* m64p_config.h */; }; + 83CA15691A988138005E7ED4 /* m64p_debugger.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14821A988137005E7ED4 /* m64p_debugger.h */; }; + 83CA156A1A988138005E7ED4 /* m64p_frontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14831A988137005E7ED4 /* m64p_frontend.h */; }; + 83CA156B1A988138005E7ED4 /* m64p_plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14841A988138005E7ED4 /* m64p_plugin.h */; }; + 83CA156C1A988138005E7ED4 /* m64p_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14851A988138005E7ED4 /* m64p_types.h */; }; + 83CA156D1A988138005E7ED4 /* m64p_vidext.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14861A988138005E7ED4 /* m64p_vidext.h */; }; + 83CA156E1A988138005E7ED4 /* list.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14881A988138005E7ED4 /* list.h */; }; + 83CA156F1A988138005E7ED4 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14891A988138005E7ED4 /* main.c */; }; + 83CA15701A988138005E7ED4 /* main.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA148A1A988138005E7ED4 /* main.h */; }; + 83CA15711A988138005E7ED4 /* rom.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA148B1A988138005E7ED4 /* rom.c */; }; + 83CA15721A988138005E7ED4 /* rom.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA148C1A988138005E7ED4 /* rom.h */; }; + 83CA15731A988138005E7ED4 /* savestates.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA148D1A988138005E7ED4 /* savestates.c */; }; + 83CA15741A988138005E7ED4 /* savestates.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA148E1A988138005E7ED4 /* savestates.h */; }; + 83CA15751A988138005E7ED4 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA148F1A988138005E7ED4 /* util.c */; }; + 83CA15761A988138005E7ED4 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14901A988138005E7ED4 /* util.h */; }; + 83CA15771A988138005E7ED4 /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14911A988138005E7ED4 /* version.h */; }; + 83CA15781A988138005E7ED4 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14931A988138005E7ED4 /* memory.c */; }; + 83CA15791A988138005E7ED4 /* memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14941A988138005E7ED4 /* memory.h */; }; + 83CA157A1A988138005E7ED4 /* cart_rom.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14961A988138005E7ED4 /* cart_rom.c */; }; + 83CA157B1A988138005E7ED4 /* cart_rom.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14971A988138005E7ED4 /* cart_rom.h */; }; + 83CA157C1A988138005E7ED4 /* pi_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14981A988138005E7ED4 /* pi_controller.c */; }; + 83CA157D1A988138005E7ED4 /* pi_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14991A988138005E7ED4 /* pi_controller.h */; }; + 83CA157F1A988138005E7ED4 /* cached_interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA149C1A988138005E7ED4 /* cached_interp.c */; }; + 83CA15801A988138005E7ED4 /* cached_interp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA149D1A988138005E7ED4 /* cached_interp.h */; }; + 83CA15811A988138005E7ED4 /* cp0.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA149E1A988138005E7ED4 /* cp0.c */; }; + 83CA15821A988138005E7ED4 /* cp0.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA149F1A988138005E7ED4 /* cp0.h */; }; + 83CA15831A988138005E7ED4 /* cp1.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14A01A988138005E7ED4 /* cp1.c */; }; + 83CA15841A988138005E7ED4 /* cp1.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14A11A988138005E7ED4 /* cp1.h */; }; + 83CA15861A988138005E7ED4 /* exception.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14A31A988138005E7ED4 /* exception.c */; }; + 83CA15871A988138005E7ED4 /* exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14A41A988138005E7ED4 /* exception.h */; }; + 83CA15881A988138005E7ED4 /* fpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14A51A988138005E7ED4 /* fpu.h */; }; + 83CA15891A988138005E7ED4 /* instr_counters.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14A61A988138005E7ED4 /* instr_counters.c */; }; + 83CA158A1A988138005E7ED4 /* instr_counters.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14A71A988138005E7ED4 /* instr_counters.h */; }; + 83CA158B1A988138005E7ED4 /* interpreter.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14A81A988138005E7ED4 /* interpreter.def */; }; + 83CA158C1A988138005E7ED4 /* interpreter_cop0.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14A91A988138005E7ED4 /* interpreter_cop0.def */; }; + 83CA158D1A988138005E7ED4 /* interpreter_cop1.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14AA1A988138005E7ED4 /* interpreter_cop1.def */; }; + 83CA158E1A988138005E7ED4 /* interpreter_r4300.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14AB1A988138005E7ED4 /* interpreter_r4300.def */; }; + 83CA158F1A988138005E7ED4 /* interpreter_regimm.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14AC1A988138005E7ED4 /* interpreter_regimm.def */; }; + 83CA15901A988138005E7ED4 /* interpreter_special.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14AD1A988138005E7ED4 /* interpreter_special.def */; }; + 83CA15911A988138005E7ED4 /* interpreter_tlb.def in Resources */ = {isa = PBXBuildFile; fileRef = 83CA14AE1A988138005E7ED4 /* interpreter_tlb.def */; }; + 83CA15921A988138005E7ED4 /* interupt.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14AF1A988138005E7ED4 /* interupt.c */; }; + 83CA15931A988138005E7ED4 /* interupt.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14B01A988138005E7ED4 /* interupt.h */; }; + 83CA15941A988138005E7ED4 /* macros.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14B11A988138005E7ED4 /* macros.h */; }; + 83CA15951A988138005E7ED4 /* mi_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14B21A988138005E7ED4 /* mi_controller.c */; }; + 83CA15961A988138005E7ED4 /* mi_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14B31A988138005E7ED4 /* mi_controller.h */; }; + 83CA15A01A988138005E7ED4 /* ops.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14BE1A988138005E7ED4 /* ops.h */; }; + 83CA15A11A988138005E7ED4 /* pure_interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14BF1A988138005E7ED4 /* pure_interp.c */; }; + 83CA15A21A988138005E7ED4 /* pure_interp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C01A988138005E7ED4 /* pure_interp.h */; }; + 83CA15A31A988138005E7ED4 /* r4300.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14C11A988138005E7ED4 /* r4300.c */; }; + 83CA15A41A988138005E7ED4 /* r4300.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C21A988138005E7ED4 /* r4300.h */; }; + 83CA15A51A988138005E7ED4 /* r4300_core.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14C31A988138005E7ED4 /* r4300_core.c */; }; + 83CA15A61A988138005E7ED4 /* r4300_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C41A988138005E7ED4 /* r4300_core.h */; }; + 83CA15A71A988138005E7ED4 /* recomp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14C51A988138005E7ED4 /* recomp.c */; }; + 83CA15A81A988138005E7ED4 /* recomp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C61A988138005E7ED4 /* recomp.h */; }; + 83CA15A91A988138005E7ED4 /* recomph.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C71A988138005E7ED4 /* recomph.h */; }; + 83CA15AA1A988138005E7ED4 /* reset.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14C81A988138005E7ED4 /* reset.c */; }; + 83CA15AB1A988138005E7ED4 /* reset.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14C91A988138005E7ED4 /* reset.h */; }; + 83CA15AC1A988138005E7ED4 /* tlb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14CA1A988138005E7ED4 /* tlb.c */; }; + 83CA15AD1A988138005E7ED4 /* tlb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14CB1A988138005E7ED4 /* tlb.h */; }; + 83CA15C01A988138005E7ED4 /* assemble.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E01A988138005E7ED4 /* assemble.c */; }; + 83CA15C11A988138005E7ED4 /* assemble.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14E11A988138005E7ED4 /* assemble.h */; }; + 83CA15C21A988138005E7ED4 /* assemble_struct.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14E21A988138005E7ED4 /* assemble_struct.h */; }; + 83CA15C31A988138005E7ED4 /* gbc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E31A988138005E7ED4 /* gbc.c */; }; + 83CA15C41A988138005E7ED4 /* gcop0.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E41A988138005E7ED4 /* gcop0.c */; }; + 83CA15C51A988138005E7ED4 /* gcop1.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E51A988138005E7ED4 /* gcop1.c */; }; + 83CA15C61A988138005E7ED4 /* gcop1_d.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E61A988138005E7ED4 /* gcop1_d.c */; }; + 83CA15C71A988138005E7ED4 /* gcop1_l.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E71A988138005E7ED4 /* gcop1_l.c */; }; + 83CA15C81A988138005E7ED4 /* gcop1_s.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E81A988138005E7ED4 /* gcop1_s.c */; }; + 83CA15C91A988138005E7ED4 /* gcop1_w.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14E91A988138005E7ED4 /* gcop1_w.c */; }; + 83CA15CA1A988138005E7ED4 /* gr4300.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14EA1A988138005E7ED4 /* gr4300.c */; }; + 83CA15CB1A988138005E7ED4 /* gregimm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14EB1A988138005E7ED4 /* gregimm.c */; }; + 83CA15CC1A988138005E7ED4 /* gspecial.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14EC1A988138005E7ED4 /* gspecial.c */; }; + 83CA15CD1A988138005E7ED4 /* gtlb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14ED1A988138005E7ED4 /* gtlb.c */; }; + 83CA15CE1A988138005E7ED4 /* interpret.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14EE1A988138005E7ED4 /* interpret.h */; }; + 83CA15CF1A988138005E7ED4 /* regcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14EF1A988138005E7ED4 /* regcache.c */; }; + 83CA15D01A988138005E7ED4 /* regcache.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14F01A988138005E7ED4 /* regcache.h */; }; + 83CA15D11A988138005E7ED4 /* rjump.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14F11A988138005E7ED4 /* rjump.c */; }; + 83CA15D21A988138005E7ED4 /* rdp_core.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14F31A988138005E7ED4 /* rdp_core.c */; }; + 83CA15D31A988138005E7ED4 /* rdp_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14F41A988138005E7ED4 /* rdp_core.h */; }; + 83CA15D41A988138005E7ED4 /* rdram.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14F61A988138005E7ED4 /* rdram.c */; }; + 83CA15D51A988138005E7ED4 /* rdram.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14F71A988138005E7ED4 /* rdram.h */; }; + 83CA15D61A988138005E7ED4 /* rdram_detection_hack.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14F81A988138005E7ED4 /* rdram_detection_hack.c */; }; + 83CA15D71A988138005E7ED4 /* rdram_detection_hack.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14F91A988138005E7ED4 /* rdram_detection_hack.h */; }; + 83CA15D81A988138005E7ED4 /* ri_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14FA1A988138005E7ED4 /* ri_controller.c */; }; + 83CA15D91A988138005E7ED4 /* ri_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14FB1A988138005E7ED4 /* ri_controller.h */; }; + 83CA15DA1A988138005E7ED4 /* rsp_core.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA14FD1A988138005E7ED4 /* rsp_core.c */; }; + 83CA15DB1A988138005E7ED4 /* rsp_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA14FE1A988138005E7ED4 /* rsp_core.h */; }; + 83CA15DC1A988138005E7ED4 /* alist.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15001A988138005E7ED4 /* alist.c */; }; + 83CA15DD1A988138005E7ED4 /* alist.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15011A988138005E7ED4 /* alist.h */; }; + 83CA15DE1A988138005E7ED4 /* alist_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15021A988138005E7ED4 /* alist_audio.c */; }; + 83CA15DF1A988138005E7ED4 /* alist_naudio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15031A988138005E7ED4 /* alist_naudio.c */; }; + 83CA15E01A988138005E7ED4 /* alist_nead.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15041A988138005E7ED4 /* alist_nead.c */; }; + 83CA15E11A988138005E7ED4 /* arithmetics.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15051A988138005E7ED4 /* arithmetics.h */; }; + 83CA15E21A988138005E7ED4 /* audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15061A988138005E7ED4 /* audio.c */; }; + 83CA15E31A988138005E7ED4 /* audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15071A988138005E7ED4 /* audio.h */; }; + 83CA15E41A988138005E7ED4 /* cicx105.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15081A988138005E7ED4 /* cicx105.c */; }; + 83CA15E51A988138005E7ED4 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15091A988138005E7ED4 /* common.h */; }; + 83CA15E61A988138005E7ED4 /* hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA150A1A988138005E7ED4 /* hle.c */; }; + 83CA15E71A988138005E7ED4 /* hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA150B1A988138005E7ED4 /* hle.h */; }; + 83CA15E81A988138005E7ED4 /* hle_external.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA150C1A988138005E7ED4 /* hle_external.h */; }; + 83CA15E91A988138005E7ED4 /* hle_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA150D1A988138005E7ED4 /* hle_internal.h */; }; + 83CA15EA1A988138005E7ED4 /* jpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA150E1A988138005E7ED4 /* jpeg.c */; }; + 83CA15EB1A988138005E7ED4 /* LICENSES in Resources */ = {isa = PBXBuildFile; fileRef = 83CA150F1A988138005E7ED4 /* LICENSES */; }; + 83CA15EC1A988138005E7ED4 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15101A988138005E7ED4 /* memory.c */; }; + 83CA15ED1A988138005E7ED4 /* memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15111A988138005E7ED4 /* memory.h */; }; + 83CA15EE1A988138005E7ED4 /* mp3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15121A988138005E7ED4 /* mp3.c */; }; + 83CA15F01A988138005E7ED4 /* musyx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15151A988138005E7ED4 /* musyx.c */; }; + 83CA15F11A988138005E7ED4 /* plugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15161A988138005E7ED4 /* plugin.c */; }; + 83CA15F21A988138005E7ED4 /* ucodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15171A988138005E7ED4 /* ucodes.h */; }; + 83CA15F41A988138005E7ED4 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA151A1A988138005E7ED4 /* config.h */; }; + 83CA15F51A988138005E7ED4 /* execute.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA151B1A988138005E7ED4 /* execute.h */; }; + 83CA15F61A988138005E7ED4 /* matrix.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA151C1A988138005E7ED4 /* matrix.h */; }; + 83CA15F71A988138005E7ED4 /* rsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA151D1A988138005E7ED4 /* rsp.c */; }; + 83CA15F81A988138005E7ED4 /* rsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA151E1A988138005E7ED4 /* rsp.h */; }; + 83CA15F91A988138005E7ED4 /* rsp_lle.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA151F1A988138005E7ED4 /* rsp_lle.h */; }; + 83CA15FA1A988138005E7ED4 /* su.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15201A988138005E7ED4 /* su.h */; }; + 83CA15FB1A988138005E7ED4 /* cf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15221A988138005E7ED4 /* cf.h */; }; + 83CA15FC1A988138005E7ED4 /* clamp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15231A988138005E7ED4 /* clamp.h */; }; + 83CA15FD1A988138005E7ED4 /* divrom.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15241A988138005E7ED4 /* divrom.h */; }; + 83CA15FE1A988138005E7ED4 /* shuffle.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15251A988138005E7ED4 /* shuffle.h */; }; + 83CA15FF1A988138005E7ED4 /* vabs.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15261A988138005E7ED4 /* vabs.h */; }; + 83CA16001A988138005E7ED4 /* vadd.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15271A988138005E7ED4 /* vadd.h */; }; + 83CA16011A988138005E7ED4 /* vaddc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15281A988138005E7ED4 /* vaddc.h */; }; + 83CA16021A988138005E7ED4 /* vand.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15291A988138005E7ED4 /* vand.h */; }; + 83CA16031A988138005E7ED4 /* vch.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152A1A988138005E7ED4 /* vch.h */; }; + 83CA16041A988138005E7ED4 /* vcl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152B1A988138005E7ED4 /* vcl.h */; }; + 83CA16051A988138005E7ED4 /* vcr.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152C1A988138005E7ED4 /* vcr.h */; }; + 83CA16061A988138005E7ED4 /* veq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152D1A988138005E7ED4 /* veq.h */; }; + 83CA16071A988138005E7ED4 /* vge.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152E1A988138005E7ED4 /* vge.h */; }; + 83CA16081A988138005E7ED4 /* vlt.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA152F1A988138005E7ED4 /* vlt.h */; }; + 83CA16091A988138005E7ED4 /* vmacf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15301A988138005E7ED4 /* vmacf.h */; }; + 83CA160A1A988138005E7ED4 /* vmacq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15311A988138005E7ED4 /* vmacq.h */; }; + 83CA160B1A988138005E7ED4 /* vmacu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15321A988138005E7ED4 /* vmacu.h */; }; + 83CA160C1A988138005E7ED4 /* vmadh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15331A988138005E7ED4 /* vmadh.h */; }; + 83CA160D1A988138005E7ED4 /* vmadl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15341A988138005E7ED4 /* vmadl.h */; }; + 83CA160E1A988138005E7ED4 /* vmadm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15351A988138005E7ED4 /* vmadm.h */; }; + 83CA160F1A988138005E7ED4 /* vmadn.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15361A988138005E7ED4 /* vmadn.h */; }; + 83CA16101A988138005E7ED4 /* vmov.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15371A988138005E7ED4 /* vmov.h */; }; + 83CA16111A988138005E7ED4 /* vmrg.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15381A988138005E7ED4 /* vmrg.h */; }; + 83CA16121A988138005E7ED4 /* vmudh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15391A988138005E7ED4 /* vmudh.h */; }; + 83CA16131A988138005E7ED4 /* vmudl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153A1A988138005E7ED4 /* vmudl.h */; }; + 83CA16141A988138005E7ED4 /* vmudm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153B1A988138005E7ED4 /* vmudm.h */; }; + 83CA16151A988138005E7ED4 /* vmudn.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153C1A988138005E7ED4 /* vmudn.h */; }; + 83CA16161A988138005E7ED4 /* vmulf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153D1A988138005E7ED4 /* vmulf.h */; }; + 83CA16171A988138005E7ED4 /* vmulu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153E1A988138005E7ED4 /* vmulu.h */; }; + 83CA16181A988138005E7ED4 /* vnand.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA153F1A988138005E7ED4 /* vnand.h */; }; + 83CA16191A988138005E7ED4 /* vne.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15401A988138005E7ED4 /* vne.h */; }; + 83CA161A1A988138005E7ED4 /* vnop.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15411A988138005E7ED4 /* vnop.h */; }; + 83CA161B1A988138005E7ED4 /* vnor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15421A988138005E7ED4 /* vnor.h */; }; + 83CA161C1A988138005E7ED4 /* vnxor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15431A988138005E7ED4 /* vnxor.h */; }; + 83CA161D1A988138005E7ED4 /* vor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15441A988138005E7ED4 /* vor.h */; }; + 83CA161E1A988138005E7ED4 /* vrcp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15451A988138005E7ED4 /* vrcp.h */; }; + 83CA161F1A988138005E7ED4 /* vrcph.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15461A988138005E7ED4 /* vrcph.h */; }; + 83CA16201A988138005E7ED4 /* vrcpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15471A988138005E7ED4 /* vrcpl.h */; }; + 83CA16211A988138005E7ED4 /* vrsq.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15481A988138005E7ED4 /* vrsq.h */; }; + 83CA16221A988138005E7ED4 /* vrsqh.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15491A988138005E7ED4 /* vrsqh.h */; }; + 83CA16231A988138005E7ED4 /* vrsql.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154A1A988138005E7ED4 /* vrsql.h */; }; + 83CA16241A988138005E7ED4 /* vsaw.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154B1A988138005E7ED4 /* vsaw.h */; }; + 83CA16251A988138005E7ED4 /* vsub.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154C1A988138005E7ED4 /* vsub.h */; }; + 83CA16261A988138005E7ED4 /* vsubc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154D1A988138005E7ED4 /* vsubc.h */; }; + 83CA16271A988138005E7ED4 /* vu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154E1A988138005E7ED4 /* vu.h */; }; + 83CA16281A988138005E7ED4 /* vxor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA154F1A988138005E7ED4 /* vxor.h */; }; + 83CA16291A988138005E7ED4 /* cic.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15511A988138005E7ED4 /* cic.c */; }; + 83CA162A1A988138005E7ED4 /* cic.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15521A988138005E7ED4 /* cic.h */; }; + 83CA162B1A988138005E7ED4 /* game_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15531A988138005E7ED4 /* game_controller.c */; }; + 83CA162C1A988138005E7ED4 /* game_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15541A988138005E7ED4 /* game_controller.h */; }; + 83CA162D1A988138005E7ED4 /* n64_cic_nus_6105.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15551A988138005E7ED4 /* n64_cic_nus_6105.c */; }; + 83CA162E1A988138005E7ED4 /* n64_cic_nus_6105.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15561A988138005E7ED4 /* n64_cic_nus_6105.h */; }; + 83CA162F1A988138005E7ED4 /* pif.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15571A988138005E7ED4 /* pif.c */; }; + 83CA16301A988138005E7ED4 /* pif.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15581A988138005E7ED4 /* pif.h */; }; + 83CA16311A988138005E7ED4 /* si_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15591A988138005E7ED4 /* si_controller.c */; }; + 83CA16321A988138005E7ED4 /* si_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA155A1A988138005E7ED4 /* si_controller.h */; }; + 83CA16331A988138005E7ED4 /* usf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA155C1A988138005E7ED4 /* usf.c */; }; + 83CA16341A988138005E7ED4 /* usf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA155D1A988138005E7ED4 /* usf.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 83CA16351A988138005E7ED4 /* usf_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA155E1A988138005E7ED4 /* usf_internal.h */; }; + 83CA16361A988138005E7ED4 /* vi_controller.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15601A988138005E7ED4 /* vi_controller.c */; }; + 83CA16371A988138005E7ED4 /* vi_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15611A988138005E7ED4 /* vi_controller.h */; }; + 83CA16391A988191005E7ED4 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CA16381A988191005E7ED4 /* libz.dylib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 8319EF171A219846009DD5C4 /* cpu_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpu_hle.c; sourceTree = ""; }; - 8319EF181A219846009DD5C4 /* cpu_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu_hle.h; sourceTree = ""; }; - 8319EF1B1A2198B9009DD5C4 /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os.c; sourceTree = ""; }; - 8319EF1C1A2198B9009DD5C4 /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os.h; sourceTree = ""; }; - 8319EF1F1A219BE7009DD5C4 /* audiolib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audiolib.c; sourceTree = ""; }; - 8319EF201A219BE7009DD5C4 /* audiolib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audiolib.h; sourceTree = ""; }; - 8378415418C6E56B002C4FE5 /* alist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist.c; sourceTree = ""; }; - 8378415518C6E56B002C4FE5 /* alist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist.h; sourceTree = ""; }; - 8378415618C6E56B002C4FE5 /* alist_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_audio.c; sourceTree = ""; }; - 8378415818C6E56B002C4FE5 /* alist_naudio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_naudio.c; sourceTree = ""; }; - 8378415918C6E56B002C4FE5 /* alist_nead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_nead.c; sourceTree = ""; }; - 8378415A18C6E56B002C4FE5 /* arithmetics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arithmetics.h; sourceTree = ""; }; - 8378415D18C6E56B002C4FE5 /* cicx105.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cicx105.c; sourceTree = ""; }; - 8378415F18C6E56B002C4FE5 /* jpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jpeg.c; sourceTree = ""; }; - 8378416518C6E56B002C4FE5 /* mp3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3.c; sourceTree = ""; }; - 8378416618C6E56B002C4FE5 /* musyx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = musyx.c; sourceTree = ""; }; - 837841B818C847B2002C4FE5 /* audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio.c; sourceTree = ""; }; - 837841B918C847B2002C4FE5 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = ""; }; - 837841BC18C847B2002C4FE5 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = ""; }; - 837841BD18C847B2002C4FE5 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; - 837841BE18C847B2002C4FE5 /* plugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin.c; sourceTree = ""; }; - 83A2248E18CAC28500FE4173 /* hle_external.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle_external.h; sourceTree = ""; }; - 83A2248F18CAC28500FE4173 /* hle_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle_internal.h; sourceTree = ""; }; - 83A2249018CAC28500FE4173 /* hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hle.c; sourceTree = ""; }; - 83A2249118CAC28500FE4173 /* hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle.h; sourceTree = ""; }; + 8379B5881AA4237E00F28A95 /* barray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = barray.c; sourceTree = ""; }; + 8379B5891AA4237E00F28A95 /* barray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = barray.h; sourceTree = ""; }; + 83C0787A1A9B544300ABBB67 /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = ""; }; + 83C0787B1A9B544300ABBB67 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; 83C8B62218AF57770071B040 /* lazyusf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lazyusf.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 83C8B65918AF58080071B040 /* audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio.c; sourceTree = ""; }; - 83C8B65A18AF58080071B040 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = ""; }; - 83C8B65B18AF58080071B040 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; - 83C8B65C18AF58080071B040 /* cpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpu.c; sourceTree = ""; }; - 83C8B65D18AF58080071B040 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = ""; }; - 83C8B65E18AF58080071B040 /* dma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dma.c; sourceTree = ""; }; - 83C8B65F18AF58080071B040 /* dma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dma.h; sourceTree = ""; }; - 83C8B66018AF58080071B040 /* exception.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exception.c; sourceTree = ""; }; - 83C8B66118AF58080071B040 /* exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception.h; sourceTree = ""; }; - 83C8B66218AF58080071B040 /* interpreter_cpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interpreter_cpu.c; sourceTree = ""; }; - 83C8B66318AF58080071B040 /* interpreter_cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interpreter_cpu.h; sourceTree = ""; }; - 83C8B66418AF58080071B040 /* interpreter_ops.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interpreter_ops.c; sourceTree = ""; }; - 83C8B66518AF58080071B040 /* interpreter_ops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interpreter_ops.h; sourceTree = ""; }; - 83C8B66618AF58080071B040 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; - 83C8B66718AF58080071B040 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = ""; }; - 83C8B66818AF58080071B040 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = ""; }; - 83C8B66918AF58080071B040 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; - 83C8B66A18AF58080071B040 /* opcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcode.h; sourceTree = ""; }; - 83C8B66B18AF58080071B040 /* pif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pif.c; sourceTree = ""; }; - 83C8B66C18AF58080071B040 /* pif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pif.h; sourceTree = ""; }; - 83C8B66D18AF58080071B040 /* registers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = registers.c; sourceTree = ""; }; - 83C8B66E18AF58080071B040 /* registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = registers.h; sourceTree = ""; }; - 83C8B67018AF58080071B040 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; - 83C8B67118AF58080071B040 /* execute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = execute.h; sourceTree = ""; }; - 83C8B67218AF58080071B040 /* rsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rsp.c; sourceTree = ""; }; - 83C8B67318AF58080071B040 /* rsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsp.h; sourceTree = ""; }; - 83C8B67418AF58080071B040 /* su.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = su.h; sourceTree = ""; }; - 83C8B67618AF58080071B040 /* cf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cf.h; sourceTree = ""; }; - 83C8B67718AF58080071B040 /* clamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clamp.h; sourceTree = ""; }; - 83C8B67818AF58080071B040 /* divrom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = divrom.h; sourceTree = ""; }; - 83C8B67918AF58080071B040 /* shuffle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shuffle.h; sourceTree = ""; }; - 83C8B67A18AF58080071B040 /* vabs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vabs.h; sourceTree = ""; }; - 83C8B67B18AF58080071B040 /* vadd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vadd.h; sourceTree = ""; }; - 83C8B67C18AF58080071B040 /* vaddc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vaddc.h; sourceTree = ""; }; - 83C8B67D18AF58080071B040 /* vand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vand.h; sourceTree = ""; }; - 83C8B67E18AF58080071B040 /* vch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vch.h; sourceTree = ""; }; - 83C8B67F18AF58080071B040 /* vcl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcl.h; sourceTree = ""; }; - 83C8B68018AF58080071B040 /* vcr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcr.h; sourceTree = ""; }; - 83C8B68118AF58080071B040 /* veq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = veq.h; sourceTree = ""; }; - 83C8B68218AF58080071B040 /* vge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vge.h; sourceTree = ""; }; - 83C8B68318AF58080071B040 /* vlt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vlt.h; sourceTree = ""; }; - 83C8B68418AF58080071B040 /* vmacf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacf.h; sourceTree = ""; }; - 83C8B68518AF58080071B040 /* vmacq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacq.h; sourceTree = ""; }; - 83C8B68618AF58080071B040 /* vmacu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacu.h; sourceTree = ""; }; - 83C8B68718AF58080071B040 /* vmadh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadh.h; sourceTree = ""; }; - 83C8B68818AF58080071B040 /* vmadl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadl.h; sourceTree = ""; }; - 83C8B68918AF58080071B040 /* vmadm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadm.h; sourceTree = ""; }; - 83C8B68A18AF58080071B040 /* vmadn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadn.h; sourceTree = ""; }; - 83C8B68B18AF58080071B040 /* vmov.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmov.h; sourceTree = ""; }; - 83C8B68C18AF58080071B040 /* vmrg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmrg.h; sourceTree = ""; }; - 83C8B68D18AF58080071B040 /* vmudh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudh.h; sourceTree = ""; }; - 83C8B68E18AF58080071B040 /* vmudl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudl.h; sourceTree = ""; }; - 83C8B68F18AF58080071B040 /* vmudm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudm.h; sourceTree = ""; }; - 83C8B69018AF58080071B040 /* vmudn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudn.h; sourceTree = ""; }; - 83C8B69118AF58080071B040 /* vmulf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmulf.h; sourceTree = ""; }; - 83C8B69218AF58080071B040 /* vmulu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmulu.h; sourceTree = ""; }; - 83C8B69318AF58080071B040 /* vnand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnand.h; sourceTree = ""; }; - 83C8B69418AF58080071B040 /* vne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vne.h; sourceTree = ""; }; - 83C8B69518AF58080071B040 /* vnop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnop.h; sourceTree = ""; }; - 83C8B69618AF58080071B040 /* vnor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnor.h; sourceTree = ""; }; - 83C8B69718AF58080071B040 /* vnxor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnxor.h; sourceTree = ""; }; - 83C8B69818AF58080071B040 /* vor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vor.h; sourceTree = ""; }; - 83C8B69918AF58080071B040 /* vrcp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcp.h; sourceTree = ""; }; - 83C8B69A18AF58080071B040 /* vrcph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcph.h; sourceTree = ""; }; - 83C8B69B18AF58080071B040 /* vrcpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcpl.h; sourceTree = ""; }; - 83C8B69C18AF58080071B040 /* vrsq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsq.h; sourceTree = ""; }; - 83C8B69D18AF58080071B040 /* vrsqh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsqh.h; sourceTree = ""; }; - 83C8B69E18AF58080071B040 /* vrsql.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsql.h; sourceTree = ""; }; - 83C8B69F18AF58080071B040 /* vsaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsaw.h; sourceTree = ""; }; - 83C8B6A018AF58080071B040 /* vsub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsub.h; sourceTree = ""; }; - 83C8B6A118AF58080071B040 /* vsubc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsubc.h; sourceTree = ""; }; - 83C8B6A218AF58080071B040 /* vu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vu.h; sourceTree = ""; }; - 83C8B6A318AF58080071B040 /* vxor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vxor.h; sourceTree = ""; }; - 83C8B6A418AF58080071B040 /* rsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsp.h; sourceTree = ""; }; - 83C8B6A518AF58080071B040 /* tlb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tlb.c; sourceTree = ""; }; - 83C8B6A618AF58080071B040 /* tlb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tlb.h; sourceTree = ""; }; - 83C8B6A718AF58080071B040 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; - 83C8B6A818AF58080071B040 /* usf_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usf_internal.h; sourceTree = ""; }; - 83C8B6A918AF58080071B040 /* usf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usf.c; sourceTree = ""; }; - 83C8B6AA18AF58080071B040 /* usf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usf.h; sourceTree = ""; }; - 83C8B6FD18AF59E70071B040 /* lazyusf-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "lazyusf-Info.plist"; sourceTree = ""; }; 83CA146E1A987E91005E7ED4 /* preproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preproc.h; sourceTree = ""; }; 83CA14701A987E91005E7ED4 /* dbg_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dbg_decoder.c; sourceTree = ""; }; 83CA14711A987E91005E7ED4 /* dbg_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder.h; sourceTree = ""; }; 83CA14721A987E91005E7ED4 /* dbg_decoder_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder_local.h; sourceTree = ""; }; 83CA14731A987E91005E7ED4 /* dbg_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_types.h; sourceTree = ""; }; - 83FBECB918ECE86B00311448 /* ucodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucodes.h; sourceTree = ""; }; + 83CA147A1A988137005E7ED4 /* ai_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ai_controller.c; sourceTree = ""; }; + 83CA147B1A988137005E7ED4 /* ai_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ai_controller.h; sourceTree = ""; }; + 83CA147D1A988137005E7ED4 /* api_export.ver */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = api_export.ver; sourceTree = ""; }; + 83CA147E1A988137005E7ED4 /* callbacks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = callbacks.c; sourceTree = ""; }; + 83CA147F1A988137005E7ED4 /* callbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = callbacks.h; sourceTree = ""; }; + 83CA14801A988137005E7ED4 /* m64p_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_common.h; sourceTree = ""; }; + 83CA14811A988137005E7ED4 /* m64p_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_config.h; sourceTree = ""; }; + 83CA14821A988137005E7ED4 /* m64p_debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_debugger.h; sourceTree = ""; }; + 83CA14831A988137005E7ED4 /* m64p_frontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_frontend.h; sourceTree = ""; }; + 83CA14841A988138005E7ED4 /* m64p_plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_plugin.h; sourceTree = ""; }; + 83CA14851A988138005E7ED4 /* m64p_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_types.h; sourceTree = ""; }; + 83CA14861A988138005E7ED4 /* m64p_vidext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m64p_vidext.h; sourceTree = ""; }; + 83CA14881A988138005E7ED4 /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = ""; }; + 83CA14891A988138005E7ED4 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 83CA148A1A988138005E7ED4 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = ""; }; + 83CA148B1A988138005E7ED4 /* rom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rom.c; sourceTree = ""; }; + 83CA148C1A988138005E7ED4 /* rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rom.h; sourceTree = ""; }; + 83CA148D1A988138005E7ED4 /* savestates.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = savestates.c; sourceTree = ""; }; + 83CA148E1A988138005E7ED4 /* savestates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = savestates.h; sourceTree = ""; }; + 83CA148F1A988138005E7ED4 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = ""; }; + 83CA14901A988138005E7ED4 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; + 83CA14911A988138005E7ED4 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = ""; }; + 83CA14931A988138005E7ED4 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = ""; }; + 83CA14941A988138005E7ED4 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; + 83CA14961A988138005E7ED4 /* cart_rom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cart_rom.c; sourceTree = ""; }; + 83CA14971A988138005E7ED4 /* cart_rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cart_rom.h; sourceTree = ""; }; + 83CA14981A988138005E7ED4 /* pi_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pi_controller.c; sourceTree = ""; }; + 83CA14991A988138005E7ED4 /* pi_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pi_controller.h; sourceTree = ""; }; + 83CA149C1A988138005E7ED4 /* cached_interp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cached_interp.c; sourceTree = ""; }; + 83CA149D1A988138005E7ED4 /* cached_interp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cached_interp.h; sourceTree = ""; }; + 83CA149E1A988138005E7ED4 /* cp0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cp0.c; sourceTree = ""; }; + 83CA149F1A988138005E7ED4 /* cp0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cp0.h; sourceTree = ""; }; + 83CA14A01A988138005E7ED4 /* cp1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cp1.c; sourceTree = ""; }; + 83CA14A11A988138005E7ED4 /* cp1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cp1.h; sourceTree = ""; }; + 83CA14A31A988138005E7ED4 /* exception.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exception.c; sourceTree = ""; }; + 83CA14A41A988138005E7ED4 /* exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception.h; sourceTree = ""; }; + 83CA14A51A988138005E7ED4 /* fpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fpu.h; sourceTree = ""; }; + 83CA14A61A988138005E7ED4 /* instr_counters.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = instr_counters.c; sourceTree = ""; }; + 83CA14A71A988138005E7ED4 /* instr_counters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instr_counters.h; sourceTree = ""; }; + 83CA14A81A988138005E7ED4 /* interpreter.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter.def; sourceTree = ""; }; + 83CA14A91A988138005E7ED4 /* interpreter_cop0.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_cop0.def; sourceTree = ""; }; + 83CA14AA1A988138005E7ED4 /* interpreter_cop1.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_cop1.def; sourceTree = ""; }; + 83CA14AB1A988138005E7ED4 /* interpreter_r4300.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_r4300.def; sourceTree = ""; }; + 83CA14AC1A988138005E7ED4 /* interpreter_regimm.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_regimm.def; sourceTree = ""; }; + 83CA14AD1A988138005E7ED4 /* interpreter_special.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_special.def; sourceTree = ""; }; + 83CA14AE1A988138005E7ED4 /* interpreter_tlb.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = interpreter_tlb.def; sourceTree = ""; }; + 83CA14AF1A988138005E7ED4 /* interupt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interupt.c; sourceTree = ""; }; + 83CA14B01A988138005E7ED4 /* interupt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interupt.h; sourceTree = ""; }; + 83CA14B11A988138005E7ED4 /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macros.h; sourceTree = ""; }; + 83CA14B21A988138005E7ED4 /* mi_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mi_controller.c; sourceTree = ""; }; + 83CA14B31A988138005E7ED4 /* mi_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mi_controller.h; sourceTree = ""; }; + 83CA14BE1A988138005E7ED4 /* ops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ops.h; sourceTree = ""; }; + 83CA14BF1A988138005E7ED4 /* pure_interp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pure_interp.c; sourceTree = ""; }; + 83CA14C01A988138005E7ED4 /* pure_interp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pure_interp.h; sourceTree = ""; }; + 83CA14C11A988138005E7ED4 /* r4300.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = r4300.c; sourceTree = ""; }; + 83CA14C21A988138005E7ED4 /* r4300.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = r4300.h; sourceTree = ""; }; + 83CA14C31A988138005E7ED4 /* r4300_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = r4300_core.c; sourceTree = ""; }; + 83CA14C41A988138005E7ED4 /* r4300_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = r4300_core.h; sourceTree = ""; }; + 83CA14C51A988138005E7ED4 /* recomp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = recomp.c; sourceTree = ""; }; + 83CA14C61A988138005E7ED4 /* recomp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recomp.h; sourceTree = ""; }; + 83CA14C71A988138005E7ED4 /* recomph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recomph.h; sourceTree = ""; }; + 83CA14C81A988138005E7ED4 /* reset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = reset.c; sourceTree = ""; }; + 83CA14C91A988138005E7ED4 /* reset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reset.h; sourceTree = ""; }; + 83CA14CA1A988138005E7ED4 /* tlb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tlb.c; sourceTree = ""; }; + 83CA14CB1A988138005E7ED4 /* tlb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tlb.h; sourceTree = ""; }; + 83CA14E01A988138005E7ED4 /* assemble.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = assemble.c; sourceTree = ""; }; + 83CA14E11A988138005E7ED4 /* assemble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assemble.h; sourceTree = ""; }; + 83CA14E21A988138005E7ED4 /* assemble_struct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assemble_struct.h; sourceTree = ""; }; + 83CA14E31A988138005E7ED4 /* gbc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gbc.c; sourceTree = ""; }; + 83CA14E41A988138005E7ED4 /* gcop0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop0.c; sourceTree = ""; }; + 83CA14E51A988138005E7ED4 /* gcop1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop1.c; sourceTree = ""; }; + 83CA14E61A988138005E7ED4 /* gcop1_d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop1_d.c; sourceTree = ""; }; + 83CA14E71A988138005E7ED4 /* gcop1_l.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop1_l.c; sourceTree = ""; }; + 83CA14E81A988138005E7ED4 /* gcop1_s.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop1_s.c; sourceTree = ""; }; + 83CA14E91A988138005E7ED4 /* gcop1_w.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcop1_w.c; sourceTree = ""; }; + 83CA14EA1A988138005E7ED4 /* gr4300.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gr4300.c; sourceTree = ""; }; + 83CA14EB1A988138005E7ED4 /* gregimm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gregimm.c; sourceTree = ""; }; + 83CA14EC1A988138005E7ED4 /* gspecial.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gspecial.c; sourceTree = ""; }; + 83CA14ED1A988138005E7ED4 /* gtlb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gtlb.c; sourceTree = ""; }; + 83CA14EE1A988138005E7ED4 /* interpret.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interpret.h; sourceTree = ""; }; + 83CA14EF1A988138005E7ED4 /* regcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = regcache.c; sourceTree = ""; }; + 83CA14F01A988138005E7ED4 /* regcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = regcache.h; sourceTree = ""; }; + 83CA14F11A988138005E7ED4 /* rjump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rjump.c; sourceTree = ""; }; + 83CA14F31A988138005E7ED4 /* rdp_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rdp_core.c; sourceTree = ""; }; + 83CA14F41A988138005E7ED4 /* rdp_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rdp_core.h; sourceTree = ""; }; + 83CA14F61A988138005E7ED4 /* rdram.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rdram.c; sourceTree = ""; }; + 83CA14F71A988138005E7ED4 /* rdram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rdram.h; sourceTree = ""; }; + 83CA14F81A988138005E7ED4 /* rdram_detection_hack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rdram_detection_hack.c; sourceTree = ""; }; + 83CA14F91A988138005E7ED4 /* rdram_detection_hack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rdram_detection_hack.h; sourceTree = ""; }; + 83CA14FA1A988138005E7ED4 /* ri_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ri_controller.c; sourceTree = ""; }; + 83CA14FB1A988138005E7ED4 /* ri_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ri_controller.h; sourceTree = ""; }; + 83CA14FD1A988138005E7ED4 /* rsp_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rsp_core.c; sourceTree = ""; }; + 83CA14FE1A988138005E7ED4 /* rsp_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsp_core.h; sourceTree = ""; }; + 83CA15001A988138005E7ED4 /* alist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist.c; sourceTree = ""; }; + 83CA15011A988138005E7ED4 /* alist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist.h; sourceTree = ""; }; + 83CA15021A988138005E7ED4 /* alist_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_audio.c; sourceTree = ""; }; + 83CA15031A988138005E7ED4 /* alist_naudio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_naudio.c; sourceTree = ""; }; + 83CA15041A988138005E7ED4 /* alist_nead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_nead.c; sourceTree = ""; }; + 83CA15051A988138005E7ED4 /* arithmetics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arithmetics.h; sourceTree = ""; }; + 83CA15061A988138005E7ED4 /* audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio.c; sourceTree = ""; }; + 83CA15071A988138005E7ED4 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = ""; }; + 83CA15081A988138005E7ED4 /* cicx105.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cicx105.c; sourceTree = ""; }; + 83CA15091A988138005E7ED4 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + 83CA150A1A988138005E7ED4 /* hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hle.c; sourceTree = ""; }; + 83CA150B1A988138005E7ED4 /* hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle.h; sourceTree = ""; }; + 83CA150C1A988138005E7ED4 /* hle_external.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle_external.h; sourceTree = ""; }; + 83CA150D1A988138005E7ED4 /* hle_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hle_internal.h; sourceTree = ""; }; + 83CA150E1A988138005E7ED4 /* jpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jpeg.c; sourceTree = ""; }; + 83CA150F1A988138005E7ED4 /* LICENSES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSES; sourceTree = ""; }; + 83CA15101A988138005E7ED4 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = ""; }; + 83CA15111A988138005E7ED4 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; + 83CA15121A988138005E7ED4 /* mp3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3.c; sourceTree = ""; }; + 83CA15141A988138005E7ED4 /* stdbool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdbool.h; sourceTree = ""; }; + 83CA15151A988138005E7ED4 /* musyx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = musyx.c; sourceTree = ""; }; + 83CA15161A988138005E7ED4 /* plugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin.c; sourceTree = ""; }; + 83CA15171A988138005E7ED4 /* ucodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucodes.h; sourceTree = ""; }; + 83CA151A1A988138005E7ED4 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; + 83CA151B1A988138005E7ED4 /* execute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = execute.h; sourceTree = ""; }; + 83CA151C1A988138005E7ED4 /* matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix.h; sourceTree = ""; }; + 83CA151D1A988138005E7ED4 /* rsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rsp.c; sourceTree = ""; }; + 83CA151E1A988138005E7ED4 /* rsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsp.h; sourceTree = ""; }; + 83CA151F1A988138005E7ED4 /* rsp_lle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsp_lle.h; sourceTree = ""; }; + 83CA15201A988138005E7ED4 /* su.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = su.h; sourceTree = ""; }; + 83CA15221A988138005E7ED4 /* cf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cf.h; sourceTree = ""; }; + 83CA15231A988138005E7ED4 /* clamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clamp.h; sourceTree = ""; }; + 83CA15241A988138005E7ED4 /* divrom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = divrom.h; sourceTree = ""; }; + 83CA15251A988138005E7ED4 /* shuffle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shuffle.h; sourceTree = ""; }; + 83CA15261A988138005E7ED4 /* vabs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vabs.h; sourceTree = ""; }; + 83CA15271A988138005E7ED4 /* vadd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vadd.h; sourceTree = ""; }; + 83CA15281A988138005E7ED4 /* vaddc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vaddc.h; sourceTree = ""; }; + 83CA15291A988138005E7ED4 /* vand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vand.h; sourceTree = ""; }; + 83CA152A1A988138005E7ED4 /* vch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vch.h; sourceTree = ""; }; + 83CA152B1A988138005E7ED4 /* vcl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcl.h; sourceTree = ""; }; + 83CA152C1A988138005E7ED4 /* vcr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcr.h; sourceTree = ""; }; + 83CA152D1A988138005E7ED4 /* veq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = veq.h; sourceTree = ""; }; + 83CA152E1A988138005E7ED4 /* vge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vge.h; sourceTree = ""; }; + 83CA152F1A988138005E7ED4 /* vlt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vlt.h; sourceTree = ""; }; + 83CA15301A988138005E7ED4 /* vmacf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacf.h; sourceTree = ""; }; + 83CA15311A988138005E7ED4 /* vmacq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacq.h; sourceTree = ""; }; + 83CA15321A988138005E7ED4 /* vmacu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmacu.h; sourceTree = ""; }; + 83CA15331A988138005E7ED4 /* vmadh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadh.h; sourceTree = ""; }; + 83CA15341A988138005E7ED4 /* vmadl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadl.h; sourceTree = ""; }; + 83CA15351A988138005E7ED4 /* vmadm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadm.h; sourceTree = ""; }; + 83CA15361A988138005E7ED4 /* vmadn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmadn.h; sourceTree = ""; }; + 83CA15371A988138005E7ED4 /* vmov.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmov.h; sourceTree = ""; }; + 83CA15381A988138005E7ED4 /* vmrg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmrg.h; sourceTree = ""; }; + 83CA15391A988138005E7ED4 /* vmudh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudh.h; sourceTree = ""; }; + 83CA153A1A988138005E7ED4 /* vmudl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudl.h; sourceTree = ""; }; + 83CA153B1A988138005E7ED4 /* vmudm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudm.h; sourceTree = ""; }; + 83CA153C1A988138005E7ED4 /* vmudn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmudn.h; sourceTree = ""; }; + 83CA153D1A988138005E7ED4 /* vmulf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmulf.h; sourceTree = ""; }; + 83CA153E1A988138005E7ED4 /* vmulu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmulu.h; sourceTree = ""; }; + 83CA153F1A988138005E7ED4 /* vnand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnand.h; sourceTree = ""; }; + 83CA15401A988138005E7ED4 /* vne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vne.h; sourceTree = ""; }; + 83CA15411A988138005E7ED4 /* vnop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnop.h; sourceTree = ""; }; + 83CA15421A988138005E7ED4 /* vnor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnor.h; sourceTree = ""; }; + 83CA15431A988138005E7ED4 /* vnxor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnxor.h; sourceTree = ""; }; + 83CA15441A988138005E7ED4 /* vor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vor.h; sourceTree = ""; }; + 83CA15451A988138005E7ED4 /* vrcp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcp.h; sourceTree = ""; }; + 83CA15461A988138005E7ED4 /* vrcph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcph.h; sourceTree = ""; }; + 83CA15471A988138005E7ED4 /* vrcpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrcpl.h; sourceTree = ""; }; + 83CA15481A988138005E7ED4 /* vrsq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsq.h; sourceTree = ""; }; + 83CA15491A988138005E7ED4 /* vrsqh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsqh.h; sourceTree = ""; }; + 83CA154A1A988138005E7ED4 /* vrsql.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vrsql.h; sourceTree = ""; }; + 83CA154B1A988138005E7ED4 /* vsaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsaw.h; sourceTree = ""; }; + 83CA154C1A988138005E7ED4 /* vsub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsub.h; sourceTree = ""; }; + 83CA154D1A988138005E7ED4 /* vsubc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsubc.h; sourceTree = ""; }; + 83CA154E1A988138005E7ED4 /* vu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vu.h; sourceTree = ""; }; + 83CA154F1A988138005E7ED4 /* vxor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vxor.h; sourceTree = ""; }; + 83CA15511A988138005E7ED4 /* cic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cic.c; sourceTree = ""; }; + 83CA15521A988138005E7ED4 /* cic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic.h; sourceTree = ""; }; + 83CA15531A988138005E7ED4 /* game_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = game_controller.c; sourceTree = ""; }; + 83CA15541A988138005E7ED4 /* game_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = game_controller.h; sourceTree = ""; }; + 83CA15551A988138005E7ED4 /* n64_cic_nus_6105.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = n64_cic_nus_6105.c; sourceTree = ""; }; + 83CA15561A988138005E7ED4 /* n64_cic_nus_6105.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = n64_cic_nus_6105.h; sourceTree = ""; }; + 83CA15571A988138005E7ED4 /* pif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pif.c; sourceTree = ""; }; + 83CA15581A988138005E7ED4 /* pif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pif.h; sourceTree = ""; }; + 83CA15591A988138005E7ED4 /* si_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = si_controller.c; sourceTree = ""; }; + 83CA155A1A988138005E7ED4 /* si_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = si_controller.h; sourceTree = ""; }; + 83CA155C1A988138005E7ED4 /* usf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usf.c; sourceTree = ""; }; + 83CA155D1A988138005E7ED4 /* usf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usf.h; sourceTree = ""; }; + 83CA155E1A988138005E7ED4 /* usf_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usf_internal.h; sourceTree = ""; }; + 83CA15601A988138005E7ED4 /* vi_controller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vi_controller.c; sourceTree = ""; }; + 83CA15611A988138005E7ED4 /* vi_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vi_controller.h; sourceTree = ""; }; + 83CA16381A988191005E7ED4 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -241,39 +405,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 83CA16391A988191005E7ED4 /* libz.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 8378415318C6E56B002C4FE5 /* rsp_hle */ = { - isa = PBXGroup; - children = ( - 83FBECB918ECE86B00311448 /* ucodes.h */, - 83A2248E18CAC28500FE4173 /* hle_external.h */, - 83A2248F18CAC28500FE4173 /* hle_internal.h */, - 83A2249018CAC28500FE4173 /* hle.c */, - 83A2249118CAC28500FE4173 /* hle.h */, - 837841B818C847B2002C4FE5 /* audio.c */, - 837841B918C847B2002C4FE5 /* audio.h */, - 837841BC18C847B2002C4FE5 /* memory.c */, - 837841BD18C847B2002C4FE5 /* memory.h */, - 837841BE18C847B2002C4FE5 /* plugin.c */, - 8378415418C6E56B002C4FE5 /* alist.c */, - 8378415518C6E56B002C4FE5 /* alist.h */, - 8378415618C6E56B002C4FE5 /* alist_audio.c */, - 8378415818C6E56B002C4FE5 /* alist_naudio.c */, - 8378415918C6E56B002C4FE5 /* alist_nead.c */, - 8378415A18C6E56B002C4FE5 /* arithmetics.h */, - 8378415D18C6E56B002C4FE5 /* cicx105.c */, - 8378415F18C6E56B002C4FE5 /* jpeg.c */, - 8378416518C6E56B002C4FE5 /* mp3.c */, - 8378416618C6E56B002C4FE5 /* musyx.c */, - ); - path = rsp_hle; - sourceTree = ""; - }; 83C8B61818AF57770071B040 = { isa = PBXGroup; children = ( @@ -294,6 +432,7 @@ 83C8B62418AF57770071B040 /* Frameworks */ = { isa = PBXGroup; children = ( + 83CA16381A988191005E7ED4 /* libz.dylib */, 83C8B62718AF57770071B040 /* Other Frameworks */, ); name = Frameworks; @@ -309,46 +448,22 @@ 83C8B62B18AF57770071B040 /* lazyusf */ = { isa = PBXGroup; children = ( + 83CA14791A988137005E7ED4 /* ai */, + 83CA147C1A988137005E7ED4 /* api */, + 83CA14871A988138005E7ED4 /* main */, + 83CA14921A988138005E7ED4 /* memory */, + 83CA14951A988138005E7ED4 /* pi */, + 83CA149A1A988138005E7ED4 /* r4300 */, + 83CA14F21A988138005E7ED4 /* rdp */, + 83CA14F51A988138005E7ED4 /* ri */, + 83CA14FC1A988138005E7ED4 /* rsp */, + 83CA14FF1A988138005E7ED4 /* rsp_hle */, + 83CA15181A988138005E7ED4 /* rsp_lle */, + 83CA15501A988138005E7ED4 /* si */, + 83CA155B1A988138005E7ED4 /* usf */, + 83CA155F1A988138005E7ED4 /* vi */, 83CA146D1A987E91005E7ED4 /* osal */, 83CA146F1A987E91005E7ED4 /* debugger */, - 8319EF1F1A219BE7009DD5C4 /* audiolib.c */, - 8319EF201A219BE7009DD5C4 /* audiolib.h */, - 8319EF1B1A2198B9009DD5C4 /* os.c */, - 8319EF1C1A2198B9009DD5C4 /* os.h */, - 8319EF171A219846009DD5C4 /* cpu_hle.c */, - 8319EF181A219846009DD5C4 /* cpu_hle.h */, - 8378415318C6E56B002C4FE5 /* rsp_hle */, - 83C8B6FD18AF59E70071B040 /* lazyusf-Info.plist */, - 83C8B65A18AF58080071B040 /* audio.h */, - 83C8B65918AF58080071B040 /* audio.c */, - 83C8B65B18AF58080071B040 /* config.h */, - 83C8B65C18AF58080071B040 /* cpu.c */, - 83C8B65D18AF58080071B040 /* cpu.h */, - 83C8B65E18AF58080071B040 /* dma.c */, - 83C8B65F18AF58080071B040 /* dma.h */, - 83C8B66018AF58080071B040 /* exception.c */, - 83C8B66118AF58080071B040 /* exception.h */, - 83C8B66218AF58080071B040 /* interpreter_cpu.c */, - 83C8B66318AF58080071B040 /* interpreter_cpu.h */, - 83C8B66418AF58080071B040 /* interpreter_ops.c */, - 83C8B66518AF58080071B040 /* interpreter_ops.h */, - 83C8B66618AF58080071B040 /* main.c */, - 83C8B66718AF58080071B040 /* main.h */, - 83C8B66818AF58080071B040 /* memory.c */, - 83C8B66918AF58080071B040 /* memory.h */, - 83C8B66A18AF58080071B040 /* opcode.h */, - 83C8B66B18AF58080071B040 /* pif.c */, - 83C8B66C18AF58080071B040 /* pif.h */, - 83C8B66D18AF58080071B040 /* registers.c */, - 83C8B66E18AF58080071B040 /* registers.h */, - 83C8B66F18AF58080071B040 /* rsp */, - 83C8B6A418AF58080071B040 /* rsp.h */, - 83C8B6A518AF58080071B040 /* tlb.c */, - 83C8B6A618AF58080071B040 /* tlb.h */, - 83C8B6A718AF58080071B040 /* types.h */, - 83C8B6A818AF58080071B040 /* usf_internal.h */, - 83C8B6A918AF58080071B040 /* usf.c */, - 83C8B6AA18AF58080071B040 /* usf.h */, 83C8B62C18AF57770071B040 /* Supporting Files */, ); path = lazyusf; @@ -361,72 +476,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 83C8B66F18AF58080071B040 /* rsp */ = { - isa = PBXGroup; - children = ( - 83C8B67018AF58080071B040 /* config.h */, - 83C8B67118AF58080071B040 /* execute.h */, - 83C8B67218AF58080071B040 /* rsp.c */, - 83C8B67318AF58080071B040 /* rsp.h */, - 83C8B67418AF58080071B040 /* su.h */, - 83C8B67518AF58080071B040 /* vu */, - ); - path = rsp; - sourceTree = ""; - }; - 83C8B67518AF58080071B040 /* vu */ = { - isa = PBXGroup; - children = ( - 83C8B67618AF58080071B040 /* cf.h */, - 83C8B67718AF58080071B040 /* clamp.h */, - 83C8B67818AF58080071B040 /* divrom.h */, - 83C8B67918AF58080071B040 /* shuffle.h */, - 83C8B67A18AF58080071B040 /* vabs.h */, - 83C8B67B18AF58080071B040 /* vadd.h */, - 83C8B67C18AF58080071B040 /* vaddc.h */, - 83C8B67D18AF58080071B040 /* vand.h */, - 83C8B67E18AF58080071B040 /* vch.h */, - 83C8B67F18AF58080071B040 /* vcl.h */, - 83C8B68018AF58080071B040 /* vcr.h */, - 83C8B68118AF58080071B040 /* veq.h */, - 83C8B68218AF58080071B040 /* vge.h */, - 83C8B68318AF58080071B040 /* vlt.h */, - 83C8B68418AF58080071B040 /* vmacf.h */, - 83C8B68518AF58080071B040 /* vmacq.h */, - 83C8B68618AF58080071B040 /* vmacu.h */, - 83C8B68718AF58080071B040 /* vmadh.h */, - 83C8B68818AF58080071B040 /* vmadl.h */, - 83C8B68918AF58080071B040 /* vmadm.h */, - 83C8B68A18AF58080071B040 /* vmadn.h */, - 83C8B68B18AF58080071B040 /* vmov.h */, - 83C8B68C18AF58080071B040 /* vmrg.h */, - 83C8B68D18AF58080071B040 /* vmudh.h */, - 83C8B68E18AF58080071B040 /* vmudl.h */, - 83C8B68F18AF58080071B040 /* vmudm.h */, - 83C8B69018AF58080071B040 /* vmudn.h */, - 83C8B69118AF58080071B040 /* vmulf.h */, - 83C8B69218AF58080071B040 /* vmulu.h */, - 83C8B69318AF58080071B040 /* vnand.h */, - 83C8B69418AF58080071B040 /* vne.h */, - 83C8B69518AF58080071B040 /* vnop.h */, - 83C8B69618AF58080071B040 /* vnor.h */, - 83C8B69718AF58080071B040 /* vnxor.h */, - 83C8B69818AF58080071B040 /* vor.h */, - 83C8B69918AF58080071B040 /* vrcp.h */, - 83C8B69A18AF58080071B040 /* vrcph.h */, - 83C8B69B18AF58080071B040 /* vrcpl.h */, - 83C8B69C18AF58080071B040 /* vrsq.h */, - 83C8B69D18AF58080071B040 /* vrsqh.h */, - 83C8B69E18AF58080071B040 /* vrsql.h */, - 83C8B69F18AF58080071B040 /* vsaw.h */, - 83C8B6A018AF58080071B040 /* vsub.h */, - 83C8B6A118AF58080071B040 /* vsubc.h */, - 83C8B6A218AF58080071B040 /* vu.h */, - 83C8B6A318AF58080071B040 /* vxor.h */, - ); - path = vu; - sourceTree = ""; - }; 83CA146D1A987E91005E7ED4 /* osal */ = { isa = PBXGroup; children = ( @@ -446,6 +495,316 @@ path = debugger; sourceTree = ""; }; + 83CA14791A988137005E7ED4 /* ai */ = { + isa = PBXGroup; + children = ( + 83CA147A1A988137005E7ED4 /* ai_controller.c */, + 83CA147B1A988137005E7ED4 /* ai_controller.h */, + ); + path = ai; + sourceTree = ""; + }; + 83CA147C1A988137005E7ED4 /* api */ = { + isa = PBXGroup; + children = ( + 83CA147D1A988137005E7ED4 /* api_export.ver */, + 83CA147E1A988137005E7ED4 /* callbacks.c */, + 83CA147F1A988137005E7ED4 /* callbacks.h */, + 83CA14801A988137005E7ED4 /* m64p_common.h */, + 83CA14811A988137005E7ED4 /* m64p_config.h */, + 83CA14821A988137005E7ED4 /* m64p_debugger.h */, + 83CA14831A988137005E7ED4 /* m64p_frontend.h */, + 83CA14841A988138005E7ED4 /* m64p_plugin.h */, + 83CA14851A988138005E7ED4 /* m64p_types.h */, + 83CA14861A988138005E7ED4 /* m64p_vidext.h */, + ); + path = api; + sourceTree = ""; + }; + 83CA14871A988138005E7ED4 /* main */ = { + isa = PBXGroup; + children = ( + 83CA14881A988138005E7ED4 /* list.h */, + 83CA14891A988138005E7ED4 /* main.c */, + 83CA148A1A988138005E7ED4 /* main.h */, + 83CA148B1A988138005E7ED4 /* rom.c */, + 83CA148C1A988138005E7ED4 /* rom.h */, + 83CA148D1A988138005E7ED4 /* savestates.c */, + 83CA148E1A988138005E7ED4 /* savestates.h */, + 83CA148F1A988138005E7ED4 /* util.c */, + 83CA14901A988138005E7ED4 /* util.h */, + 83CA14911A988138005E7ED4 /* version.h */, + ); + path = main; + sourceTree = ""; + }; + 83CA14921A988138005E7ED4 /* memory */ = { + isa = PBXGroup; + children = ( + 83CA14931A988138005E7ED4 /* memory.c */, + 83CA14941A988138005E7ED4 /* memory.h */, + ); + path = memory; + sourceTree = ""; + }; + 83CA14951A988138005E7ED4 /* pi */ = { + isa = PBXGroup; + children = ( + 83CA14961A988138005E7ED4 /* cart_rom.c */, + 83CA14971A988138005E7ED4 /* cart_rom.h */, + 83CA14981A988138005E7ED4 /* pi_controller.c */, + 83CA14991A988138005E7ED4 /* pi_controller.h */, + ); + path = pi; + sourceTree = ""; + }; + 83CA149A1A988138005E7ED4 /* r4300 */ = { + isa = PBXGroup; + children = ( + 83CA149C1A988138005E7ED4 /* cached_interp.c */, + 83CA149D1A988138005E7ED4 /* cached_interp.h */, + 83CA149E1A988138005E7ED4 /* cp0.c */, + 83CA149F1A988138005E7ED4 /* cp0.h */, + 83CA14A01A988138005E7ED4 /* cp1.c */, + 83CA14A11A988138005E7ED4 /* cp1.h */, + 83CA14A31A988138005E7ED4 /* exception.c */, + 83CA14A41A988138005E7ED4 /* exception.h */, + 83CA14A51A988138005E7ED4 /* fpu.h */, + 83CA14A61A988138005E7ED4 /* instr_counters.c */, + 83CA14A71A988138005E7ED4 /* instr_counters.h */, + 83CA14A81A988138005E7ED4 /* interpreter.def */, + 83CA14A91A988138005E7ED4 /* interpreter_cop0.def */, + 83CA14AA1A988138005E7ED4 /* interpreter_cop1.def */, + 83CA14AB1A988138005E7ED4 /* interpreter_r4300.def */, + 83CA14AC1A988138005E7ED4 /* interpreter_regimm.def */, + 83CA14AD1A988138005E7ED4 /* interpreter_special.def */, + 83CA14AE1A988138005E7ED4 /* interpreter_tlb.def */, + 83CA14AF1A988138005E7ED4 /* interupt.c */, + 83CA14B01A988138005E7ED4 /* interupt.h */, + 83CA14B11A988138005E7ED4 /* macros.h */, + 83CA14B21A988138005E7ED4 /* mi_controller.c */, + 83CA14B31A988138005E7ED4 /* mi_controller.h */, + 83CA14BE1A988138005E7ED4 /* ops.h */, + 83CA14BF1A988138005E7ED4 /* pure_interp.c */, + 83CA14C01A988138005E7ED4 /* pure_interp.h */, + 83CA14C11A988138005E7ED4 /* r4300.c */, + 83CA14C21A988138005E7ED4 /* r4300.h */, + 83CA14C31A988138005E7ED4 /* r4300_core.c */, + 83CA14C41A988138005E7ED4 /* r4300_core.h */, + 83CA14C51A988138005E7ED4 /* recomp.c */, + 83CA14C61A988138005E7ED4 /* recomp.h */, + 83CA14C71A988138005E7ED4 /* recomph.h */, + 83CA14C81A988138005E7ED4 /* reset.c */, + 83CA14C91A988138005E7ED4 /* reset.h */, + 83CA14CA1A988138005E7ED4 /* tlb.c */, + 83CA14CB1A988138005E7ED4 /* tlb.h */, + 83CA14DF1A988138005E7ED4 /* x86_64 */, + ); + path = r4300; + sourceTree = ""; + }; + 83CA14DF1A988138005E7ED4 /* x86_64 */ = { + isa = PBXGroup; + children = ( + 83CA14E01A988138005E7ED4 /* assemble.c */, + 83CA14E11A988138005E7ED4 /* assemble.h */, + 83CA14E21A988138005E7ED4 /* assemble_struct.h */, + 83CA14E31A988138005E7ED4 /* gbc.c */, + 83CA14E41A988138005E7ED4 /* gcop0.c */, + 83CA14E51A988138005E7ED4 /* gcop1.c */, + 83CA14E61A988138005E7ED4 /* gcop1_d.c */, + 83CA14E71A988138005E7ED4 /* gcop1_l.c */, + 83CA14E81A988138005E7ED4 /* gcop1_s.c */, + 83CA14E91A988138005E7ED4 /* gcop1_w.c */, + 83CA14EA1A988138005E7ED4 /* gr4300.c */, + 83CA14EB1A988138005E7ED4 /* gregimm.c */, + 83CA14EC1A988138005E7ED4 /* gspecial.c */, + 83CA14ED1A988138005E7ED4 /* gtlb.c */, + 83CA14EE1A988138005E7ED4 /* interpret.h */, + 83CA14EF1A988138005E7ED4 /* regcache.c */, + 83CA14F01A988138005E7ED4 /* regcache.h */, + 83CA14F11A988138005E7ED4 /* rjump.c */, + ); + path = x86_64; + sourceTree = ""; + }; + 83CA14F21A988138005E7ED4 /* rdp */ = { + isa = PBXGroup; + children = ( + 83CA14F31A988138005E7ED4 /* rdp_core.c */, + 83CA14F41A988138005E7ED4 /* rdp_core.h */, + ); + path = rdp; + sourceTree = ""; + }; + 83CA14F51A988138005E7ED4 /* ri */ = { + isa = PBXGroup; + children = ( + 83CA14F61A988138005E7ED4 /* rdram.c */, + 83CA14F71A988138005E7ED4 /* rdram.h */, + 83CA14F81A988138005E7ED4 /* rdram_detection_hack.c */, + 83CA14F91A988138005E7ED4 /* rdram_detection_hack.h */, + 83CA14FA1A988138005E7ED4 /* ri_controller.c */, + 83CA14FB1A988138005E7ED4 /* ri_controller.h */, + ); + path = ri; + sourceTree = ""; + }; + 83CA14FC1A988138005E7ED4 /* rsp */ = { + isa = PBXGroup; + children = ( + 83CA14FD1A988138005E7ED4 /* rsp_core.c */, + 83CA14FE1A988138005E7ED4 /* rsp_core.h */, + ); + path = rsp; + sourceTree = ""; + }; + 83CA14FF1A988138005E7ED4 /* rsp_hle */ = { + isa = PBXGroup; + children = ( + 83CA15001A988138005E7ED4 /* alist.c */, + 83CA15011A988138005E7ED4 /* alist.h */, + 83CA15021A988138005E7ED4 /* alist_audio.c */, + 83CA15031A988138005E7ED4 /* alist_naudio.c */, + 83CA15041A988138005E7ED4 /* alist_nead.c */, + 83CA15051A988138005E7ED4 /* arithmetics.h */, + 83CA15061A988138005E7ED4 /* audio.c */, + 83CA15071A988138005E7ED4 /* audio.h */, + 83CA15081A988138005E7ED4 /* cicx105.c */, + 83CA15091A988138005E7ED4 /* common.h */, + 83CA150A1A988138005E7ED4 /* hle.c */, + 83CA150B1A988138005E7ED4 /* hle.h */, + 83CA150C1A988138005E7ED4 /* hle_external.h */, + 83CA150D1A988138005E7ED4 /* hle_internal.h */, + 83CA150E1A988138005E7ED4 /* jpeg.c */, + 83CA150F1A988138005E7ED4 /* LICENSES */, + 83CA15101A988138005E7ED4 /* memory.c */, + 83CA15111A988138005E7ED4 /* memory.h */, + 83CA15121A988138005E7ED4 /* mp3.c */, + 83CA15131A988138005E7ED4 /* msvc-compat */, + 83CA15151A988138005E7ED4 /* musyx.c */, + 83CA15161A988138005E7ED4 /* plugin.c */, + 83CA15171A988138005E7ED4 /* ucodes.h */, + ); + path = rsp_hle; + sourceTree = ""; + }; + 83CA15131A988138005E7ED4 /* msvc-compat */ = { + isa = PBXGroup; + children = ( + 83CA15141A988138005E7ED4 /* stdbool.h */, + ); + path = "msvc-compat"; + sourceTree = ""; + }; + 83CA15181A988138005E7ED4 /* rsp_lle */ = { + isa = PBXGroup; + children = ( + 83CA151A1A988138005E7ED4 /* config.h */, + 83CA151B1A988138005E7ED4 /* execute.h */, + 83CA151C1A988138005E7ED4 /* matrix.h */, + 83CA151D1A988138005E7ED4 /* rsp.c */, + 83CA151E1A988138005E7ED4 /* rsp.h */, + 83CA151F1A988138005E7ED4 /* rsp_lle.h */, + 83CA15201A988138005E7ED4 /* su.h */, + 83CA15211A988138005E7ED4 /* vu */, + ); + path = rsp_lle; + sourceTree = ""; + }; + 83CA15211A988138005E7ED4 /* vu */ = { + isa = PBXGroup; + children = ( + 83CA15221A988138005E7ED4 /* cf.h */, + 83CA15231A988138005E7ED4 /* clamp.h */, + 83CA15241A988138005E7ED4 /* divrom.h */, + 83CA15251A988138005E7ED4 /* shuffle.h */, + 83CA15261A988138005E7ED4 /* vabs.h */, + 83CA15271A988138005E7ED4 /* vadd.h */, + 83CA15281A988138005E7ED4 /* vaddc.h */, + 83CA15291A988138005E7ED4 /* vand.h */, + 83CA152A1A988138005E7ED4 /* vch.h */, + 83CA152B1A988138005E7ED4 /* vcl.h */, + 83CA152C1A988138005E7ED4 /* vcr.h */, + 83CA152D1A988138005E7ED4 /* veq.h */, + 83CA152E1A988138005E7ED4 /* vge.h */, + 83CA152F1A988138005E7ED4 /* vlt.h */, + 83CA15301A988138005E7ED4 /* vmacf.h */, + 83CA15311A988138005E7ED4 /* vmacq.h */, + 83CA15321A988138005E7ED4 /* vmacu.h */, + 83CA15331A988138005E7ED4 /* vmadh.h */, + 83CA15341A988138005E7ED4 /* vmadl.h */, + 83CA15351A988138005E7ED4 /* vmadm.h */, + 83CA15361A988138005E7ED4 /* vmadn.h */, + 83CA15371A988138005E7ED4 /* vmov.h */, + 83CA15381A988138005E7ED4 /* vmrg.h */, + 83CA15391A988138005E7ED4 /* vmudh.h */, + 83CA153A1A988138005E7ED4 /* vmudl.h */, + 83CA153B1A988138005E7ED4 /* vmudm.h */, + 83CA153C1A988138005E7ED4 /* vmudn.h */, + 83CA153D1A988138005E7ED4 /* vmulf.h */, + 83CA153E1A988138005E7ED4 /* vmulu.h */, + 83CA153F1A988138005E7ED4 /* vnand.h */, + 83CA15401A988138005E7ED4 /* vne.h */, + 83CA15411A988138005E7ED4 /* vnop.h */, + 83CA15421A988138005E7ED4 /* vnor.h */, + 83CA15431A988138005E7ED4 /* vnxor.h */, + 83CA15441A988138005E7ED4 /* vor.h */, + 83CA15451A988138005E7ED4 /* vrcp.h */, + 83CA15461A988138005E7ED4 /* vrcph.h */, + 83CA15471A988138005E7ED4 /* vrcpl.h */, + 83CA15481A988138005E7ED4 /* vrsq.h */, + 83CA15491A988138005E7ED4 /* vrsqh.h */, + 83CA154A1A988138005E7ED4 /* vrsql.h */, + 83CA154B1A988138005E7ED4 /* vsaw.h */, + 83CA154C1A988138005E7ED4 /* vsub.h */, + 83CA154D1A988138005E7ED4 /* vsubc.h */, + 83CA154E1A988138005E7ED4 /* vu.h */, + 83CA154F1A988138005E7ED4 /* vxor.h */, + ); + path = vu; + sourceTree = ""; + }; + 83CA15501A988138005E7ED4 /* si */ = { + isa = PBXGroup; + children = ( + 83CA15511A988138005E7ED4 /* cic.c */, + 83CA15521A988138005E7ED4 /* cic.h */, + 83CA15531A988138005E7ED4 /* game_controller.c */, + 83CA15541A988138005E7ED4 /* game_controller.h */, + 83CA15551A988138005E7ED4 /* n64_cic_nus_6105.c */, + 83CA15561A988138005E7ED4 /* n64_cic_nus_6105.h */, + 83CA15571A988138005E7ED4 /* pif.c */, + 83CA15581A988138005E7ED4 /* pif.h */, + 83CA15591A988138005E7ED4 /* si_controller.c */, + 83CA155A1A988138005E7ED4 /* si_controller.h */, + ); + path = si; + sourceTree = ""; + }; + 83CA155B1A988138005E7ED4 /* usf */ = { + isa = PBXGroup; + children = ( + 8379B5881AA4237E00F28A95 /* barray.c */, + 8379B5891AA4237E00F28A95 /* barray.h */, + 83C0787A1A9B544300ABBB67 /* resampler.c */, + 83C0787B1A9B544300ABBB67 /* resampler.h */, + 83CA155C1A988138005E7ED4 /* usf.c */, + 83CA155D1A988138005E7ED4 /* usf.h */, + 83CA155E1A988138005E7ED4 /* usf_internal.h */, + ); + path = usf; + sourceTree = ""; + }; + 83CA155F1A988138005E7ED4 /* vi */ = { + isa = PBXGroup; + children = ( + 83CA15601A988138005E7ED4 /* vi_controller.c */, + 83CA15611A988138005E7ED4 /* vi_controller.h */, + ); + path = vi; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -453,88 +812,125 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 83C8B6FA18AF58090071B040 /* usf.h in Headers */, - 83C8B6AC18AF58080071B040 /* audio.h in Headers */, - 837841C118C847B2002C4FE5 /* audio.h in Headers */, - 83C8B6B118AF58080071B040 /* dma.h in Headers */, + 83CA16341A988138005E7ED4 /* usf.h in Headers */, + 83CA16281A988138005E7ED4 /* vxor.h in Headers */, + 83CA161F1A988138005E7ED4 /* vrcph.h in Headers */, + 83CA16091A988138005E7ED4 /* vmacf.h in Headers */, + 83CA15A21A988138005E7ED4 /* pure_interp.h in Headers */, + 83CA15881A988138005E7ED4 /* fpu.h in Headers */, + 83CA16161A988138005E7ED4 /* vmulf.h in Headers */, + 83CA16021A988138005E7ED4 /* vand.h in Headers */, + 83CA16041A988138005E7ED4 /* vcl.h in Headers */, + 83CA15AB1A988138005E7ED4 /* reset.h in Headers */, + 83CA15AD1A988138005E7ED4 /* tlb.h in Headers */, + 83CA15761A988138005E7ED4 /* util.h in Headers */, + 83CA15DB1A988138005E7ED4 /* rsp_core.h in Headers */, + 83CA15F21A988138005E7ED4 /* ucodes.h in Headers */, + 83CA15701A988138005E7ED4 /* main.h in Headers */, + 83CA15F41A988138005E7ED4 /* config.h in Headers */, + 83CA15A41A988138005E7ED4 /* r4300.h in Headers */, + 83CA15D51A988138005E7ED4 /* rdram.h in Headers */, + 83CA15D31A988138005E7ED4 /* rdp_core.h in Headers */, + 83CA162C1A988138005E7ED4 /* game_controller.h in Headers */, + 83CA15ED1A988138005E7ED4 /* memory.h in Headers */, + 83CA16191A988138005E7ED4 /* vne.h in Headers */, + 83CA162E1A988138005E7ED4 /* n64_cic_nus_6105.h in Headers */, + 83CA156E1A988138005E7ED4 /* list.h in Headers */, + 83CA157D1A988138005E7ED4 /* pi_controller.h in Headers */, + 83CA15FF1A988138005E7ED4 /* vabs.h in Headers */, + 83CA15E31A988138005E7ED4 /* audio.h in Headers */, + 83CA160E1A988138005E7ED4 /* vmadm.h in Headers */, + 83C0787D1A9B544300ABBB67 /* resampler.h in Headers */, + 83CA16051A988138005E7ED4 /* vcr.h in Headers */, + 83CA15691A988138005E7ED4 /* m64p_debugger.h in Headers */, + 83CA15F81A988138005E7ED4 /* rsp.h in Headers */, + 83CA160A1A988138005E7ED4 /* vmacq.h in Headers */, + 83CA160B1A988138005E7ED4 /* vmacu.h in Headers */, + 83CA156A1A988138005E7ED4 /* m64p_frontend.h in Headers */, + 83CA15F61A988138005E7ED4 /* matrix.h in Headers */, + 83CA16171A988138005E7ED4 /* vmulu.h in Headers */, + 83CA15A81A988138005E7ED4 /* recomp.h in Headers */, + 83CA15821A988138005E7ED4 /* cp0.h in Headers */, + 83CA16111A988138005E7ED4 /* vmrg.h in Headers */, + 83CA15741A988138005E7ED4 /* savestates.h in Headers */, + 83CA15FE1A988138005E7ED4 /* shuffle.h in Headers */, + 83CA15FA1A988138005E7ED4 /* su.h in Headers */, + 83CA15931A988138005E7ED4 /* interupt.h in Headers */, + 83CA15F91A988138005E7ED4 /* rsp_lle.h in Headers */, + 83CA16061A988138005E7ED4 /* veq.h in Headers */, + 83CA16141A988138005E7ED4 /* vmudm.h in Headers */, 83CA14781A987E91005E7ED4 /* dbg_types.h in Headers */, - 83A2249518CAC28500FE4173 /* hle.h in Headers */, - 83C8B6AD18AF58080071B040 /* config.h in Headers */, - 83A2249318CAC28500FE4173 /* hle_internal.h in Headers */, - 83C8B6B518AF58080071B040 /* interpreter_cpu.h in Headers */, - 83C8B6B918AF58080071B040 /* main.h in Headers */, - 83C8B6F418AF58090071B040 /* rsp.h in Headers */, - 8378417018C6E56B002C4FE5 /* arithmetics.h in Headers */, - 8319EF221A219BE7009DD5C4 /* audiolib.h in Headers */, - 83C8B6C018AF58080071B040 /* registers.h in Headers */, + 83CA16011A988138005E7ED4 /* vaddc.h in Headers */, + 83CA16251A988138005E7ED4 /* vsub.h in Headers */, + 83CA15C11A988138005E7ED4 /* assemble.h in Headers */, + 83CA161C1A988138005E7ED4 /* vnxor.h in Headers */, + 83CA16321A988138005E7ED4 /* si_controller.h in Headers */, + 83CA15E71A988138005E7ED4 /* hle.h in Headers */, + 83CA15941A988138005E7ED4 /* macros.h in Headers */, + 83CA15791A988138005E7ED4 /* memory.h in Headers */, + 83CA16231A988138005E7ED4 /* vrsql.h in Headers */, + 83CA161D1A988138005E7ED4 /* vor.h in Headers */, + 83CA15671A988138005E7ED4 /* m64p_common.h in Headers */, + 83CA15E11A988138005E7ED4 /* arithmetics.h in Headers */, + 83CA16351A988138005E7ED4 /* usf_internal.h in Headers */, + 83CA15A01A988138005E7ED4 /* ops.h in Headers */, + 83CA162A1A988138005E7ED4 /* cic.h in Headers */, + 83CA16071A988138005E7ED4 /* vge.h in Headers */, + 83CA15E91A988138005E7ED4 /* hle_internal.h in Headers */, + 83CA16301A988138005E7ED4 /* pif.h in Headers */, + 83CA16221A988138005E7ED4 /* vrsqh.h in Headers */, + 83CA15841A988138005E7ED4 /* cp1.h in Headers */, + 83CA16241A988138005E7ED4 /* vsaw.h in Headers */, + 83CA15871A988138005E7ED4 /* exception.h in Headers */, + 83CA15661A988138005E7ED4 /* callbacks.h in Headers */, + 83CA15631A988138005E7ED4 /* ai_controller.h in Headers */, + 83CA15961A988138005E7ED4 /* mi_controller.h in Headers */, + 83CA15D71A988138005E7ED4 /* rdram_detection_hack.h in Headers */, + 83CA15FC1A988138005E7ED4 /* clamp.h in Headers */, + 83CA161A1A988138005E7ED4 /* vnop.h in Headers */, + 83CA161B1A988138005E7ED4 /* vnor.h in Headers */, + 83CA15E81A988138005E7ED4 /* hle_external.h in Headers */, + 83CA15801A988138005E7ED4 /* cached_interp.h in Headers */, + 83CA16261A988138005E7ED4 /* vsubc.h in Headers */, + 83CA15FD1A988138005E7ED4 /* divrom.h in Headers */, + 83CA15D91A988138005E7ED4 /* ri_controller.h in Headers */, 83CA14741A987E91005E7ED4 /* preproc.h in Headers */, - 83C8B6BE18AF58080071B040 /* pif.h in Headers */, - 83C8B6F618AF58090071B040 /* tlb.h in Headers */, - 83C8B6F718AF58090071B040 /* types.h in Headers */, - 83C8B6BB18AF58080071B040 /* memory.h in Headers */, - 8319EF1E1A2198B9009DD5C4 /* os.h in Headers */, - 83C8B6BC18AF58080071B040 /* opcode.h in Headers */, - 83C8B6B718AF58080071B040 /* interpreter_ops.h in Headers */, + 83CA15721A988138005E7ED4 /* rom.h in Headers */, + 83CA160C1A988138005E7ED4 /* vmadh.h in Headers */, + 83CA16001A988138005E7ED4 /* vadd.h in Headers */, + 83CA16131A988138005E7ED4 /* vmudl.h in Headers */, + 83CA16211A988138005E7ED4 /* vrsq.h in Headers */, 83CA14761A987E91005E7ED4 /* dbg_decoder.h in Headers */, - 83C8B6B318AF58080071B040 /* exception.h in Headers */, - 83C8B6AF18AF58080071B040 /* cpu.h in Headers */, - 83C8B6F118AF58090071B040 /* vsubc.h in Headers */, - 83C8B6F018AF58090071B040 /* vsub.h in Headers */, - 83C8B6E018AF58080071B040 /* vmudn.h in Headers */, - 83C8B6EF18AF58090071B040 /* vsaw.h in Headers */, - 83C8B6C918AF58080071B040 /* shuffle.h in Headers */, - 83C8B6DD18AF58080071B040 /* vmudh.h in Headers */, - 83C8B6E118AF58080071B040 /* vmulf.h in Headers */, - 83C8B6CE18AF58080071B040 /* vch.h in Headers */, - 83C8B6CB18AF58080071B040 /* vadd.h in Headers */, - 83C8B6D618AF58080071B040 /* vmacu.h in Headers */, - 83C8B6C618AF58080071B040 /* cf.h in Headers */, - 83C8B6E818AF58080071B040 /* vor.h in Headers */, - 83C8B6D918AF58080071B040 /* vmadm.h in Headers */, - 83C8B6E318AF58080071B040 /* vnand.h in Headers */, - 83C8B6D218AF58080071B040 /* vge.h in Headers */, - 83C8B6C518AF58080071B040 /* su.h in Headers */, - 83C8B6C218AF58080071B040 /* execute.h in Headers */, + 83CA16371A988138005E7ED4 /* vi_controller.h in Headers */, + 83CA158A1A988138005E7ED4 /* instr_counters.h in Headers */, 83CA14771A987E91005E7ED4 /* dbg_decoder_local.h in Headers */, - 83C8B6E518AF58080071B040 /* vnop.h in Headers */, - 83C8B6E418AF58080071B040 /* vne.h in Headers */, - 83C8B6D418AF58080071B040 /* vmacf.h in Headers */, - 83C8B6DC18AF58080071B040 /* vmrg.h in Headers */, - 83C8B6C718AF58080071B040 /* clamp.h in Headers */, - 83A2249218CAC28500FE4173 /* hle_external.h in Headers */, - 83C8B6D718AF58080071B040 /* vmadh.h in Headers */, - 83C8B6F318AF58090071B040 /* vxor.h in Headers */, - 83C8B6EC18AF58090071B040 /* vrsq.h in Headers */, - 837841C518C847B2002C4FE5 /* memory.h in Headers */, - 83C8B6D018AF58080071B040 /* vcr.h in Headers */, - 8378416B18C6E56B002C4FE5 /* alist.h in Headers */, - 83C8B6EA18AF58090071B040 /* vrcph.h in Headers */, - 83C8B6F818AF58090071B040 /* usf_internal.h in Headers */, - 83C8B6EE18AF58090071B040 /* vrsql.h in Headers */, - 83C8B6D118AF58080071B040 /* veq.h in Headers */, - 83C8B6CA18AF58080071B040 /* vabs.h in Headers */, - 83C8B6DB18AF58080071B040 /* vmov.h in Headers */, - 83C8B6ED18AF58090071B040 /* vrsqh.h in Headers */, - 83C8B6E618AF58080071B040 /* vnor.h in Headers */, - 83C8B6DE18AF58080071B040 /* vmudl.h in Headers */, - 83C8B6DA18AF58080071B040 /* vmadn.h in Headers */, - 83C8B6E218AF58080071B040 /* vmulu.h in Headers */, - 83C8B6CC18AF58080071B040 /* vaddc.h in Headers */, - 83FBECBA18ECE86B00311448 /* ucodes.h in Headers */, - 83C8B6D518AF58080071B040 /* vmacq.h in Headers */, - 83C8B6C418AF58080071B040 /* rsp.h in Headers */, - 83C8B6E918AF58080071B040 /* vrcp.h in Headers */, - 83C8B6D318AF58080071B040 /* vlt.h in Headers */, - 83C8B6C118AF58080071B040 /* config.h in Headers */, - 8319EF1A1A219846009DD5C4 /* cpu_hle.h in Headers */, - 83C8B6DF18AF58080071B040 /* vmudm.h in Headers */, - 83C8B6D818AF58080071B040 /* vmadl.h in Headers */, - 83C8B6EB18AF58090071B040 /* vrcpl.h in Headers */, - 83C8B6CD18AF58080071B040 /* vand.h in Headers */, - 83C8B6CF18AF58080071B040 /* vcl.h in Headers */, - 83C8B6E718AF58080071B040 /* vnxor.h in Headers */, - 83C8B6C818AF58080071B040 /* divrom.h in Headers */, - 83C8B6F218AF58090071B040 /* vu.h in Headers */, + 83CA15C21A988138005E7ED4 /* assemble_struct.h in Headers */, + 83CA15E51A988138005E7ED4 /* common.h in Headers */, + 83CA15FB1A988138005E7ED4 /* cf.h in Headers */, + 83CA16271A988138005E7ED4 /* vu.h in Headers */, + 83CA160D1A988138005E7ED4 /* vmadl.h in Headers */, + 8379B58B1AA4237E00F28A95 /* barray.h in Headers */, + 83CA157B1A988138005E7ED4 /* cart_rom.h in Headers */, + 83CA161E1A988138005E7ED4 /* vrcp.h in Headers */, + 83CA156D1A988138005E7ED4 /* m64p_vidext.h in Headers */, + 83CA15A61A988138005E7ED4 /* r4300_core.h in Headers */, + 83CA16151A988138005E7ED4 /* vmudn.h in Headers */, + 83CA16181A988138005E7ED4 /* vnand.h in Headers */, + 83CA16121A988138005E7ED4 /* vmudh.h in Headers */, + 83CA156C1A988138005E7ED4 /* m64p_types.h in Headers */, + 83CA15D01A988138005E7ED4 /* regcache.h in Headers */, + 83CA16081A988138005E7ED4 /* vlt.h in Headers */, + 83CA15DD1A988138005E7ED4 /* alist.h in Headers */, + 83CA15771A988138005E7ED4 /* version.h in Headers */, + 83CA15A91A988138005E7ED4 /* recomph.h in Headers */, + 83CA15681A988138005E7ED4 /* m64p_config.h in Headers */, + 83CA16031A988138005E7ED4 /* vch.h in Headers */, + 83CA156B1A988138005E7ED4 /* m64p_plugin.h in Headers */, + 83CA15F51A988138005E7ED4 /* execute.h in Headers */, + 83CA15CE1A988138005E7ED4 /* interpret.h in Headers */, + 83CA16201A988138005E7ED4 /* vrcpl.h in Headers */, + 83CA16101A988138005E7ED4 /* vmov.h in Headers */, + 83CA160F1A988138005E7ED4 /* vmadn.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -590,6 +986,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 83CA15911A988138005E7ED4 /* interpreter_tlb.def in Resources */, + 83CA15901A988138005E7ED4 /* interpreter_special.def in Resources */, + 83CA15641A988138005E7ED4 /* api_export.ver in Resources */, + 83CA158C1A988138005E7ED4 /* interpreter_cop0.def in Resources */, + 83CA158F1A988138005E7ED4 /* interpreter_regimm.def in Resources */, + 83CA158D1A988138005E7ED4 /* interpreter_cop1.def in Resources */, + 83CA158E1A988138005E7ED4 /* interpreter_r4300.def in Resources */, + 83CA15EB1A988138005E7ED4 /* LICENSES in Resources */, + 83CA158B1A988138005E7ED4 /* interpreter.def in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -600,35 +1005,70 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 837841C618C847B2002C4FE5 /* plugin.c in Sources */, - 83C8B6F518AF58090071B040 /* tlb.c in Sources */, - 83C8B6C318AF58080071B040 /* rsp.c in Sources */, - 83C8B6BD18AF58080071B040 /* pif.c in Sources */, - 83C8B6B418AF58080071B040 /* interpreter_cpu.c in Sources */, - 837841C018C847B2002C4FE5 /* audio.c in Sources */, - 8378417518C6E56B002C4FE5 /* jpeg.c in Sources */, - 8378417C18C6E56B002C4FE5 /* musyx.c in Sources */, - 8378417B18C6E56B002C4FE5 /* mp3.c in Sources */, - 8378416F18C6E56B002C4FE5 /* alist_nead.c in Sources */, - 837841C418C847B2002C4FE5 /* memory.c in Sources */, - 83C8B6B618AF58080071B040 /* interpreter_ops.c in Sources */, - 8378416C18C6E56B002C4FE5 /* alist_audio.c in Sources */, - 83C8B6BA18AF58080071B040 /* memory.c in Sources */, - 83C8B6B018AF58080071B040 /* dma.c in Sources */, - 8378417318C6E56B002C4FE5 /* cicx105.c in Sources */, - 8378416A18C6E56B002C4FE5 /* alist.c in Sources */, - 83C8B6AE18AF58080071B040 /* cpu.c in Sources */, - 83C8B6AB18AF58080071B040 /* audio.c in Sources */, + 83CA15F71A988138005E7ED4 /* rsp.c in Sources */, + 83CA15F11A988138005E7ED4 /* plugin.c in Sources */, + 83CA15CD1A988138005E7ED4 /* gtlb.c in Sources */, + 83CA15DF1A988138005E7ED4 /* alist_naudio.c in Sources */, + 83CA15731A988138005E7ED4 /* savestates.c in Sources */, + 83CA15EA1A988138005E7ED4 /* jpeg.c in Sources */, + 83C0787C1A9B544300ABBB67 /* resampler.c in Sources */, + 83CA16361A988138005E7ED4 /* vi_controller.c in Sources */, + 83CA156F1A988138005E7ED4 /* main.c in Sources */, + 83CA15AA1A988138005E7ED4 /* reset.c in Sources */, + 83CA16311A988138005E7ED4 /* si_controller.c in Sources */, + 83CA15A71A988138005E7ED4 /* recomp.c in Sources */, + 83CA15F01A988138005E7ED4 /* musyx.c in Sources */, + 83CA15E61A988138005E7ED4 /* hle.c in Sources */, + 83CA15C71A988138005E7ED4 /* gcop1_l.c in Sources */, + 83CA15CC1A988138005E7ED4 /* gspecial.c in Sources */, + 83CA15DE1A988138005E7ED4 /* alist_audio.c in Sources */, + 83CA15D81A988138005E7ED4 /* ri_controller.c in Sources */, + 83CA15861A988138005E7ED4 /* exception.c in Sources */, + 83CA15891A988138005E7ED4 /* instr_counters.c in Sources */, + 83CA15C61A988138005E7ED4 /* gcop1_d.c in Sources */, + 83CA16291A988138005E7ED4 /* cic.c in Sources */, + 83CA15A11A988138005E7ED4 /* pure_interp.c in Sources */, + 83CA15CB1A988138005E7ED4 /* gregimm.c in Sources */, + 83CA15E21A988138005E7ED4 /* audio.c in Sources */, + 83CA15781A988138005E7ED4 /* memory.c in Sources */, + 8379B58A1AA4237E00F28A95 /* barray.c in Sources */, + 83CA15CF1A988138005E7ED4 /* regcache.c in Sources */, + 83CA15751A988138005E7ED4 /* util.c in Sources */, + 83CA162B1A988138005E7ED4 /* game_controller.c in Sources */, + 83CA15A31A988138005E7ED4 /* r4300.c in Sources */, + 83CA15921A988138005E7ED4 /* interupt.c in Sources */, + 83CA15C81A988138005E7ED4 /* gcop1_s.c in Sources */, 83CA14751A987E91005E7ED4 /* dbg_decoder.c in Sources */, - 83A2249418CAC28500FE4173 /* hle.c in Sources */, - 8319EF191A219846009DD5C4 /* cpu_hle.c in Sources */, - 8319EF1D1A2198B9009DD5C4 /* os.c in Sources */, - 8378416E18C6E56B002C4FE5 /* alist_naudio.c in Sources */, - 83C8B6B218AF58080071B040 /* exception.c in Sources */, - 8319EF211A219BE7009DD5C4 /* audiolib.c in Sources */, - 83C8B6BF18AF58080071B040 /* registers.c in Sources */, - 83C8B6F918AF58090071B040 /* usf.c in Sources */, - 83C8B6B818AF58080071B040 /* main.c in Sources */, + 83CA15C51A988138005E7ED4 /* gcop1.c in Sources */, + 83CA15C31A988138005E7ED4 /* gbc.c in Sources */, + 83CA15C41A988138005E7ED4 /* gcop0.c in Sources */, + 83CA15711A988138005E7ED4 /* rom.c in Sources */, + 83CA15651A988138005E7ED4 /* callbacks.c in Sources */, + 83CA15E41A988138005E7ED4 /* cicx105.c in Sources */, + 83CA15EE1A988138005E7ED4 /* mp3.c in Sources */, + 83CA15831A988138005E7ED4 /* cp1.c in Sources */, + 83CA15DA1A988138005E7ED4 /* rsp_core.c in Sources */, + 83CA15A51A988138005E7ED4 /* r4300_core.c in Sources */, + 83CA15C91A988138005E7ED4 /* gcop1_w.c in Sources */, + 83CA15D61A988138005E7ED4 /* rdram_detection_hack.c in Sources */, + 83CA15D11A988138005E7ED4 /* rjump.c in Sources */, + 83CA162F1A988138005E7ED4 /* pif.c in Sources */, + 83CA15CA1A988138005E7ED4 /* gr4300.c in Sources */, + 83CA15621A988138005E7ED4 /* ai_controller.c in Sources */, + 83CA162D1A988138005E7ED4 /* n64_cic_nus_6105.c in Sources */, + 83CA15D41A988138005E7ED4 /* rdram.c in Sources */, + 83CA15C01A988138005E7ED4 /* assemble.c in Sources */, + 83CA15D21A988138005E7ED4 /* rdp_core.c in Sources */, + 83CA15E01A988138005E7ED4 /* alist_nead.c in Sources */, + 83CA157C1A988138005E7ED4 /* pi_controller.c in Sources */, + 83CA15EC1A988138005E7ED4 /* memory.c in Sources */, + 83CA15AC1A988138005E7ED4 /* tlb.c in Sources */, + 83CA15DC1A988138005E7ED4 /* alist.c in Sources */, + 83CA15811A988138005E7ED4 /* cp0.c in Sources */, + 83CA157A1A988138005E7ED4 /* cart_rom.c in Sources */, + 83CA16331A988138005E7ED4 /* usf.c in Sources */, + 83CA157F1A988138005E7ED4 /* cached_interp.c in Sources */, + 83CA15951A988138005E7ED4 /* mi_controller.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -712,8 +1152,8 @@ FRAMEWORK_VERSION = A; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", - DEBUG_INFO, ARCH_MIN_SSE2, + DYNAREC, ); GCC_WARN_PEDANTIC = YES; INFOPLIST_FILE = "lazyusf/lazyusf-Info.plist"; @@ -736,6 +1176,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherit)", ARCH_MIN_SSE2, + DYNAREC, ); GCC_WARN_PEDANTIC = YES; INFOPLIST_FILE = "lazyusf/lazyusf-Info.plist"; diff --git a/Frameworks/lazyusf/lazyusf/ai/ai_controller.c b/Frameworks/lazyusf/lazyusf/ai/ai_controller.c new file mode 100644 index 000000000..22d590867 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ai/ai_controller.c @@ -0,0 +1,240 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - ai_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "ai_controller.h" + +#include "main/rom.h" +#include "memory/memory.h" +#include "r4300/cp0.h" +#include "r4300/r4300_core.h" +#include "r4300/interupt.h" +#include "ri/ri_controller.h" +#include "vi/vi_controller.h" + +#include + +/* Clang complains that 0x80000000 is too large for enumerators, which it says must be 'int' */ +static const uint32_t AI_STATUS_BUSY = 0x40000000; +static const uint32_t AI_STATUS_FULL = 0x80000000; + + +static uint32_t get_remaining_dma_length(struct ai_controller* ai) +{ + unsigned int next_ai_event; + unsigned int remaining_dma_duration; + + if (ai->fifo[0].duration == 0) + return 0; + + update_count(ai->r4300->state); + next_ai_event = get_event(ai->r4300->state, AI_INT); + if (next_ai_event == 0) + return 0; + + remaining_dma_duration = next_ai_event - ai->r4300->state->g_cp0_regs[CP0_COUNT_REG]; + + if (remaining_dma_duration >= 0x80000000) + return 0; + + return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration); +} + +static unsigned int get_dma_duration(struct ai_controller* ai) +{ + unsigned int samples_per_sec = ai->r4300->state->ROM_PARAMS.aidacrate / (1 + ai->regs[AI_DACRATE_REG]); + + return (uint32_t)(((uint64_t)ai->regs[AI_LEN_REG]*ai->vi->delay*ai->r4300->state->ROM_PARAMS.vilimit) + / (4 * samples_per_sec)); +} + + +static void do_dma(struct ai_controller* ai, const struct ai_dma* dma) +{ +#ifdef DEBUG_INFO + fprintf(ai->r4300->state->debug_log, "Audio DMA push: %d %d\n", dma->address, dma->length); +#endif + + /* lazy initialization of sample format */ + if (ai->samples_format_changed) + { + unsigned int frequency = (ai->regs[AI_DACRATE_REG] == 0) + ? 44100 + : ai->r4300->state->ROM_PARAMS.aidacrate / (1 + ai->regs[AI_DACRATE_REG]); + + unsigned int bits = (ai->regs[AI_BITRATE_REG] == 0) + ? 16 + : 1 + ai->regs[AI_BITRATE_REG]; + + set_audio_format(ai, frequency, bits); + + ai->samples_format_changed = 0; + } + + /* push audio samples to external sink */ + push_audio_samples(ai, &ai->ri->rdram.dram[dma->address/4], dma->length); + + /* schedule end of dma event */ + update_count(ai->r4300->state); + if (!(ai->regs[AI_STATUS_REG] & AI_STATUS_FULL)) + { + remove_event(ai->r4300->state, AI_INT); + add_interupt_event(ai->r4300->state, AI_INT, ai->r4300->state->g_delay_ai ? dma->duration : 0); + } +} + +void ai_fifo_queue_int(struct ai_controller* ai) +{ + add_interupt_event(ai->r4300->state, AI_INT, ai->r4300->state->g_delay_ai ? get_dma_duration(ai) : 0); +} + +static void fifo_push(struct ai_controller* ai) +{ + unsigned int duration = get_dma_duration(ai); + + if (ai->regs[AI_STATUS_REG] & AI_STATUS_BUSY) + { + ai->fifo[1].address = ai->regs[AI_DRAM_ADDR_REG]; + ai->fifo[1].length = ai->regs[AI_LEN_REG]; + ai->fifo[1].duration = duration; + + if (ai->r4300->state->enableFIFOfull) + ai->regs[AI_STATUS_REG] |= AI_STATUS_FULL; + else + do_dma(ai, &ai->fifo[1]); + } + else + { + ai->fifo[0].address = ai->regs[AI_DRAM_ADDR_REG]; + ai->fifo[0].length = ai->regs[AI_LEN_REG]; + ai->fifo[0].duration = duration; + ai->regs[AI_STATUS_REG] |= AI_STATUS_BUSY; + + do_dma(ai, &ai->fifo[0]); + } +} + +static void fifo_pop(struct ai_controller* ai) +{ + if (ai->regs[AI_STATUS_REG] & AI_STATUS_FULL) + { + ai->fifo[0].address = ai->fifo[1].address; + ai->fifo[0].length = ai->fifo[1].length; + ai->fifo[0].duration = ai->fifo[1].duration; + ai->regs[AI_STATUS_REG] &= ~AI_STATUS_FULL; + + do_dma(ai, &ai->fifo[0]); + } + else + { + ai->regs[AI_STATUS_REG] &= ~AI_STATUS_BUSY; + } +} + + +void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits) +{ + ai->set_audio_format(ai->user_data, frequency, bits); +} + +void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size) +{ + ai->push_audio_samples(ai->user_data, buffer, size); +} + + +void connect_ai(struct ai_controller* ai, + struct r4300_core* r4300, + struct ri_controller* ri, + struct vi_controller* vi) +{ + ai->r4300 = r4300; + ai->ri = ri; + ai->vi = vi; +} + +void init_ai(struct ai_controller* ai) +{ + memset(ai->regs, 0, AI_REGS_COUNT*sizeof(uint32_t)); + memset(ai->fifo, 0, 2*sizeof(struct ai_dma)); + ai->samples_format_changed = 0; +} + + +int read_ai_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct ai_controller* ai = (struct ai_controller*)opaque; + uint32_t reg = ai_reg(address); + + if (reg == AI_LEN_REG) + { + *value = get_remaining_dma_length(ai); + } + else + { + *value = ai->regs[reg]; + } + + return 0; +} + +int write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct ai_controller* ai = (struct ai_controller*)opaque; + uint32_t reg = ai_reg(address); + + switch (reg) + { + case AI_LEN_REG: + masked_write(&ai->regs[AI_LEN_REG], value, mask); + fifo_push(ai); + return 0; + + case AI_STATUS_REG: + clear_rcp_interrupt(ai->r4300, MI_INTR_AI); + ai->r4300->mi.AudioIntrReg &= ~MI_INTR_AI; + return 0; + + case AI_BITRATE_REG: + case AI_DACRATE_REG: + /* lazy audio format setting */ + if ((ai->regs[reg]) != (value & mask)) + ai->samples_format_changed = 1; + + masked_write(&ai->regs[reg], value, mask); + return 0; + } + + masked_write(&ai->regs[reg], value, mask); + + return 0; +} + +void ai_end_of_dma_event(struct ai_controller* ai) +{ + fifo_pop(ai); + ai->r4300->mi.AudioIntrReg |= MI_INTR_AI; + raise_rcp_interrupt(ai->r4300, MI_INTR_AI); +} + diff --git a/Frameworks/lazyusf/lazyusf/ai/ai_controller.h b/Frameworks/lazyusf/lazyusf/ai/ai_controller.h new file mode 100644 index 000000000..3034c2184 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ai/ai_controller.h @@ -0,0 +1,91 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - ai_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_AI_AI_CONTROLLER_H +#define M64P_AI_AI_CONTROLLER_H + +#include +#include + +#include "osal/preproc.h" + +struct r4300_core; +struct ri_controller; +struct vi_controller; + +enum ai_registers +{ + AI_DRAM_ADDR_REG, + AI_LEN_REG, + AI_CONTROL_REG, + AI_STATUS_REG, + AI_DACRATE_REG, + AI_BITRATE_REG, + AI_REGS_COUNT +}; + +struct ai_dma +{ + uint32_t address; + uint32_t length; + unsigned int duration; +}; + +struct ai_controller +{ + uint32_t regs[AI_REGS_COUNT]; + struct ai_dma fifo[2]; + unsigned int samples_format_changed; + + /* external speaker output */ + void* user_data; + void (*set_audio_format)(void*,unsigned int, unsigned int); + void (*push_audio_samples)(void*,const void*,size_t); + + struct r4300_core* r4300; + struct ri_controller* ri; + struct vi_controller* vi; +}; + +static osal_inline uint32_t ai_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +/* This is for enablefifofull */ +void ai_fifo_queue_int(struct ai_controller* ai); + +void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits); +void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size); + +void connect_ai(struct ai_controller* ai, + struct r4300_core* r4300, + struct ri_controller* ri, + struct vi_controller* vi); + +void init_ai(struct ai_controller* ai); + +int read_ai_regs(void* opaque, uint32_t address, uint32_t* value); +int write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void ai_end_of_dma_event(struct ai_controller* ai); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/api/api_export.ver b/Frameworks/lazyusf/lazyusf/api/api_export.ver new file mode 100644 index 000000000..479d1797f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/api_export.ver @@ -0,0 +1,70 @@ +{ global: +ConfigDeleteSection; +ConfigGetParamBool; +ConfigGetParameter; +ConfigGetParameterHelp; +ConfigGetParameterType; +ConfigGetParamFloat; +ConfigGetParamInt; +ConfigGetParamString; +ConfigGetSharedDataFilepath; +ConfigGetUserCachePath; +ConfigGetUserConfigPath; +ConfigGetUserDataPath; +ConfigHasUnsavedChanges; +ConfigListParameters; +ConfigListSections; +ConfigOpenSection; +ConfigRevertChanges; +ConfigSaveFile; +ConfigSaveSection; +ConfigSetDefaultBool; +ConfigSetDefaultFloat; +ConfigSetDefaultInt; +ConfigSetDefaultString; +ConfigSetParameter; +ConfigSetParameterHelp; +CoreAddCheat; +CoreAttachPlugin; +CoreCheatEnabled; +CoreDetachPlugin; +CoreDoCommand; +CoreErrorMessage; +CoreGetAPIVersions; +CoreGetRomSettings; +CoreOverrideVidExt; +CoreShutdown; +CoreStartup; +DebugBreakpointCommand; +DebugBreakpointLookup; +DebugDecodeOp; +DebugGetCPUDataPtr; +DebugGetState; +DebugMemGetMemInfo; +DebugMemGetPointer; +DebugMemGetRecompInfo; +DebugMemRead16; +DebugMemRead32; +DebugMemRead64; +DebugMemRead8; +DebugMemWrite16; +DebugMemWrite32; +DebugMemWrite64; +DebugMemWrite8; +DebugSetCallbacks; +DebugSetCoreCompare; +DebugSetRunState; +DebugStep; +PluginGetVersion; +VidExt_GL_GetProcAddress; +VidExt_GL_SetAttribute; +VidExt_GL_GetAttribute; +VidExt_GL_SwapBuffers; +VidExt_Init; +VidExt_ListFullscreenModes; +VidExt_Quit; +VidExt_SetCaption; +VidExt_SetVideoMode; +VidExt_ToggleFullScreen; +VidExt_ResizeWindow; +local: *; }; diff --git a/Frameworks/lazyusf/lazyusf/api/callbacks.c b/Frameworks/lazyusf/lazyusf/api/callbacks.c new file mode 100644 index 000000000..5712b2483 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/callbacks.c @@ -0,0 +1,77 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - api/callbacks.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This file contains the Core functions for handling callbacks to the + * front-end application + */ + +#include +#include +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "m64p_types.h" +#include "callbacks.h" + +void DebugMessage(usf_state_t * state, int level, const char *message, ...) +{ + va_list args; + size_t len; + + if ( +#ifdef DEBUG_INFO + 1 || +#endif + level > 1 ) + { +#ifdef DEBUG_INFO + char buffer[1024]; + va_start(args, message); + vsprintf(buffer, message, args); + va_end(args); + fprintf(state->debug_log, "%s\n", buffer); + if ( level > 1 ) +#endif + return; + } + + len = strlen( state->error_message ); + + if ( len ) + state->error_message[ len++ ] = '\n'; + + va_start(args, message); +#if _MSC_VER >= 1300 + vsprintf_s(state->error_message + len, 16384 - len, message, args); +#else + vsprintf(state->error_message + len, message, args); +#endif + va_end(args); + + state->last_error = state->error_message; + state->stop = 1; +} + + diff --git a/Frameworks/lazyusf/lazyusf/api/callbacks.h b/Frameworks/lazyusf/lazyusf/api/callbacks.h new file mode 100644 index 000000000..0f363e3db --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/callbacks.h @@ -0,0 +1,41 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - api/callbacks.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This file contains the definitions for callback functions which will be + * called from the other Core modules + */ + +#if !defined(API_CALLBACKS_H) +#define API_CALLBACKS_H + +#include "usf/usf.h" + +#include "m64p_types.h" +#include "m64p_frontend.h" + +/* Functions for use by the Core, to send information back to the front-end app */ +extern m64p_error SetDebugCallback(usf_state_t *, ptr_DebugCallback pFunc, void *Context); +extern m64p_error SetStateCallback(usf_state_t *, ptr_StateCallback pFunc, void *Context); +extern void DebugMessage(usf_state_t *, int level, const char *message, ...); +extern void StateChanged(usf_state_t *, m64p_core_param param_type, int new_value); + +#endif /* API_CALLBACKS_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_common.h b/Frameworks/lazyusf/lazyusf/api/m64p_common.h new file mode 100644 index 000000000..d6f60f990 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_common.h @@ -0,0 +1,90 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_common.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to common Core + * and plugin functions, for use by the front-end and plugin modules to attach + * to the dynamic libraries. + */ + +#if !defined(M64P_COMMON_H) +#define M64P_COMMON_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* PluginGetVersion() + * + * This function retrieves version information from a library. This + * function is the same for the core library and the plugins. + */ +typedef m64p_error (*ptr_PluginGetVersion)(m64p_plugin_type *, int *, int *, const char **, int *); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *, int *, int *, const char **, int *); +#endif + +/* CoreGetAPIVersions() + * + * This function retrieves API version information from the core. + */ +typedef m64p_error (*ptr_CoreGetAPIVersions)(int *, int *, int *, int *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreGetAPIVersions(int *, int *, int *, int *); +#endif + +/* CoreErrorMessage() + * + * This function returns a pointer to a NULL-terminated string giving a + * human-readable description of the error. +*/ +typedef const char * (*ptr_CoreErrorMessage)(m64p_error); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL CoreErrorMessage(m64p_error); +#endif + +/* PluginStartup() + * + * This function initializes a plugin for use by allocating memory, creating + * data structures, and loading the configuration data. +*/ +typedef m64p_error (*ptr_PluginStartup)(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); +#endif + +/* PluginShutdown() + * + * This function destroys data structures and releases memory allocated by + * the plugin library. +*/ +typedef m64p_error (*ptr_PluginShutdown)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginShutdown(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_COMMON_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_config.h b/Frameworks/lazyusf/lazyusf/api/m64p_config.h new file mode 100644 index 000000000..043d21551 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_config.h @@ -0,0 +1,252 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_config.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to the Core's + * configuration handling functions. + */ + +#if !defined(M64P_CONFIG_H) +#define M64P_CONFIG_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConfigListSections() + * + * This function is called to enumerate the list of Sections in the Mupen64Plus + * configuration file. It is expected that there will be a section named "Core" + * for core-specific configuration data, "Graphics" for common graphics options, + * and one or more sections for each plugin library. + */ +typedef m64p_error (*ptr_ConfigListSections)(void *, void (*)(void *, const char *)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigListSections(void *, void (*)(void *, const char *)); +#endif + +/* ConfigOpenSection() + * + * This function is used to give a configuration section handle to the front-end + * which may be used to read or write configuration parameter values in a given + * section of the configuration file. + */ +typedef m64p_error (*ptr_ConfigOpenSection)(const char *, m64p_handle *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigOpenSection(const char *, m64p_handle *); +#endif + +/* ConfigListParameters() + * + * This function is called to enumerate the list of Parameters in a given + * Section of the Mupen64Plus configuration file. + */ +typedef m64p_error (*ptr_ConfigListParameters)(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigListParameters(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); +#endif + +/* ConfigSaveFile() + * + * This function saves the entire current Mupen64Plus configuration to disk. + */ +typedef m64p_error (*ptr_ConfigSaveFile)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSaveFile(void); +#endif + +/* ConfigSaveSection() + * + * This function saves one section of the current Mupen64Plus configuration to disk. + */ +typedef m64p_error (*ptr_ConfigSaveSection)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSaveSection(const char *); +#endif + +/* ConfigHasUnsavedChanges() + * + * This function determines if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded. + */ +typedef int (*ptr_ConfigHasUnsavedChanges)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL ConfigHasUnsavedChanges(const char *); +#endif + +/* ConfigDeleteSection() + * + * This function deletes a section from the Mupen64Plus configuration data. + */ +typedef m64p_error (*ptr_ConfigDeleteSection)(const char *SectionName); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName); +#endif + +/* ConfigRevertChanges() + * + * This function reverts changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk. + */ +typedef m64p_error (*ptr_ConfigRevertChanges)(const char *SectionName); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName); +#endif + +/* ConfigSetParameter() + * + * This function sets the value of one of the emulator's configuration + * parameters. + */ +typedef m64p_error (*ptr_ConfigSetParameter)(m64p_handle, const char *, m64p_type, const void *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetParameter(m64p_handle, const char *, m64p_type, const void *); +#endif + +/* ConfigSetParameterHelp() + * + * This function sets the help string of one of the emulator's configuration + * parameters. + */ +typedef m64p_error (*ptr_ConfigSetParameterHelp)(m64p_handle, const char *, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetParameterHelp(m64p_handle, const char *, const char *); +#endif + +/* ConfigGetParameter() + * + * This function retrieves the value of one of the emulator's parameters. + */ +typedef m64p_error (*ptr_ConfigGetParameter)(m64p_handle, const char *, m64p_type, void *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigGetParameter(m64p_handle, const char *, m64p_type, void *, int); +#endif + +/* ConfigGetParameterType() + * + * This function retrieves the type of one of the emulator's parameters. + */ +typedef m64p_error (*ptr_ConfigGetParameterType)(m64p_handle, const char *, m64p_type *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigGetParameterType(m64p_handle, const char *, m64p_type *); +#endif + +/* ConfigGetParameterHelp() + * + * This function retrieves the help information about one of the emulator's + * parameters. + */ +typedef const char * (*ptr_ConfigGetParameterHelp)(m64p_handle, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetParameterHelp(m64p_handle, const char *); +#endif + +/* ConfigSetDefault***() + * + * These functions are used to set the value of a configuration parameter if it + * is not already present in the configuration file. This may happen if a new + * user runs the emulator, or an upgraded module uses a new parameter, or the + * user deletes his or her configuration file. If the parameter is already + * present in the given section of the configuration file, then no action will + * be taken and this function will return successfully. + */ +typedef m64p_error (*ptr_ConfigSetDefaultInt)(m64p_handle, const char *, int, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultFloat)(m64p_handle, const char *, float, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultBool)(m64p_handle, const char *, int, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultString)(m64p_handle, const char *, const char *, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetDefaultInt(m64p_handle, const char *, int, const char *); +EXPORT m64p_error CALL ConfigSetDefaultFloat(m64p_handle, const char *, float, const char *); +EXPORT m64p_error CALL ConfigSetDefaultBool(m64p_handle, const char *, int, const char *); +EXPORT m64p_error CALL ConfigSetDefaultString(m64p_handle, const char *, const char *, const char *); +#endif + +/* ConfigGetParam***() + * + * These functions retrieve the value of one of the emulator's parameters in + * the given section, and return the value directly to the calling function. If + * an errors occurs (such as an invalid Section handle, or invalid + * configuration parameter name), then an error will be sent to the front-end + * via the DebugCallback() function, and either a 0 (zero) or an empty string + * will be returned. + */ +typedef int (*ptr_ConfigGetParamInt)(m64p_handle, const char *); +typedef float (*ptr_ConfigGetParamFloat)(m64p_handle, const char *); +typedef int (*ptr_ConfigGetParamBool)(m64p_handle, const char *); +typedef const char * (*ptr_ConfigGetParamString)(m64p_handle, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL ConfigGetParamInt(m64p_handle, const char *); +EXPORT float CALL ConfigGetParamFloat(m64p_handle, const char *); +EXPORT int CALL ConfigGetParamBool(m64p_handle, const char *); +EXPORT const char * CALL ConfigGetParamString(m64p_handle, const char *); +#endif + +/* ConfigGetSharedDataFilepath() + * + * This function is provided to allow a plugin to retrieve a full pathname to a + * given shared data file. This type of file is intended to be shared among + * multiple users on a system, so it is likely to be read-only. + */ +typedef const char * (*ptr_ConfigGetSharedDataFilepath)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetSharedDataFilepath(const char *); +#endif + +/* ConfigGetUserConfigPath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing user-specific configuration files. This will be the + * directory where "mupen64plus.cfg" is located. + */ +typedef const char * (*ptr_ConfigGetUserConfigPath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserConfigPath(void); +#endif + +/* ConfigGetUserDataPath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing user-specific data files. This may be used to store + * files such as screenshots, saved game states, or hi-res textures. + */ +typedef const char * (*ptr_ConfigGetUserDataPath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserDataPath(void); +#endif + +/* ConfigGetUserCachePath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing cached user-specific data files. Files in this + * directory may be deleted by the user to save space, so critical information + * should not be stored here. This directory may be used to store files such + * as the ROM browser cache. + */ +typedef const char * (*ptr_ConfigGetUserCachePath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserCachePath(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_CONFIG_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_debugger.h b/Frameworks/lazyusf/lazyusf/api/m64p_debugger.h new file mode 100644 index 000000000..c8644d3cc --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_debugger.h @@ -0,0 +1,202 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_debugger.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to Core Debugger + * functions. + */ + +#if !defined(M64P_DEBUGGER_H) +#define M64P_DEBUGGER_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* DebugSetCallbacks() + * + * This function is called by the front-end to supply debugger callback + * function pointers. If debugger is enabled and then later disabled within the + * UI, this function may be called with NULL pointers in order to disable the + * callbacks. + */ +typedef m64p_error (*ptr_DebugSetCallbacks)(void (*)(void), void (*)(unsigned int), void (*)(void)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL DebugSetCallbacks(void (*)(void), void (*)(unsigned int), void (*)(void)); +#endif + +/* DebugSetCoreCompare() + * + * This function is called by the front-end to supply callback function pointers + * for the Core Comparison feature. + */ +typedef m64p_error (*ptr_DebugSetCoreCompare)(void (*)(unsigned int), void (*)(int, void *)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL DebugSetCoreCompare(void (*)(unsigned int), void (*)(int, void *)); +#endif + +/* DebugSetRunState() + * + * This function sets the run state of the R4300 CPU emulator. + */ +typedef m64p_error (*ptr_DebugSetRunState)(m64p_dbg_runstate); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL DebugSetRunState(m64p_dbg_runstate); +#endif + +/* DebugGetState() + * + * This function reads and returns a debugger state variable, which are + * enumerated in m64p_types.h. + */ +typedef int (*ptr_DebugGetState)(m64p_dbg_state); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL DebugGetState(m64p_dbg_state); +#endif + +/* DebugStep() + * + * This function signals the debugger to advance one instruction when in the + * stepping mode. + */ +typedef m64p_error (*ptr_DebugStep)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL DebugStep(void); +#endif + +/* DebugDecodeOp() + * + * This is a helper function for the debugger front-end. This instruction takes + * a PC value and an R4300 instruction opcode and writes the disassembled + * instruction mnemonic and arguments into character buffers. This is intended + * to be used to display disassembled code. + */ +typedef void (*ptr_DebugDecodeOp)(unsigned int, char *, char *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void CALL DebugDecodeOp(unsigned int, char *, char *, int); +#endif + +/* DebugMemGetRecompInfo() + * + * This function is used by the front-end to retrieve disassembly information + * about recompiled code. For example, the dynamic recompiler may take a single + * R4300 instruction and compile it into 10 x86 instructions. This function may + * then be used to retrieve the disassembled code of the 10 x86 instructions. + */ +typedef void * (*ptr_DebugMemGetRecompInfo)(m64p_dbg_mem_info, unsigned int, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void * CALL DebugMemGetRecompInfo(m64p_dbg_mem_info, unsigned int, int); +#endif + +/* DebugMemGetMemInfo() + * + * This function returns an integer value regarding the memory location address, + * corresponding to the information requested by mem_info_type, which is a type + * enumerated in m64p_types.h. + */ +typedef int (*ptr_DebugMemGetMemInfo)(m64p_dbg_mem_info, unsigned int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL DebugMemGetMemInfo(m64p_dbg_mem_info, unsigned int); +#endif + +/* DebugMemGetPointer() + * + * This function returns a memory pointer (in x86 memory space) to a block of + * emulated N64 memory. This may be used to retrieve a pointer to a special N64 + * block (such as the serial, video, or audio registers) or the RDRAM. + */ +typedef void * (*ptr_DebugMemGetPointer)(m64p_dbg_memptr_type); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void * CALL DebugMemGetPointer(m64p_dbg_memptr_type); +#endif + +/* DebugMemRead**() + * + * These functions retrieve a value from the emulated N64 memory. The returned + * value will be correctly byte-swapped for the host architecture. + */ +typedef unsigned long long (*ptr_DebugMemRead64)(unsigned int); +typedef unsigned int (*ptr_DebugMemRead32)(unsigned int); +typedef unsigned short (*ptr_DebugMemRead16)(unsigned int); +typedef unsigned char (*ptr_DebugMemRead8)(unsigned int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT unsigned long long CALL DebugMemRead64(unsigned int); +EXPORT unsigned int CALL DebugMemRead32(unsigned int); +EXPORT unsigned short CALL DebugMemRead16(unsigned int); +EXPORT unsigned char CALL DebugMemRead8(unsigned int); +#endif + +/* DebugMemWrite**() + * + * These functions write a value into the emulated N64 memory. The given value + * will be correctly byte-swapped before storage. + */ +typedef void (*ptr_DebugMemWrite64)(unsigned int, unsigned long long); +typedef void (*ptr_DebugMemWrite32)(unsigned int, unsigned int); +typedef void (*ptr_DebugMemWrite16)(unsigned int, unsigned short); +typedef void (*ptr_DebugMemWrite8)(unsigned int, unsigned char); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void CALL DebugMemWrite64(unsigned int, unsigned long long); +EXPORT void CALL DebugMemWrite32(unsigned int, unsigned int); +EXPORT void CALL DebugMemWrite16(unsigned int, unsigned short); +EXPORT void CALL DebugMemWrite8(unsigned int, unsigned char); +#endif + +/* DebugGetCPUDataPtr() + * + * This function returns a memory pointer (in x86 memory space) to a specific + * register in the emulated R4300 CPU. + */ +typedef void * (*ptr_DebugGetCPUDataPtr)(m64p_dbg_cpu_data); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void * CALL DebugGetCPUDataPtr(m64p_dbg_cpu_data); +#endif + +/* DebugBreakpointLookup() + * + * This function searches through all current breakpoints in the debugger to + * find one that matches the given input parameters. If a matching breakpoint + * is found, the index number is returned. If no breakpoints are found, -1 is + * returned. + */ +typedef int (*ptr_DebugBreakpointLookup)(unsigned int, unsigned int, unsigned int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL DebugBreakpointLookup(unsigned int, unsigned int, unsigned int); +#endif + +/* DebugBreakpointCommand() + * + * This function is used to process common breakpoint commands, such as adding, + * removing, or searching the breakpoints. The meanings of the index and ptr + * input parameters vary by command. + */ +typedef int (*ptr_DebugBreakpointCommand)(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL DebugBreakpointCommand(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_DEBUGGER_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_frontend.h b/Frameworks/lazyusf/lazyusf/api/m64p_frontend.h new file mode 100644 index 000000000..61a5cac41 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_frontend.h @@ -0,0 +1,141 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_frontend.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to Core functions + * designed for use by the front-end user interface. + */ + +#if !defined(M64P_FRONTEND_H) +#define M64P_FRONTEND_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* pointer types to the callback functions in the front-end application */ +typedef void (*ptr_DebugCallback)(void *Context, int level, const char *message); +typedef void (*ptr_StateCallback)(void *Context, m64p_core_param param_type, int new_value); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void CALL DebugCallback(void *Context, int level, const char *message); +EXPORT void CALL StateCallback(void *Context, m64p_core_param param_type, int new_value); +#endif + +/* CoreStartup() + * + * This function initializes libmupen64plus for use by allocating memory, + * creating data structures, and loading the configuration file. + */ +typedef m64p_error (*ptr_CoreStartup)(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreStartup(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback); +#endif + +/* CoreShutdown() + * + * This function saves the configuration file, then destroys data structures + * and releases memory allocated by the core library. + */ +typedef m64p_error (*ptr_CoreShutdown)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreShutdown(void); +#endif + +/* CoreAttachPlugin() + * + * This function attaches the given plugin to the emulator core. There can only + * be one plugin of each type attached to the core at any given time. + */ +typedef m64p_error (*ptr_CoreAttachPlugin)(m64p_plugin_type, m64p_dynlib_handle); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type, m64p_dynlib_handle); +#endif + +/* CoreDetachPlugin() + * + * This function detaches the given plugin from the emulator core, and re-attaches + * the 'dummy' plugin functions. + */ +typedef m64p_error (*ptr_CoreDetachPlugin)(m64p_plugin_type); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type); +#endif + +/* CoreDoCommand() + * + * This function sends a command to the emulator core. + */ +typedef m64p_error (*ptr_CoreDoCommand)(m64p_command, int, void *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreDoCommand(m64p_command, int, void *); +#endif + +/* CoreOverrideVidExt() + * + * This function overrides the core's internal SDL-based OpenGL functions. This + * override functionality allows a front-end to define its own video extension + * functions to be used instead of the SDL functions. If any of the function + * pointers in the structure are NULL, the override function will be disabled + * and the core's internal SDL functions will be used. + */ +typedef m64p_error (*ptr_CoreOverrideVidExt)(m64p_video_extension_functions *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *); +#endif + +/* CoreAddCheat() + * + * This function will add a Cheat Function to a list of currently active cheats + * which are applied to the open ROM. + */ +typedef m64p_error (*ptr_CoreAddCheat)(const char *, m64p_cheat_code *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreAddCheat(const char *, m64p_cheat_code *, int); +#endif + +/* CoreCheatEnabled() + * + * This function will enable or disable a Cheat Function which is in the list of + * currently active cheats. + */ +typedef m64p_error (*ptr_CoreCheatEnabled)(const char *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreCheatEnabled(const char *, int); +#endif + +/* CoreGetRomSettings() + * + * This function will retrieve the ROM settings from the mupen64plus INI file for + * the ROM image corresponding to the given CRC values. + */ +typedef m64p_error (*ptr_CoreGetRomSettings)(m64p_rom_settings *, int, int, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *, int, int, int); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_FRONTEND_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_plugin.h b/Frameworks/lazyusf/lazyusf/api/m64p_plugin.h new file mode 100644 index 000000000..dfe6f32a5 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_plugin.h @@ -0,0 +1,273 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_plugin.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if !defined(M64P_PLUGIN_H) +#define M64P_PLUGIN_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*** Controller plugin's ****/ +#define PLUGIN_NONE 1 +#define PLUGIN_MEMPAK 2 +#define PLUGIN_RUMBLE_PAK 3 /* not implemented for non raw data */ +#define PLUGIN_TRANSFER_PAK 4 /* not implemented for non raw data */ +#define PLUGIN_RAW 5 /* the controller plugin is passed in raw data */ + +/***** Structures *****/ +typedef struct { + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * SP_MEM_ADDR_REG; + unsigned int * SP_DRAM_ADDR_REG; + unsigned int * SP_RD_LEN_REG; + unsigned int * SP_WR_LEN_REG; + unsigned int * SP_STATUS_REG; + unsigned int * SP_DMA_FULL_REG; + unsigned int * SP_DMA_BUSY_REG; + unsigned int * SP_PC_REG; + unsigned int * SP_SEMAPHORE_REG; + + unsigned int * DPC_START_REG; + unsigned int * DPC_END_REG; + unsigned int * DPC_CURRENT_REG; + unsigned int * DPC_STATUS_REG; + unsigned int * DPC_CLOCK_REG; + unsigned int * DPC_BUFBUSY_REG; + unsigned int * DPC_PIPEBUSY_REG; + unsigned int * DPC_TMEM_REG; + + void (*CheckInterrupts)(void); + void (*ProcessDlistList)(void); + void (*ProcessAlistList)(void); + void (*ProcessRdpList)(void); + void (*ShowCFB)(void); +} RSP_INFO; + +typedef struct { + unsigned char * HEADER; /* This is the rom header (first 40h bytes of the rom) */ + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * DPC_START_REG; + unsigned int * DPC_END_REG; + unsigned int * DPC_CURRENT_REG; + unsigned int * DPC_STATUS_REG; + unsigned int * DPC_CLOCK_REG; + unsigned int * DPC_BUFBUSY_REG; + unsigned int * DPC_PIPEBUSY_REG; + unsigned int * DPC_TMEM_REG; + + unsigned int * VI_STATUS_REG; + unsigned int * VI_ORIGIN_REG; + unsigned int * VI_WIDTH_REG; + unsigned int * VI_INTR_REG; + unsigned int * VI_V_CURRENT_LINE_REG; + unsigned int * VI_TIMING_REG; + unsigned int * VI_V_SYNC_REG; + unsigned int * VI_H_SYNC_REG; + unsigned int * VI_LEAP_REG; + unsigned int * VI_H_START_REG; + unsigned int * VI_V_START_REG; + unsigned int * VI_V_BURST_REG; + unsigned int * VI_X_SCALE_REG; + unsigned int * VI_Y_SCALE_REG; + + void (*CheckInterrupts)(void); +} GFX_INFO; + +typedef struct { + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * AI_DRAM_ADDR_REG; + unsigned int * AI_LEN_REG; + unsigned int * AI_CONTROL_REG; + unsigned int * AI_STATUS_REG; + unsigned int * AI_DACRATE_REG; + unsigned int * AI_BITRATE_REG; + + void (*CheckInterrupts)(void); +} AUDIO_INFO; + +typedef struct { + int Present; + int RawData; + int Plugin; +} CONTROL; + +typedef union { + unsigned int Value; + struct { + unsigned R_DPAD : 1; + unsigned L_DPAD : 1; + unsigned D_DPAD : 1; + unsigned U_DPAD : 1; + unsigned START_BUTTON : 1; + unsigned Z_TRIG : 1; + unsigned B_BUTTON : 1; + unsigned A_BUTTON : 1; + + unsigned R_CBUTTON : 1; + unsigned L_CBUTTON : 1; + unsigned D_CBUTTON : 1; + unsigned U_CBUTTON : 1; + unsigned R_TRIG : 1; + unsigned L_TRIG : 1; + unsigned Reserved1 : 1; + unsigned Reserved2 : 1; + + signed X_AXIS : 8; + signed Y_AXIS : 8; + }; +} BUTTONS; + +typedef struct { + CONTROL *Controls; /* A pointer to an array of 4 controllers .. eg: + CONTROL Controls[4]; */ +} CONTROL_INFO; + +/* common plugin function pointer types */ +typedef void (*ptr_RomClosed)(void); +typedef int (*ptr_RomOpen)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT int CALL RomOpen(void); +EXPORT void CALL RomClosed(void); +#endif + +/* video plugin function pointer types */ +typedef void (*ptr_ChangeWindow)(void); +typedef int (*ptr_InitiateGFX)(GFX_INFO Gfx_Info); +typedef void (*ptr_MoveScreen)(int x, int y); +typedef void (*ptr_ProcessDList)(void); +typedef void (*ptr_ProcessRDPList)(void); +typedef void (*ptr_ShowCFB)(void); +typedef void (*ptr_UpdateScreen)(void); +typedef void (*ptr_ViStatusChanged)(void); +typedef void (*ptr_ViWidthChanged)(void); +typedef void (*ptr_ReadScreen2)(void *dest, int *width, int *height, int front); +typedef void (*ptr_SetRenderingCallback)(void (*callback)(int)); +typedef void (*ptr_ResizeVideoOutput)(int width, int height); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL ChangeWindow(void); +EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info); +EXPORT void CALL MoveScreen(int x, int y); +EXPORT void CALL ProcessDList(void); +EXPORT void CALL ProcessRDPList(void); +EXPORT void CALL ShowCFB(void); +EXPORT void CALL UpdateScreen(void); +EXPORT void CALL ViStatusChanged(void); +EXPORT void CALL ViWidthChanged(void); +EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front); +EXPORT void CALL SetRenderingCallback(void (*callback)(int)); +EXPORT void CALL ResizeVideoOutput(int width, int height); +#endif + +/* frame buffer plugin spec extension */ +typedef struct +{ + unsigned int addr; + unsigned int size; + unsigned int width; + unsigned int height; +} FrameBufferInfo; +typedef void (*ptr_FBRead)(unsigned int addr); +typedef void (*ptr_FBWrite)(unsigned int addr, unsigned int size); +typedef void (*ptr_FBGetFrameBufferInfo)(void *p); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL FBRead(unsigned int addr); +EXPORT void CALL FBWrite(unsigned int addr, unsigned int size); +EXPORT void CALL FBGetFrameBufferInfo(void *p); +#endif + +/* audio plugin function pointers */ +typedef void (*ptr_AiDacrateChanged)(int SystemType); +typedef void (*ptr_AiLenChanged)(void); +typedef int (*ptr_InitiateAudio)(AUDIO_INFO Audio_Info); +typedef void (*ptr_ProcessAList)(void); +typedef void (*ptr_SetSpeedFactor)(int percent); +typedef void (*ptr_VolumeUp)(void); +typedef void (*ptr_VolumeDown)(void); +typedef int (*ptr_VolumeGetLevel)(void); +typedef void (*ptr_VolumeSetLevel)(int level); +typedef void (*ptr_VolumeMute)(void); +typedef const char * (*ptr_VolumeGetString)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL AiDacrateChanged(int SystemType); +EXPORT void CALL AiLenChanged(void); +EXPORT int CALL InitiateAudio(AUDIO_INFO Audio_Info); +EXPORT void CALL ProcessAList(void); +EXPORT void CALL SetSpeedFactor(int percent); +EXPORT void CALL VolumeUp(void); +EXPORT void CALL VolumeDown(void); +EXPORT int CALL VolumeGetLevel(void); +EXPORT void CALL VolumeSetLevel(int level); +EXPORT void CALL VolumeMute(void); +EXPORT const char * CALL VolumeGetString(void); +#endif + +/* input plugin function pointers */ +typedef void (*ptr_ControllerCommand)(int Control, unsigned char *Command); +typedef void (*ptr_GetKeys)(int Control, BUTTONS *Keys); +typedef void (*ptr_InitiateControllers)(CONTROL_INFO ControlInfo); +typedef void (*ptr_ReadController)(int Control, unsigned char *Command); +typedef void (*ptr_SDL_KeyDown)(int keymod, int keysym); +typedef void (*ptr_SDL_KeyUp)(int keymod, int keysym); +typedef void (*ptr_RenderCallback)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL ControllerCommand(int Control, unsigned char *Command); +EXPORT void CALL GetKeys(int Control, BUTTONS *Keys); +EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo); +EXPORT void CALL ReadController(int Control, unsigned char *Command); +EXPORT void CALL SDL_KeyDown(int keymod, int keysym); +EXPORT void CALL SDL_KeyUp(int keymod, int keysym); +EXPORT void CALL RenderCallback(void); +#endif + +/* RSP plugin function pointers */ +typedef unsigned int (*ptr_DoRspCycles)(unsigned int Cycles); +typedef void (*ptr_InitiateRSP)(RSP_INFO Rsp_Info, unsigned int *CycleCount); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles); +EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* M64P_PLUGIN_H */ + + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_types.h b/Frameworks/lazyusf/lazyusf/api/m64p_types.h new file mode 100644 index 000000000..31ff21f2d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_types.h @@ -0,0 +1,365 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_types.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if !defined(M64P_TYPES_H) +#define M64P_TYPES_H + +/* ----------------------------------------- */ +/* Platform-specific stuff */ +/* ----------------------------------------- */ + +/* necessary headers */ +#if defined(WIN32) + #include +#endif + +/* DLL handles and function declaration specifiers */ +#if defined(WIN32) + #define IMPORT extern "C" __declspec(dllimport) + #define EXPORT __declspec(dllexport) + #define CALL __cdecl + typedef HMODULE m64p_dynlib_handle; +#else + #define IMPORT extern "C" + #define EXPORT __attribute__((visibility("default"))) + #define CALL + typedef void * m64p_dynlib_handle; +#endif + +/* ----------------------------------------- */ +/* Structures and Types for Core library API */ +/* ----------------------------------------- */ + +typedef void * m64p_handle; + +typedef void (*m64p_frame_callback)(unsigned int FrameIndex); +typedef void (*m64p_input_callback)(void); +typedef void (*m64p_audio_callback)(void); +typedef void (*m64p_vi_callback)(void); + +typedef enum { + M64TYPE_INT = 1, + M64TYPE_FLOAT, + M64TYPE_BOOL, + M64TYPE_STRING +} m64p_type; + +typedef enum { + M64MSG_ERROR = 1, + M64MSG_WARNING, + M64MSG_INFO, + M64MSG_STATUS, + M64MSG_VERBOSE +} m64p_msg_level; + +typedef enum { + M64ERR_SUCCESS = 0, + M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */ + M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */ + M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */ + M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */ + M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */ + M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */ + M64ERR_NO_MEMORY, /* Memory allocation failed */ + M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */ + M64ERR_INTERNAL, /* Internal error (bug) */ + M64ERR_INVALID_STATE, /* Current program state does not allow operation */ + M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */ + M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */ + M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */ + M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */ +} m64p_error; + +typedef enum { + M64CAPS_DYNAREC = 1, + M64CAPS_DEBUGGER = 2, + M64CAPS_CORE_COMPARE = 4 +} m64p_core_caps; + +typedef enum { + M64PLUGIN_NULL = 0, + M64PLUGIN_RSP = 1, + M64PLUGIN_GFX, + M64PLUGIN_AUDIO, + M64PLUGIN_INPUT, + M64PLUGIN_CORE +} m64p_plugin_type; + +typedef enum { + M64EMU_STOPPED = 1, + M64EMU_RUNNING, + M64EMU_PAUSED +} m64p_emu_state; + +typedef enum { + M64VIDEO_NONE = 1, + M64VIDEO_WINDOWED, + M64VIDEO_FULLSCREEN +} m64p_video_mode; + +typedef enum { + M64VIDEOFLAG_SUPPORT_RESIZING = 1 +} m64p_video_flags; + +typedef enum { + M64CORE_EMU_STATE = 1, + M64CORE_VIDEO_MODE, + M64CORE_SAVESTATE_SLOT, + M64CORE_SPEED_FACTOR, + M64CORE_SPEED_LIMITER, + M64CORE_VIDEO_SIZE, + M64CORE_AUDIO_VOLUME, + M64CORE_AUDIO_MUTE, + M64CORE_INPUT_GAMESHARK, + M64CORE_STATE_LOADCOMPLETE, + M64CORE_STATE_SAVECOMPLETE +} m64p_core_param; + +typedef enum { + M64CMD_NOP = 0, + M64CMD_ROM_OPEN, + M64CMD_ROM_CLOSE, + M64CMD_ROM_GET_HEADER, + M64CMD_ROM_GET_SETTINGS, + M64CMD_EXECUTE, + M64CMD_STOP, + M64CMD_PAUSE, + M64CMD_RESUME, + M64CMD_CORE_STATE_QUERY, + M64CMD_STATE_LOAD, + M64CMD_STATE_SAVE, + M64CMD_STATE_SET_SLOT, + M64CMD_SEND_SDL_KEYDOWN, + M64CMD_SEND_SDL_KEYUP, + M64CMD_SET_FRAME_CALLBACK, + M64CMD_TAKE_NEXT_SCREENSHOT, + M64CMD_CORE_STATE_SET, + M64CMD_READ_SCREEN, + M64CMD_RESET, + M64CMD_ADVANCE_FRAME +} m64p_command; + +typedef struct { + unsigned int address; + int value; +} m64p_cheat_code; + +/* ----------------------------------------- */ +/* Structures to hold ROM image information */ +/* ----------------------------------------- */ + +typedef enum +{ + SYSTEM_NTSC = 0, + SYSTEM_PAL, + SYSTEM_MPAL +} m64p_system_type; + +typedef struct +{ + unsigned char init_PI_BSB_DOM1_LAT_REG; /* 0x00 */ + unsigned char init_PI_BSB_DOM1_PGS_REG; /* 0x01 */ + unsigned char init_PI_BSB_DOM1_PWD_REG; /* 0x02 */ + unsigned char init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */ + unsigned int ClockRate; /* 0x04 */ + unsigned int PC; /* 0x08 */ + unsigned int Release; /* 0x0C */ + unsigned int CRC1; /* 0x10 */ + unsigned int CRC2; /* 0x14 */ + unsigned int Unknown[2]; /* 0x18 */ + unsigned char Name[20]; /* 0x20 */ + unsigned int unknown; /* 0x34 */ + unsigned int Manufacturer_ID; /* 0x38 */ + unsigned short Cartridge_ID; /* 0x3C - Game serial number */ + unsigned short Country_code; /* 0x3E */ +} m64p_rom_header; + +typedef struct +{ + char goodname[256]; + char MD5[33]; + unsigned char savetype; + unsigned char status; /* Rom status on a scale from 0-5. */ + unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */ + unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */ +} m64p_rom_settings; + +/* ----------------------------------------- */ +/* Structures and Types for the Debugger */ +/* ----------------------------------------- */ + +typedef enum { + M64P_DBG_RUN_STATE = 1, + M64P_DBG_PREVIOUS_PC, + M64P_DBG_NUM_BREAKPOINTS, + M64P_DBG_CPU_DYNACORE, + M64P_DBG_CPU_NEXT_INTERRUPT +} m64p_dbg_state; + +typedef enum { + M64P_DBG_RUNSTATE_PAUSED = 0, + M64P_DBG_RUNSTATE_STEPPING, + M64P_DBG_RUNSTATE_RUNNING +} m64p_dbg_runstate; + +typedef enum { + M64P_DBG_MEM_TYPE = 1, + M64P_DBG_MEM_FLAGS, + M64P_DBG_MEM_HAS_RECOMPILED, + M64P_DBG_MEM_NUM_RECOMPILED, + M64P_DBG_RECOMP_OPCODE = 16, + M64P_DBG_RECOMP_ARGS, + M64P_DBG_RECOMP_ADDR +} m64p_dbg_mem_info; + +typedef enum { + M64P_MEM_NOMEM = 0, + M64P_MEM_NOTHING, + M64P_MEM_RDRAM, + M64P_MEM_RDRAMREG, + M64P_MEM_RSPMEM, + M64P_MEM_RSPREG, + M64P_MEM_RSP, + M64P_MEM_DP, + M64P_MEM_DPS, + M64P_MEM_VI, + M64P_MEM_AI, + M64P_MEM_PI, + M64P_MEM_RI, + M64P_MEM_SI, + M64P_MEM_FLASHRAMSTAT, + M64P_MEM_ROM, + M64P_MEM_PIF, + M64P_MEM_MI, + M64P_MEM_BREAKPOINT +} m64p_dbg_mem_type; + +typedef enum { + M64P_MEM_FLAG_READABLE = 0x01, + M64P_MEM_FLAG_WRITABLE = 0x02, + M64P_MEM_FLAG_READABLE_EMUONLY = 0x04, /* the EMUONLY flags signify that emulated code can read/write here, but debugger cannot */ + M64P_MEM_FLAG_WRITABLE_EMUONLY = 0x08 +} m64p_dbg_mem_flags; + +typedef enum { + M64P_DBG_PTR_RDRAM = 1, + M64P_DBG_PTR_PI_REG, + M64P_DBG_PTR_SI_REG, + M64P_DBG_PTR_VI_REG, + M64P_DBG_PTR_RI_REG, + M64P_DBG_PTR_AI_REG +} m64p_dbg_memptr_type; + +typedef enum { + M64P_CPU_PC = 1, + M64P_CPU_REG_REG, + M64P_CPU_REG_HI, + M64P_CPU_REG_LO, + M64P_CPU_REG_COP0, + M64P_CPU_REG_COP1_DOUBLE_PTR, + M64P_CPU_REG_COP1_SIMPLE_PTR, + M64P_CPU_REG_COP1_FGR_64, + M64P_CPU_TLB +} m64p_dbg_cpu_data; + +typedef enum { + M64P_BKP_CMD_ADD_ADDR = 1, + M64P_BKP_CMD_ADD_STRUCT, + M64P_BKP_CMD_REPLACE, + M64P_BKP_CMD_REMOVE_ADDR, + M64P_BKP_CMD_REMOVE_IDX, + M64P_BKP_CMD_ENABLE, + M64P_BKP_CMD_DISABLE, + M64P_BKP_CMD_CHECK +} m64p_dbg_bkp_command; + +#define M64P_MEM_INVALID 0xFFFFFFFF /* invalid memory read will return this */ + +#define BREAKPOINTS_MAX_NUMBER 128 + +typedef enum { + M64P_BKP_FLAG_ENABLED = 0x01, + M64P_BKP_FLAG_READ = 0x02, + M64P_BKP_FLAG_WRITE = 0x04, + M64P_BKP_FLAG_EXEC = 0x08, + M64P_BKP_FLAG_LOG = 0x10 /* Log to the console when this breakpoint hits */ +} m64p_dbg_bkp_flags; + +#define BPT_CHECK_FLAG(a, b) ((a.flags & b) == b) +#define BPT_SET_FLAG(a, b) a.flags = (a.flags | b); +#define BPT_CLEAR_FLAG(a, b) a.flags = (a.flags & (~b)); +#define BPT_TOGGLE_FLAG(a, b) a.flags = (a.flags ^ b); + +typedef struct { + unsigned int address; + unsigned int endaddr; + unsigned int flags; +} m64p_breakpoint; + +/* ------------------------------------------------- */ +/* Structures and Types for Core Video Extension API */ +/* ------------------------------------------------- */ + +typedef struct { + unsigned int uiWidth; + unsigned int uiHeight; +} m64p_2d_size; + +typedef enum { + M64P_GL_DOUBLEBUFFER = 1, + M64P_GL_BUFFER_SIZE, + M64P_GL_DEPTH_SIZE, + M64P_GL_RED_SIZE, + M64P_GL_GREEN_SIZE, + M64P_GL_BLUE_SIZE, + M64P_GL_ALPHA_SIZE, + M64P_GL_SWAP_CONTROL, + M64P_GL_MULTISAMPLEBUFFERS, + M64P_GL_MULTISAMPLESAMPLES, + M64P_GL_CONTEXT_MAJOR_VERSION, + M64P_GL_CONTEXT_MINOR_VERSION, + M64P_GL_CONTEXT_PROFILE_MASK +} m64p_GLattr; + +typedef enum { + M64P_GL_CONTEXT_PROFILE_CORE, + M64P_GL_CONTEXT_PROFILE_COMPATIBILITY, + M64P_GL_CONTEXT_PROFILE_ES +} m64p_GLContextType; + +typedef struct { + unsigned int Functions; + m64p_error (*VidExtFuncInit)(void); + m64p_error (*VidExtFuncQuit)(void); + m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *); + m64p_error (*VidExtFuncSetMode)(int, int, int, int, int); + void * (*VidExtFuncGLGetProc)(const char*); + m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int); + m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *); + m64p_error (*VidExtFuncGLSwapBuf)(void); + m64p_error (*VidExtFuncSetCaption)(const char *); + m64p_error (*VidExtFuncToggleFS)(void); + m64p_error (*VidExtFuncResizeWindow)(int, int); +} m64p_video_extension_functions; + +#endif /* define M64P_TYPES_H */ + diff --git a/Frameworks/lazyusf/lazyusf/api/m64p_vidext.h b/Frameworks/lazyusf/lazyusf/api/m64p_vidext.h new file mode 100644 index 000000000..a996eb54a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/api/m64p_vidext.h @@ -0,0 +1,154 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_vidext.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to the core's + * video extension functions. + */ + +#if !defined(M64P_VIDEXT_H) +#define M64P_VIDEXT_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* VidExt_Init() + * + * This function should be called from within the InitiateGFX() video plugin + * function call. The default SDL implementation of this function simply calls + * SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or + * switch video modes. + */ +typedef m64p_error (*ptr_VidExt_Init)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_Init(void); +#endif + +/* VidExt_Quit() + * + * This function closes any open rendering window and shuts down the video + * system. The default SDL implementation of this function calls + * SDL_QuitSubSystem(SDL_INIT_VIDEO). This function should be called from + * within the RomClose() video plugin function. + */ +typedef m64p_error (*ptr_VidExt_Quit)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_Quit(void); +#endif + +/* VidExt_ListFullscreenModes() + * + * This function is used to enumerate the available resolutions for fullscreen + * video modes. A pointer to an array is passed into the function, which is + * then filled with resolution sizes. + */ +typedef m64p_error (*ptr_VidExt_ListFullscreenModes)(m64p_2d_size *, int *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *, int *); +#endif + +/* VidExt_SetVideoMode() + * + * This function creates a rendering window or switches into a fullscreen + * video mode. Any desired OpenGL attributes should be set before calling + * this function. + */ +typedef m64p_error (*ptr_VidExt_SetVideoMode)(int, int, int, m64p_video_mode, m64p_video_flags); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_SetVideoMode(int, int, int, m64p_video_mode, m64p_video_flags); +#endif + +/* VidExt_ResizeWindow() + * + * This function resizes the opengl rendering window to match the given size. + */ +typedef m64p_error (*ptr_VidExt_ResizeWindow)(int, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_ResizeWindow(int, int); +#endif + +/* VidExt_SetCaption() + * + * This function sets the caption text of the emulator rendering window. + */ +typedef m64p_error (*ptr_VidExt_SetCaption)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_SetCaption(const char *); +#endif + +/* VidExt_ToggleFullScreen() + * + * This function toggles between fullscreen and windowed rendering modes. + */ +typedef m64p_error (*ptr_VidExt_ToggleFullScreen)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_ToggleFullScreen(void); +#endif + +/* VidExt_GL_GetProcAddress() + * + * This function is used to get a pointer to an OpenGL extension function. This + * is only necessary on the Windows platform, because the OpenGL implementation + * shipped with Windows only supports OpenGL version 1.1. + */ +typedef void * (*ptr_VidExt_GL_GetProcAddress)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT void * CALL VidExt_GL_GetProcAddress(const char *); +#endif + +/* VidExt_GL_SetAttribute() + * + * This function is used to set certain OpenGL attributes which must be + * specified before creating the rendering window with VidExt_SetVideoMode. + */ +typedef m64p_error (*ptr_VidExt_GL_SetAttribute)(m64p_GLattr, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr, int); +#endif + +/* VidExt_GL_GetAttribute() + * + * This function is used to get the value of OpenGL attributes. These values may + * be changed when calling VidExt_SetVideoMode. + */ +typedef m64p_error (*ptr_VidExt_GL_GetAttribute)(m64p_GLattr, int *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr, int *); +#endif + +/* VidExt_GL_SwapBuffers() + * + * This function is used to swap the front/back buffers after rendering an + * output video frame. + */ +typedef m64p_error (*ptr_VidExt_GL_SwapBuffers)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_VIDEXT_H */ + diff --git a/Frameworks/lazyusf/lazyusf/audio.c b/Frameworks/lazyusf/lazyusf/audio.c deleted file mode 100644 index 6331dbb53..000000000 --- a/Frameworks/lazyusf/lazyusf/audio.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "usf.h" -#include "memory.h" -#include "audio.h" -#include -#include - -#include "usf_internal.h" - -void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) { - unsigned int i, do_max; - int16_t * sample_buffer = state->sample_buffer; - - if(!state->cpu_running) - return; - - do_max = length >> 2; - if ( do_max > state->sample_buffer_count ) - do_max = (unsigned int) state->sample_buffer_count; - - if ( sample_buffer ) - for (i = 0; i < do_max; ++i) - { - *sample_buffer++ = ((int16_t*)buf)[1]; - *sample_buffer++ = ((int16_t*)buf)[0]; - buf += 4; - } - else - buf += 4 * do_max; - - state->sample_buffer_count -= do_max; - state->sample_buffer = sample_buffer; - - length -= do_max << 2; - - if ( length ) - { - sample_buffer = state->samplebuf; - do_max = length >> 2; - for (i = 0; i < do_max; ++i) - { - *sample_buffer++ = ((int16_t*)buf)[1]; - *sample_buffer++ = ((int16_t*)buf)[0]; - buf += 4; - } - - state->samples_in_buffer = do_max; - state->cpu_running = 0; - } -} - -void AiLenChanged(usf_state_t * state) { - int32_t length = 0; - uint32_t address = (AI_DRAM_ADDR_REG & 0x00FFFFF8); - - length = AI_LEN_REG & 0x3FFF8; - -#ifdef DEBUG_INFO - fprintf(state->debug_log, "Audio DMA push: %d %d\n", AI_DRAM_ADDR_REG, length); -#endif - - AddBuffer(state, state->RDRAM+address, length); - - if(length && !(AI_STATUS_REG&0x80000000)) { - const float VSyncTiming = 789000.0f; - double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4; - double CountsPerSecond = (double)((((double)VSyncTiming) * (double)60.0)) * 2.0; - double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond; - unsigned int IntScheduled = (unsigned int)((double)AI_LEN_REG * CountsPerByte); - - ChangeTimer(state,AiTimer,IntScheduled); - } - - if(state->enableFIFOfull) { - if(AI_STATUS_REG&0x40000000) - AI_STATUS_REG|=0x80000000; - } - - AI_STATUS_REG|=0x40000000; -} - -unsigned int AiReadLength(usf_state_t * state) { - AI_LEN_REG = 0; - return AI_LEN_REG; -} - -void AiDacrateChanged(usf_state_t * state, unsigned int value) { - AI_DACRATE_REG = value; - state->SampleRate = 48681812 / (AI_DACRATE_REG + 1); -} diff --git a/Frameworks/lazyusf/lazyusf/audio.h b/Frameworks/lazyusf/lazyusf/audio.h deleted file mode 100644 index 3721bab18..000000000 --- a/Frameworks/lazyusf/lazyusf/audio.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _AUDIO_H_ -#define _AUDIO_H_ - -#include "usf.h" -#include "cpu.h" -#include "memory.h" - -uint32_t AiReadLength(usf_state_t *); -void AiLenChanged(usf_state_t *); -void AiDacrateChanged(usf_state_t *, uint32_t value); - -#endif diff --git a/Frameworks/lazyusf/lazyusf/audiolib.c b/Frameworks/lazyusf/lazyusf/audiolib.c deleted file mode 100644 index c567928ea..000000000 --- a/Frameworks/lazyusf/lazyusf/audiolib.c +++ /dev/null @@ -1,271 +0,0 @@ -#include "usf.h" -#include "usf_internal.h" - -#include "cpu_hle.h" -#include "audiolib.h" -#include "os.h" - -#include "main.h" -#include "memory.h" - -#define N64WORD(x) (*(uint32_t*)PageVRAM((x))) -#define N64HALF(x) (*(uint16_t*)PageVRAM((x))) -#define N64BYTE(x) (*(uint8_t*)PageVRAM((x))) - - -int alCopy(usf_state_t * state, int paddr) { - uint32_t source = (state->GPR[4].UW[0]); - uint32_t dest = (state->GPR[5].UW[0]); - uint32_t len = (state->GPR[6].UW[0]); - - if(len&3) - DisplayError(state, "OMG!!!! - alCopy length & 3\n"); - - memcpyn642n64(state, dest, source, len); - - return 1; -} - - - -int alLink(usf_state_t * state, int paddr) { - ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]); - ALLink *after = (ALLink*)PageVRAM(state->GPR[5].UW[0]); - ALLink *afterNext; - - element->next = after->next; - element->prev = state->GPR[5].UW[0]; - - if (after->next) { - afterNext = (ALLink*)PageVRAM(after->next); - afterNext->prev = state->GPR[4].UW[0]; - } - - after->next = state->GPR[4].UW[0]; - return 1; -} - - -int alUnLink(usf_state_t * state, int paddr) { - ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]); - ALLink *elementNext = (ALLink*)PageVRAM(element->next); - ALLink *elementPrev = (ALLink*)PageVRAM(element->prev); -// _asm int 3 - - if (element->next) - elementNext->prev = element->prev; - if (element->prev) - elementPrev->next = element->next; - return 1; -} - -int alEvtqPostEvent(usf_state_t * state, int paddr) { - ALEventQueue *evtq; - ALEvent *events; - - uint32_t A0 = state->GPR[4].UW[0]; - uint32_t A1 = state->GPR[5].UW[0]; - uint32_t DeltaTime = state->GPR[6].UW[0]; - - uint32_t nodeNext = 0; - uint32_t nextItem = 0; - uint32_t node = 0; - uint32_t nextDelta = 0; - uint32_t item = 0; - uint32_t postWhere = 0; - uint32_t NEXT = 0; - uint32_t nextItemDelta = 0; - - evtq = (ALEventQueue *)PageVRAM(A0); - events = (ALEvent *)PageVRAM(A1); -//_asm int 3 - - NEXT = evtq->freeList.next; - - if(NEXT == 0) - return 1; - - //DisplayError("%08x", N64WORD(0x800533E4)); - //cprintf("%08x\t%08x\n", N64WORD(0x800533D4), N64WORD(0x800533D8)); - - item = NEXT; - state->GPR[4].UW[0] = NEXT; - alUnLink(state, 0); - - state->GPR[4].UW[0] = A1; state->GPR[5].UW[0] = NEXT + 0xC; state->GPR[6].UW[0] = 0x10; - alCopy(state, 0); - - postWhere = (DeltaTime==0x7FFFFFFF)?1:0; - nodeNext = A0; - node = nodeNext + 8; - - while(nodeNext !=0 ) { - nodeNext = *(uint32_t*)PageVRAM(node); - - if(nodeNext != 0) { - nextDelta = *(uint32_t*)PageVRAM(nodeNext + 8); - nextItem = nodeNext; - if(DeltaTime < nextDelta) { - *(uint32_t*)PageVRAM(item + 8) = DeltaTime; - nextItemDelta = *(uint32_t*)PageVRAM(nextItem + 8); - *(uint32_t*)PageVRAM(nextItem + 8) = nextItemDelta - DeltaTime; - - state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node; - alLink(state, 0); - return 1; - } else { - node = nodeNext; - DeltaTime -= nextDelta; - if(node == 0) - return 1; - } - } - - } - - if(postWhere == 0) - *(uint32_t*)PageVRAM(item + 8) = DeltaTime; - else - *(uint32_t*)PageVRAM(item + 8) = 0; - - - state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node; - alLink(state, 0); - return 1; -} - -int alEvtqPostEvent_Alt(usf_state_t * state, int paddr) { - return 0; -} - -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -uint32_t __nextSampleTime(usf_state_t * state, uint32_t driver, uint32_t *client) { - - uint32_t c = 0; - int32_t deltaTime = 0x7FFFFFFF; - *client = 0; - - for(c = N64WORD(driver); c != 0; c = N64WORD(c)) { - int samplesLeft = N64WORD(c + 0x10); - int curSamples = N64WORD(driver + 0x20); - if((samplesLeft - curSamples) < deltaTime) { - *client = c; - deltaTime = samplesLeft - curSamples; - } - } - - return N64WORD((*client)+0x10); -} - -int32_t _timeToSamplesNoRound(usf_state_t * state, long synth, long micros) -{ - uint32_t outputRate = N64WORD(synth+0x44); - float tmp = ((float)micros) * outputRate / 1000000.0 + 0.5; - //DisplayError("Smaple rate is %d", outputRate); - - return (int32_t)tmp; -} - -uint32_t byteswap(char b[4] ) { - uint32_t out = 0; - out += b[3]; - out += b[2] << 8; - out += b[1] << 16; - out += b[0] << 24; - return out; -} - -int alAudioFrame(usf_state_t * state, int paddr) { - - uint32_t alGlobals = 0; - uint32_t driver = 0, *paramSamples, *curSamples, client = 0, dl = 0; - uint32_t A0 = state->GPR[4].UW[0]; - uint32_t A1 = state->GPR[5].UW[0]; - uint32_t A2 = state->GPR[6].UW[0]; - uint32_t outLen = state->GPR[7].UW[0]; - uint32_t cmdlEnd = A0; - uint32_t lOutBuf = A2; - - alGlobals = ((*(uint16_t*)PageRAM2(paddr + 0x8)) & 0xFFFF) << 16; //alGlobals->drvr - alGlobals += *(int16_t*)PageRAM2(paddr + 0xc); - //alGlobals = 0x80750C74; - driver = N64WORD(alGlobals); - paramSamples = (uint32_t*) PageVRAM(driver + 0x1c); - curSamples = (uint32_t*) PageVRAM(driver + 0x20); - - if(N64WORD(driver) == 0) { // if(drvr->head == 0) - N64WORD(A1) = 0; - state->GPR[2].UW[0] = A0; - return 1; - } - - for(*paramSamples = __nextSampleTime(state, driver, &client); (*paramSamples - *curSamples) < outLen; *paramSamples = __nextSampleTime(state, driver, &client)) { - int32_t *cSamplesLeft; - cSamplesLeft = (int32_t *) PageVRAM(client + 0x10); - *paramSamples &= ~0xf; - - //run handler (not-HLE'd) - state->GPR[4].UW[0] = client; - RunFunction(state, N64WORD(client+0x8)); - *cSamplesLeft += _timeToSamplesNoRound(state, driver, state->GPR[2].UW[0]); - } - - *paramSamples &= ~0xf; - - //give us some stack - state->GPR[0x1d].UW[0] -= 0x20; - N64WORD(state->GPR[0x1d].UW[0]+0x4) = 0; //tmp - - while (outLen > 0) { - - uint32_t maxOutSamples = 0, nOut = 0, cmdPtr = 0, output = 0, setParam = 0, handler = 0; - - maxOutSamples = N64WORD(driver + 0x48); - nOut = MIN(maxOutSamples, outLen); - cmdPtr = cmdlEnd;//+8; - - output = N64WORD(driver + 0x38); - setParam = N64WORD(output+8); // alSaveParam - - state->GPR[4].DW = output; - state->GPR[5].DW = 0x6; // AL_FILTER_SET_DRAM - state->GPR[6].DW = lOutBuf; - RunFunction(state, setParam); - - handler = N64WORD(output+4); // alSavePull - state->GPR[4].DW = output; - state->GPR[5].DW = state->GPR[0x1d].UW[0]+0x12; //&tmp - state->GPR[6].DW = nOut; - state->GPR[7].DW = *curSamples; - N64WORD(state->GPR[0x1d].UW[0]+0x10) = cmdPtr; - RunFunction(state, handler); - - curSamples = (uint32_t *) PageVRAM(driver + 0x20); - - cmdlEnd = state->GPR[2].UW[0]; - outLen -= nOut; - lOutBuf += (nOut<<2); - *curSamples += nOut; - - } - - state->GPR[0x1d].UW[0] += 0x20; - - N64WORD(A1) = (int32_t) ((cmdlEnd - A0) >> 3); - - state->GPR[4].UW[0] = driver; - - while( (dl = N64WORD(driver+0x14)) ) { - state->GPR[4].UW[0] = dl; - alUnLink(state, 0); - state->GPR[4].UW[0] = dl; - state->GPR[5].UW[0] = driver + 4; - alLink(state, 0); - } - - state->GPR[2].UW[0] = cmdlEnd; - return 1; -} diff --git a/Frameworks/lazyusf/lazyusf/audiolib.h b/Frameworks/lazyusf/lazyusf/audiolib.h deleted file mode 100644 index 375e9b8cb..000000000 --- a/Frameworks/lazyusf/lazyusf/audiolib.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _CPU_HLE_AUDIOLIB_ -#define _CPU_HLE_AUDIOLIB_ - - - -#include "cpu_hle.h" -#include "os.h" - -// a few of these structures/type were sequestered from SGI\Nindendo's code - -typedef struct ALLink_s { - uint32_t next; - uint32_t prev; -} ALLink; - -typedef struct { - ALLink freeList; - ALLink allocList; - int32_t eventCount; -} ALEventQueue; - - -typedef struct { - uint16_t type; - uint8_t msg[12]; -} ALEvent; - - -typedef struct { - ALLink node; - int32_t delta; //microtime - ALEvent event; -} ALEventListItem; - -int alCopy(usf_state_t *, int paddr); -int alLink(usf_state_t *, int paddr); -int alUnLink(usf_state_t *, int paddr); -int alEvtqPostEvent(usf_state_t *, int paddr) ; -int alEvtqPostEvent_Alt(usf_state_t *, int paddr); -int alAudioFrame(usf_state_t *, int paddr); - -// need to remove these - -typedef struct { - uint8_t *base; - uint8_t *cur; - int32_t len; - int32_t count; -} ALHeap; - -typedef struct ALPlayer_s { - struct ALPlayer_s *next; - void *clientData; - void *handler; - int32_t callTime; - int32_t samplesLeft; -} ALPlayer; - - -#endif diff --git a/Frameworks/lazyusf/lazyusf/config.h b/Frameworks/lazyusf/lazyusf/config.h deleted file mode 100644 index ab09878e1..000000000 --- a/Frameworks/lazyusf/lazyusf/config.h +++ /dev/null @@ -1,63 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "lazyusf" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "lazyusf" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "lazyusf 1.0.0" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "lazyusf" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.0.0" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "1.0.0" - -/* Define to 1 if the X Window System is missing or not being used. */ -/* #undef X_DISPLAY_MISSING */ diff --git a/Frameworks/lazyusf/lazyusf/cpu.c b/Frameworks/lazyusf/lazyusf/cpu.c deleted file mode 100644 index ef32418ae..000000000 --- a/Frameworks/lazyusf/lazyusf/cpu.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#include -#include - -#include "main.h" -#include "cpu.h" -#include "usf.h" -#include "audio.h" -#include "registers.h" -#include "rsp.h" -#include "cpu_hle.h" - -#include "usf_internal.h" - -#include - -void ChangeCompareTimer(usf_state_t * state) { - uint32_t NextCompare = COMPARE_REGISTER - COUNT_REGISTER; - if ((NextCompare & 0x80000000) != 0) { NextCompare = 0x7FFFFFFF; } - if (NextCompare == 0) { NextCompare = 0x1; } - ChangeTimer(state,CompareTimer,NextCompare); -} - -void ChangeTimer(usf_state_t * state, int32_t Type, int32_t Value) { - if (Value == 0) { - state->Timers->NextTimer[Type] = 0; - state->Timers->Active[Type] = 0; - return; - } - state->Timers->NextTimer[Type] = Value - state->Timers->Timer; - state->Timers->Active[Type] = 1; - CheckTimer(state); -} - -void CheckTimer (usf_state_t * state) { - int32_t count; - - for (count = 0; count < MaxTimers; count++) { - if (!state->Timers->Active[count]) { continue; } - if (!(count == CompareTimer && state->Timers->NextTimer[count] == 0x7FFFFFFF)) { - state->Timers->NextTimer[count] += state->Timers->Timer; - } - } - state->Timers->CurrentTimerType = -1; - state->Timers->Timer = 0x7FFFFFFF; - for (count = 0; count < MaxTimers; count++) { - if (!state->Timers->Active[count]) { continue; } - if (state->Timers->NextTimer[count] >= state->Timers->Timer) { continue; } - state->Timers->Timer = state->Timers->NextTimer[count]; - state->Timers->CurrentTimerType = count; - } - if (state->Timers->CurrentTimerType == -1) { - DisplayError(state, "No active timers ???\nEmulation Stopped"); - StopEmulation(state); - } - for (count = 0; count < MaxTimers; count++) { - if (!state->Timers->Active[count]) { continue; } - if (!(count == CompareTimer && state->Timers->NextTimer[count] == 0x7FFFFFFF)) { - state->Timers->NextTimer[count] -= state->Timers->Timer; - } - } - - if (state->Timers->NextTimer[CompareTimer] == 0x7FFFFFFF) { - uint32_t NextCompare = COMPARE_REGISTER - COUNT_REGISTER; - if ((NextCompare & 0x80000000) == 0 && NextCompare != 0x7FFFFFFF) { - ChangeCompareTimer(state); - } - } -} - - - -void CloseCpu (usf_state_t * state) { - uint32_t count = 0; - - if(!state->MemChunk) return; - if (!state->cpu_running) { return; } - - state->cpu_running = 0; - - for (count = 0; count < 3; count ++ ) { - state->CPU_Action->CloseCPU = 1; - state->CPU_Action->DoSomething = 1; - } - - state->CPURunning = 0; -} - -int32_t DelaySlotEffectsCompare (usf_state_t * state, uint32_t PC, uint32_t Reg1, uint32_t Reg2) { - OPCODE Command; - - if (!r4300i_LW_VAddr(state, PC + 4, (uint32_t*)&Command.u.Hex)) { - return 1; - } - - switch (Command.u.b.op) { - case R4300i_SPECIAL: - switch (Command.u.e.funct) { - case R4300i_SPECIAL_SLL: - case R4300i_SPECIAL_SRL: - case R4300i_SPECIAL_SRA: - case R4300i_SPECIAL_SLLV: - case R4300i_SPECIAL_SRLV: - case R4300i_SPECIAL_SRAV: - case R4300i_SPECIAL_MFHI: - case R4300i_SPECIAL_MTHI: - case R4300i_SPECIAL_MFLO: - case R4300i_SPECIAL_MTLO: - case R4300i_SPECIAL_DSLLV: - case R4300i_SPECIAL_DSRLV: - case R4300i_SPECIAL_DSRAV: - case R4300i_SPECIAL_ADD: - case R4300i_SPECIAL_ADDU: - case R4300i_SPECIAL_SUB: - case R4300i_SPECIAL_SUBU: - case R4300i_SPECIAL_AND: - case R4300i_SPECIAL_OR: - case R4300i_SPECIAL_XOR: - case R4300i_SPECIAL_NOR: - case R4300i_SPECIAL_SLT: - case R4300i_SPECIAL_SLTU: - case R4300i_SPECIAL_DADD: - case R4300i_SPECIAL_DADDU: - case R4300i_SPECIAL_DSUB: - case R4300i_SPECIAL_DSUBU: - case R4300i_SPECIAL_DSLL: - case R4300i_SPECIAL_DSRL: - case R4300i_SPECIAL_DSRA: - case R4300i_SPECIAL_DSLL32: - case R4300i_SPECIAL_DSRL32: - case R4300i_SPECIAL_DSRA32: - if (Command.u.e.rd == 0) { return 0; } - if (Command.u.e.rd == Reg1) { return 1; } - if (Command.u.e.rd == Reg2) { return 1; } - break; - case R4300i_SPECIAL_MULT: - case R4300i_SPECIAL_MULTU: - case R4300i_SPECIAL_DIV: - case R4300i_SPECIAL_DIVU: - case R4300i_SPECIAL_DMULT: - case R4300i_SPECIAL_DMULTU: - case R4300i_SPECIAL_DDIV: - case R4300i_SPECIAL_DDIVU: - break; - default: - return 1; - } - break; - case R4300i_CP0: - switch (Command.u.b.rs) { - case R4300i_COP0_MT: break; - case R4300i_COP0_MF: - if (Command.u.b.rt == 0) { return 0; } - if (Command.u.b.rt == Reg1) { return 1; } - if (Command.u.b.rt == Reg2) { return 1; } - break; - default: - if ( (Command.u.b.rs & 0x10 ) != 0 ) { - switch( state->Opcode.u.e.funct ) { - case R4300i_COP0_CO_TLBR: break; - case R4300i_COP0_CO_TLBWI: break; - case R4300i_COP0_CO_TLBWR: break; - case R4300i_COP0_CO_TLBP: break; - default: - return 1; - } - return 1; - } - } - break; - case R4300i_CP1: - switch (Command.u.f.fmt) { - case R4300i_COP1_MF: - if (Command.u.b.rt == 0) { return 0; } - if (Command.u.b.rt == Reg1) { return 1; } - if (Command.u.b.rt == Reg2) { return 1; } - break; - case R4300i_COP1_CF: break; - case R4300i_COP1_MT: break; - case R4300i_COP1_CT: break; - case R4300i_COP1_S: break; - case R4300i_COP1_D: break; - case R4300i_COP1_W: break; - case R4300i_COP1_L: break; - return 1; - } - break; - case R4300i_ANDI: - case R4300i_ORI: - case R4300i_XORI: - case R4300i_LUI: - case R4300i_ADDI: - case R4300i_ADDIU: - case R4300i_SLTI: - case R4300i_SLTIU: - case R4300i_DADDI: - case R4300i_DADDIU: - case R4300i_LB: - case R4300i_LH: - case R4300i_LW: - case R4300i_LWL: - case R4300i_LWR: - case R4300i_LDL: - case R4300i_LDR: - case R4300i_LBU: - case R4300i_LHU: - case R4300i_LD: - case R4300i_LWC1: - case R4300i_LDC1: - if (Command.u.b.rt == 0) { return 0; } - if (Command.u.b.rt == Reg1) { return 1; } - if (Command.u.b.rt == Reg2) { return 1; } - break; - case R4300i_CACHE: break; - case R4300i_SB: break; - case R4300i_SH: break; - case R4300i_SW: break; - case R4300i_SWR: break; - case R4300i_SWL: break; - case R4300i_SWC1: break; - case R4300i_SDC1: break; - case R4300i_SD: break; - default: - - return 1; - } - return 0; -} - -int32_t DelaySlotEffectsJump (usf_state_t * state, uint32_t JumpPC) { - OPCODE Command; - - if (!r4300i_LW_VAddr(state, JumpPC, &Command.u.Hex)) { return 1; } - - switch (Command.u.b.op) { - case R4300i_SPECIAL: - switch (Command.u.e.funct) { - case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0); - case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,31); - } - break; - case R4300i_REGIMM: - switch (Command.u.b.rt) { - case R4300i_REGIMM_BLTZ: - case R4300i_REGIMM_BGEZ: - case R4300i_REGIMM_BLTZL: - case R4300i_REGIMM_BGEZL: - case R4300i_REGIMM_BLTZAL: - case R4300i_REGIMM_BGEZAL: - return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0); - } - break; - case R4300i_JAL: - case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,31,0); break; - case R4300i_J: return 0; - case R4300i_BEQ: - case R4300i_BNE: - case R4300i_BLEZ: - case R4300i_BGTZ: - return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt); - case R4300i_CP1: - switch (Command.u.f.fmt) { - case R4300i_COP1_BC: - switch (Command.u.f.ft) { - case R4300i_COP1_BC_BCF: - case R4300i_COP1_BC_BCT: - case R4300i_COP1_BC_BCFL: - case R4300i_COP1_BC_BCTL: - { - int32_t EffectDelaySlot; - OPCODE NewCommand; - - if (!r4300i_LW_VAddr(state, JumpPC + 4, &NewCommand.u.Hex)) { return 1; } - - EffectDelaySlot = 0; - if (NewCommand.u.b.op == R4300i_CP1) { - if (NewCommand.u.f.fmt == R4300i_COP1_S && (NewCommand.u.e.funct & 0x30) == 0x30 ) { - EffectDelaySlot = 1; - } - if (NewCommand.u.f.fmt == R4300i_COP1_D && (NewCommand.u.e.funct & 0x30) == 0x30 ) { - EffectDelaySlot = 1; - } - } - return EffectDelaySlot; - } - break; - } - break; - } - break; - case R4300i_BEQL: - case R4300i_BNEL: - case R4300i_BLEZL: - case R4300i_BGTZL: - return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt); - } - return 1; -} - -void DoSomething ( usf_state_t * state ) { - if (state->CPU_Action->CloseCPU) { - //StopEmulation(); - state->cpu_running = 0; - //printf("Stopping?\n"); - } - if (state->CPU_Action->CheckInterrupts) { - state->CPU_Action->CheckInterrupts = 0; - CheckInterrupts(state); - } - if (state->CPU_Action->DoInterrupt) { - state->CPU_Action->DoInterrupt = 0; - DoIntrException(state, 0); - } - - - state->CPU_Action->DoSomething = 0; - - if (state->CPU_Action->DoInterrupt) { state->CPU_Action->DoSomething = 1; } -} - -void InPermLoop ( usf_state_t * state ) { - // *** Changed ***/ - if (state->CPU_Action->DoInterrupt) { return; } - - /* Interrupts enabled */ - if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { goto InterruptsDisabled; } - if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { goto InterruptsDisabled; } - if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { goto InterruptsDisabled; } - if (( STATUS_REGISTER & 0xFF00) == 0) { goto InterruptsDisabled; } - - /* check sound playing */ - - /* check RSP running */ - /* check RDP running */ - if (state->Timers->Timer >= 0) { - COUNT_REGISTER += state->Timers->Timer + 1; - state->Timers->Timer = -1; - } - return; - -InterruptsDisabled: - DisplayError(state, "Stuck in Permanent Loop"); - StopEmulation(state); -} - -void ReadFromMem(const void * source, void * target, uint32_t length, uint32_t *offset) { - memcpy((uint8_t*)target,((uint8_t*)source)+*offset,length); - *offset+=length; -} - - -uint32_t Machine_LoadStateFromRAM(usf_state_t * state, void * savestatespace) { - uint8_t LoadHeader[0x40]; - uint32_t Value, count, SaveRDRAMSize, offset=0; - - ReadFromMem( savestatespace,&Value,sizeof(Value),&offset); - if (Value != 0x23D8A6C8) { return 0; } - ReadFromMem( savestatespace,&SaveRDRAMSize,sizeof(SaveRDRAMSize),&offset); - ReadFromMem( savestatespace,&LoadHeader,0x40,&offset); - - state->Timers->CurrentTimerType = -1; - state->Timers->Timer = 0; - for (count = 0; count < MaxTimers; count ++) { state->Timers->Active[count] = 0; } - - //fix rdram size - if (SaveRDRAMSize != state->RdramSize) { - // dothis :) - } - - state->RdramSize = SaveRDRAMSize; - - ReadFromMem( savestatespace,&Value,sizeof(Value),&offset); - ChangeTimer(state,ViTimer,Value); - ReadFromMem( savestatespace,&state->PROGRAM_COUNTER,sizeof(state->PROGRAM_COUNTER),&offset); - ReadFromMem( savestatespace,state->GPR,sizeof(int64_t)*32,&offset); - ReadFromMem( savestatespace,state->FPR,sizeof(int64_t)*32,&offset); - ReadFromMem( savestatespace,state->CP0,sizeof(uint32_t)*32,&offset); - ReadFromMem( savestatespace,state->FPCR,sizeof(uint32_t)*32,&offset); - ReadFromMem( savestatespace,&state->HI,sizeof(int64_t),&offset); - ReadFromMem( savestatespace,&state->LO,sizeof(int64_t),&offset); - ReadFromMem( savestatespace,state->RegRDRAM,sizeof(uint32_t)*10,&offset); - ReadFromMem( savestatespace,state->RegSP,sizeof(uint32_t)*10,&offset); - ReadFromMem( savestatespace,state->RegDPC,sizeof(uint32_t)*10,&offset); - ReadFromMem( savestatespace,state->RegMI,sizeof(uint32_t)*4,&offset); - ReadFromMem( savestatespace,state->RegVI,sizeof(uint32_t)*14,&offset); - ReadFromMem( savestatespace,state->RegAI,sizeof(uint32_t)*6,&offset); - ReadFromMem( savestatespace,state->RegPI,sizeof(uint32_t)*13,&offset); - ReadFromMem( savestatespace,state->RegRI,sizeof(uint32_t)*8,&offset); - ReadFromMem( savestatespace,state->RegSI,sizeof(uint32_t)*4,&offset); - ReadFromMem( savestatespace,state->tlb,sizeof(TLB)*32,&offset); - ReadFromMem( savestatespace,(uint8_t*)state->PIF_Ram,0x40,&offset); - ReadFromMem( savestatespace,state->RDRAM,SaveRDRAMSize,&offset); - ReadFromMem( savestatespace,state->DMEM,0x1000,&offset); - ReadFromMem( savestatespace,state->IMEM,0x1000,&offset); - - state->CP0[32] = 0; - - SetupTLB(state); - ChangeCompareTimer(state); - AI_STATUS_REG = 0; - AiDacrateChanged(state, AI_DACRATE_REG); - -// StartAiInterrupt(state); - - SetFpuLocations(state); // important if FR=1 - - return 1; -} - -void StartEmulationFromSave ( usf_state_t * state, void * savestate ) { - uint32_t count = 0; - - //printf("Starting generic Cpu\n"); - - //CloseCpu(); - memset(state->N64MEM, 0, state->RdramSize); - - memset(state->DMEM, 0, 0x1000); - memset(state->IMEM, 0, 0x1000); - memset(state->TLB_Map, 0, 0x100000 * sizeof(uintptr_t) + 0x10000); - - memset(state->CPU_Action,0,sizeof(*state->CPU_Action)); - state->WrittenToRom = 0; - - InitilizeTLB(state); - - SetupRegisters(state, state->Registers); - - BuildInterpreter(state); - - state->Timers->CurrentTimerType = -1; - state->Timers->Timer = 0; - - for (count = 0; count < MaxTimers; count ++) { state->Timers->Active[count] = 0; } - ChangeTimer(state,ViTimer,5000); - ChangeCompareTimer(state); - state->ViFieldNumber = 0; - state->CPURunning = 1; - *state->WaitMode = 0; - - init_rsp(state); - - Machine_LoadStateFromRAM(state, savestate); - - state->SampleRate = 48681812 / (AI_DACRATE_REG + 1); - - if(state->enableFIFOfull) { - const float VSyncTiming = 789000.0f; - double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4; - double CountsPerSecond = (double)(((double)VSyncTiming) * (double)60.0); - double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond; - uint32_t IntScheduled = (uint32_t)((double)AI_LEN_REG * CountsPerByte); - - ChangeTimer(state,AiTimer,IntScheduled); - AI_STATUS_REG|=0x40000000; - } - - state->OLD_VI_V_SYNC_REG = ~VI_V_SYNC_REG; - - CPUHLE_Scan(state); -} - - -void RefreshScreen (usf_state_t * state){ - if (state->OLD_VI_V_SYNC_REG != VI_V_SYNC_REG) - { - state->OLD_VI_V_SYNC_REG = VI_V_SYNC_REG; - if (VI_V_SYNC_REG == 0) - { - state->VI_INTR_TIME = 500000; - } - else - { - state->VI_INTR_TIME = (VI_V_SYNC_REG + 1) * 1500; - if ((VI_V_SYNC_REG & 1) != 0) - { - state->VI_INTR_TIME -= 38; - } - } - } - - ChangeTimer(state,ViTimer,state->Timers->Timer + state->Timers->NextTimer[ViTimer] + state->VI_INTR_TIME); - - if ((VI_STATUS_REG & 0x10) != 0) - { - if (state->ViFieldNumber == 0) - { - state->ViFieldNumber = 1; - } - else - { - state->ViFieldNumber = 0; - } - } - else - { - state->ViFieldNumber = 0; - } -} - -void RunRsp (usf_state_t * state) { -#ifdef DEBUG_INFO - fprintf(state->debug_log, "RSP Task:"); -#endif - if ( ( SP_STATUS_REG & SP_STATUS_HALT ) == 0) { - if ( ( SP_STATUS_REG & SP_STATUS_BROKE ) == 0 ) { - - uint32_t Task = *( uint32_t *)(state->DMEM + 0xFC0); - - switch (Task) { - case 1: { - MI_INTR_REG |= 0x20; - - SP_STATUS_REG |= (0x0203 ); - if ((SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) - MI_INTR_REG |= 1; - -#ifdef DEBUG_INFO - fprintf(state->debug_log, " DList - interrupts %d\n", MI_INTR_REG); -#endif - - CheckInterrupts(state); - - DPC_STATUS_REG &= ~0x0002; - return; - - } - break; - case 2: { -#ifdef DEBUG_INFO - fprintf(state->debug_log, " AList"); -#endif - break; - } - break; - default: - - break; - } - - real_run_rsp(state, 100); - SP_STATUS_REG |= (0x0203 ); - if ((SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { -#ifdef DEBUG_INFO - fprintf(state->debug_log, " - interrupt"); -#endif - MI_INTR_REG |= 1; - CheckInterrupts(state); - } - } - } -#ifdef DEBUG_INFO - fprintf(state->debug_log, "\n"); -#endif -} - -void TimerDone (usf_state_t * state) { - switch (state->Timers->CurrentTimerType) { - case CompareTimer: - if(state->enablecompare) - FAKE_CAUSE_REGISTER |= CAUSE_IP7; - CheckInterrupts(state); - ChangeCompareTimer(state); - break; - case ViTimer: - RefreshScreen(state); - MI_INTR_REG |= MI_INTR_VI; - CheckInterrupts(state); - *state->WaitMode=0; - break; - case AiTimer: - ChangeTimer(state,AiTimer,0); - AI_STATUS_REG=0; - state->AudioIntrReg|=4; - //CheckInterrupts(state); - break; - } - CheckTimer(state); -} diff --git a/Frameworks/lazyusf/lazyusf/cpu.h b/Frameworks/lazyusf/lazyusf/cpu.h deleted file mode 100644 index df328580e..000000000 --- a/Frameworks/lazyusf/lazyusf/cpu.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#ifndef _CPU_H_ -#define _CPU_H_ - -#include "interpreter_cpu.h" -#include "interpreter_ops.h" -#include "registers.h" -#include "tlb.h" -#include "memory.h" -#include "dma.h" -#include "exception.h" -#include "pif.h" -#include "opcode.h" -#include "usf.h" - -typedef struct { - int32_t DoSomething; - int32_t CloseCPU; - int32_t CheckInterrupts; - int32_t DoInterrupt; -} CPU_ACTION; - -#define MaxTimers 3 -#define CompareTimer 0 -#define ViTimer 1 -#define AiTimer 2 - -typedef struct { - int32_t NextTimer[MaxTimers]; - int32_t Active[MaxTimers]; - int32_t CurrentTimerType; - int32_t Timer; -} SYSTEM_TIMERS; - -void ChangeCompareTimer ( usf_state_t * ); -void ChangeTimer ( usf_state_t *, int32_t Type, int32_t Value ); -void CheckTimer ( usf_state_t * ); -void CloseCpu ( usf_state_t * ); -int32_t DelaySlotEffectsCompare ( usf_state_t *, uint32_t PC, uint32_t Reg1, uint32_t Reg2 ); -int32_t DelaySlotEffectsJump ( usf_state_t *, uint32_t JumpPC); -void DoSomething ( usf_state_t * ); -void InPermLoop ( usf_state_t * ); -void InitiliazeCPUFlags ( usf_state_t * ); -void RefreshScreen ( usf_state_t * ); -void RunRsp ( usf_state_t * ); -void StartEmulation ( usf_state_t * ); -void TimerDone ( usf_state_t * ); -void RecompileTimerDone ( usf_state_t * ); - -#define NORMAL 0 -#define DO_DELAY_SLOT 1 -#define DO_END_DELAY_SLOT 2 -#define DELAY_SLOT 3 -#define END_DELAY_SLOT 4 -#define LIKELY_DELAY_SLOT 5 -#define JUMP 6 -#define DELAY_SLOT_DONE 7 -#define LIKELY_DELAY_SLOT_DONE 8 -#define END_BLOCK 9 - -enum SaveType { - Auto, - Eeprom_4K, - Eeprom_16K, - Sram, - FlashRam -}; - -void StartEmulationFromSave ( usf_state_t * state, void * savestate ); - -#endif diff --git a/Frameworks/lazyusf/lazyusf/cpu_hle.c b/Frameworks/lazyusf/lazyusf/cpu_hle.c deleted file mode 100644 index 6b04cedc5..000000000 --- a/Frameworks/lazyusf/lazyusf/cpu_hle.c +++ /dev/null @@ -1,161 +0,0 @@ -#include - -#include "usf.h" -#include "usf_internal.h" - -#include "cpu_hle.h" -#include "os.h" -#include "audiolib.h" - -// Nintendo 64 Standard (and non standard) library functions, for HLE - - -int numEntries = 0; - - - -_HLE_Entry entrys[] = { - {"__osEnqueueThread",0,20,{0x8C,0x98,0,0,0x8C,0xAF,0,4,0,0x80,0xC8,0x25,0x8F,0xE,0,4,1,0xCF,8,0x2A},0,0,__osEnqueueThread}, - - {"__osRestoreInt",0,28,{0x40,8,0x60,0 ,1,4,0x40,0x25,0x40,0x88,0x60,0,0,0,0,0,0,0,0,0,3,0xE0,0,8,0,0,0,0},0,0,__osRestoreInt}, - {"__osDisableInt",0,32,{0x40,8,0x60,0,0x24,1,0xFF,0xFE,1,1,0x48,0x24,0x40,0x89,0x60,0,0x31,2,0,1,0,0,0,0,3,0xE0,0,8,0,0,0,0},0,0,__osDisableInt}, -// {"osStartThread",0,32,{0x27,0xBD,0xFF,0xD8,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xB1,0,0x18,0xC,-1,-1,-1,0xAF,0xB0,0,0x14,0x8F,0xAE,0,0x28,0x24,1,0,1,0,0x40,0x80,0x25},0,0,osStartThread}, - //{"osPiStartDma",0,52,{0x27,0xBD,0xFF,0xD8,0x3C,0xE,-1,-1,0x8D,0xCE,-1,-1,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xA5,0,0x2C,0xAF,0xA6,0,0x30,0xAF,0xA7,0,0x34,0xAF,0xB1,0,0x18,0x15,0xC0,0,3,0xAF,0xB0,0,0x14,0x10,0,0,0x32,0x24,2,0xFF,0xFF},0,0,osPiStartDma} - //{"osRecvMesg",0,60,{0x27,0xBD,0xFF,0xD8,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xA5,0,0x2C,0xAF,0xA6,0,0x30,0xAF,0xB1,0,0x18,0xC,-1,-1,-1,0xAF,0xB0,0,0x14,0x8F,0xAE,0,0x28,0,0x40,0x80,0x25,0x8D,0xCF,0,8,0x15,0xE0,0,0x12,0,0,0,0,0x8f,0xb8,0,0x30,0x17,0,0,5},0,0,osRecvMesg}, - - {"saveThreadContext",0,32,{0x3C,5,-1,-1,0x8C,0xA5,-1,-1,0x40,8,0x60,0,0x8C,0xBB,0,0x18,0x35,8,0,2,0xAC,0xA8,1,0x18,0xFC,0xB0,0,0x98,0xFC,0xB1,0,0xA0},0,0,saveThreadContext}, - {"loadThreadContext",0,40,{0x3C,4,-1,-1,0xC,-1,-1,-1,0x24,0x84,-1,-1,0x3C,1,-1,-1,0xAC,0x22,-1,-1,0x24,8,0,4,0xA4,0x48,0,0x10,0,0x40,0xD0,0x25,0x3C,8,-1,-1,0x8F,0x5B,1,0x18},0,0,loadThreadContext}, - - - {"osSetIntMask",0,44,{0x40,0xC,0x60,0,0x31,0x82,0xFF,1,0x3C,8,-1,-1,0x25,8,-1,-1,0x8D,0xB,0,0,0x24,1,0xFF,0xFF,1,0x61,0x40,0x26,0x31,8,0xFF,0,0,0x48,0x10,0x25,0x3C,0xA,0xA4,0x30,0x8D,0x4A,0,0xC},0,0,osSetIntMask}, - {"osVirtualToPhysical",0,36,{0x27,0xBD,0xFF,0xE8,0xAF,0xA4,0,0x18,0x8F,0xAE,0,0x18,0x3C,1,0x80,0,0xAF,0xBF,0,0x14,1,0xC1,8,0x2B,0x14,0x20,0,7,0x3C,1,0xA0,0,1,0xC1,8,0x2B},0,0,osVirtualToPhysical}, - - - {"alCopy",0,32,{0,0x80,0x10,0x25,0,0xA0,0x18,0x25,0x18,0xC0,0,0x18,0,0,0x38,0x25,0x30,0xC5,0,3,0x10,0xA0,0,9,0,0xA0,0x20,0x25,0x90,0x4E,0,0},0,0,alCopy}, - {"alLink",0,28,{0x8C,0xAE,0,0,0xAC,0x85,0,4,0xAC,0x8E,0,0,0x8C,0xA2,0,0,0x10,0x40,0,2,0,0,0,0,0xAC,0x44,0,4},0,0,alLink}, - {"alUnlink",0,28,{0x8C,0x82,0,0,0x50,0x40,0,4,0x8C,0x82,0,4,0x8C,0x8E,0,4,0xAC,0x4E,0,4,0x8C,0x82,0,4,0x10,0x40,0,3},0,0,alUnLink}, - - {"osAiSetNextBuffer",0,32,{0x27,0xBD,0xFF,0xE0,0x3C,0xF,-1,-1,0x91,0xEF,-1,-1,0xAF,0xA4,0,0x20,0x8F,0xAE,0,0x20,0xAF,0xBF,0,0x14,0xAF,0xA5,0,0x24,0x11,0xE0,0,3},0,0,osAiSetNextBuffer}, - - {"alLink (DK64)",0,20,{0x8C,0xAE,0,0,0xAC,0x8E,0,0,0xAC,0x85,0,4,0x8C,0xAF,0,0,0x11,0xE0,0,3},0,0,alLink}, - {"alUnLink (DK64)",0,28,{0x8C,0x8E,0,0,0x11,0xC0,0,4,0,0,0,0,0x8C,0x8F,0,4,0x8C,0x98,0,0,0xAF,0xF,0,4,0x8C,0x99,0,4},0,0,alUnLink}, - - {"alEvtqPostEvent",0,64,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA0,0,0x20,0x24,4,0,1,0xC,-1,-1,-1,0xAF,0xA6,0,0x38,0x8F,0xAE,0,0x30,0x8F,0xA7,0,0x38,0,0x40,0x28,0x25,0x8D,0xC8,0,0,0x15,0,0,5,1,0,0x20,0x25,0xC,-1,-1,-1,0,0x40,0x20,0x25},0,0,alEvtqPostEvent}, - - {"alEvtqPostEvent (DK64)",0,64,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA6,0,0x38,0xAF,0xA0,0,0x20,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x1C,0x8F,0xAE,0,0x30,0x8D,0xCF,0,0,0xAF,0xAF,0,0x2C,0x8F,0xB8,0,0x2C,0x17,0,0,5,0,0,0,0,0xC,-1,-1,-1,0x8F,0xA4,0,0x1C},0,0,alEvtqPostEvent}, - {"alEvtqPostEvent (CBFD)",0,56,{0x27,0xBD,0xFF,0xC0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x40,0xAF,0xA5,0,0x44,0xAF,0xA6,0,0x48,0xAF,0xA7,0,0x4C,0xAF,0xA0,0,0x30,0x8F,0xAE,0,0x4C,0x31,0xCF,0,2,0x11,0xE0,0,4,0,0,0,0,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x2C},0,0,alEvtqPostEvent}, - {"alEvtqPostEvent (BT)",0,60,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA6,0,0x38,0xAF,0xA7,0,0x3C,0xAF,0xA0,0,0x20,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x1C,0x8F,0xAE,0,0x30,0x8D,0xCF,0,0,0xAF,0xAF,0,0x2C,0x8F,0xB8,0,0x2C,0x17,0,0,5},0,0,alEvtqPostEvent}, - - {"alAudioFrame",0,52,{0x27,0xBD,0xFF,0x48,0xAF,0xB1,0,0x30,0x3C,0x11,-1,-1,0x8E,0x31,0-1,-1,0xAF,0xBF,0,0x4C,0xAF,0xB7,0,0x48,0xAF,0xB6,0,0x44,0xAF,0xB5,0,0x40,0xAF,0xB4,0,0x3C,0xAF,0xB3,0,0x38,0xAF,0xB2,0,0x34,0xAF,0xB0,0,0x2C,0xF7,0xB6,0,0x20},0,0,alAudioFrame}, - - //{"alAudioFrame (DK64)",0,64,{0x27,0xBD,0xFF,0xC0,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x40,0xAF,0xA5,0,0x44,0xAF,0xA6,0,0x48,0xAF,0xA7,0,0x4C,0xAF,0xB1,0,0x18,0xAF,0xB0,0,0x14,0xA7,0xA0,0,0x3A,0x8F,0xAE,0,0x40,0xAF,0xAE,0,0x34,0x8F,0xAF,0,0x48,0xAF,0xAF,0,0x28,0x3C,0x18,0x80,0x75,0x8F,0x18,0xC,0x74,0x8F,0x19,0,0},0,0,alAudioFrame}, - -}; -//int 0xA4,0xA6,0,0x38 - -//char foundlist[2048]; - -int sort_entrys(void * a, void * b) -{ - _HLE_Entry * _a = (_HLE_Entry *)a; - _HLE_Entry * _b = (_HLE_Entry *)b; - return _b->used - _a->used; -} - -int CPUHLE_Scan(usf_state_t * state) -{ - int i = 0, j = 0; - unsigned char c = 0; - long d = 0; - int entrySize = 0; - int entry = 0; - void * address = 0; - int good = 1; //, needcomma = 0; - _HLE_Entry * entries; - unsigned entries_used = 0; - - numEntries = sizeof(entrys) / sizeof(_HLE_Entry); - - entries = state->cpu_hle_entries = realloc( state->cpu_hle_entries, sizeof(entrys) ); - memcpy( entries, entrys, sizeof(entrys) ); - - //for(i=0; i < numEntries; i++) - // entries[i].used = 0; - - //memset(foundlist,0,2048); - - for(i=0; i < (state->RdramSize - 64); i+=4) { - - for(entry = 0; entry < numEntries; entry++) { - - if(entries[entry].used) - continue; - - good = 1; - entrySize = entries[entry].length; - - for(j=0; j < entrySize; j++) { - address = state->N64MEM + i + j; - //address = i; - c = *(unsigned char *)(address); - d = entries[entry].bytes[j^3]; - - if((c != d) && (d!=-1)) { - good = 0; - break; - } - } - - if(good == 1 && i< (state->RdramSize-64)) { - //char buf[256]; - //if(needcomma) { - // sprintf(buf,", %s", entries[entry].name); - //} else { - // sprintf(buf,"%s", entries[entry].name); - //} - - //needcomma = 1; - //strcat(foundlist,buf); - - entries[entry].used = 1; - entries[entry].phys = i; - ++entries_used; - break; - } - } - - } - - qsort(entries, numEntries, sizeof(*entries), sort_entrys); - state->cpu_hle_entry_count = entries_used; - - //printf("<--------------HLE Functions Found--------------->\n%s<------------------------------------------------>\n", foundlist); - //printf("HLE Functions found: %s\n", foundlist); - - return 0; -} - -int DoCPUHLE(usf_state_t * state, unsigned long loc) -{ - int i = 0; - uintptr_t real_addr = PageVRAM2(loc); - _HLE_Entry * entries = state->cpu_hle_entries; - unsigned numEntries = state->cpu_hle_entry_count; - - for(i = 0; i < numEntries; i++) { - - if(entries[i].phys == real_addr) { - //printf("CPU HLEing using %d at %08x (phys: %08x) \"%s\"\n", entries[i].name, loc, entries[i].phys, entries[i].name); - - if(entries[i].location(state, entries[i].phys)) { - // printf("done\n"); - return 1; - } - else - return 0; - } - - } - - return 0; -} diff --git a/Frameworks/lazyusf/lazyusf/cpu_hle.h b/Frameworks/lazyusf/lazyusf/cpu_hle.h deleted file mode 100644 index a2a0d6355..000000000 --- a/Frameworks/lazyusf/lazyusf/cpu_hle.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _CPU_HLE_ -#define _CPU_HLE_ - -#include "usf.h" -#include "cpu.h" -#include "interpreter_ops.h" -#include "memory.h" - -typedef struct { - char *name; - int num; - int length; - long bytes[80]; - int used; - int phys; - int (*location)(usf_state_t *, int); -} _HLE_Entry; - -int CPUHLE_Scan(usf_state_t *); -int DoCPUHLE(usf_state_t *, unsigned long loc); -//////////////////////////////////////////////////////////////////// -// OS Thread Stuff -// found this stuff in daedalus - - - -#endif diff --git a/Frameworks/lazyusf/lazyusf/dma.c b/Frameworks/lazyusf/lazyusf/dma.c deleted file mode 100644 index c7ee2323c..000000000 --- a/Frameworks/lazyusf/lazyusf/dma.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#include - -#include "main.h" -#include "cpu.h" - -#include "usf.h" -#include "usf_internal.h" - -void PI_DMA_READ (usf_state_t * state) { - - PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; - MI_INTR_REG |= MI_INTR_PI; - CheckInterrupts(state); - return; -} - -void PI_DMA_WRITE (usf_state_t * state) { - uint32_t i; -#ifdef DEBUG_INFO - fprintf(state->debug_log, "PI DMA WRITE: %08x to %08x for %08x bytes\n", PI_CART_ADDR_REG, PI_DRAM_ADDR_REG, PI_WR_LEN_REG + 1); -#endif - PI_STATUS_REG |= PI_STATUS_DMA_BUSY; - if ( PI_DRAM_ADDR_REG + PI_WR_LEN_REG + 1 > state->RdramSize) { - PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; - MI_INTR_REG |= MI_INTR_PI; - CheckInterrupts(state); - return; - } - - if ( PI_CART_ADDR_REG >= 0x08000000 && PI_CART_ADDR_REG <= 0x08010000) { - return; - } - - if ( PI_CART_ADDR_REG >= 0x10000000 && PI_CART_ADDR_REG <= 0x1FBFFFFF) { - PI_CART_ADDR_REG -= 0x10000000; - for (i = 0; i < PI_WR_LEN_REG + 1; i ++) { - *(state->N64MEM+((PI_DRAM_ADDR_REG + i) ^ 3)) = *PageROM(state, (PI_CART_ADDR_REG + i) ^ 3); - } - PI_CART_ADDR_REG += 0x10000000; - - PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; - MI_INTR_REG |= MI_INTR_PI; - CheckInterrupts(state); - CheckTimer(state); - return; - } - - PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; - MI_INTR_REG |= MI_INTR_PI; - CheckInterrupts(state); -} - - -void SI_DMA_READ (usf_state_t * state) { - - if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) { - return; - } - - PifRamRead(state); - SI_DRAM_ADDR_REG &= 0xFFFFFFF8; - if ((int32_t)SI_DRAM_ADDR_REG < 0) { - int32_t count, RdramPos; - - RdramPos = (int32_t)SI_DRAM_ADDR_REG; - for (count = 0; count < 0x40; count++, RdramPos++) { - if (RdramPos < 0) { continue; } - state->N64MEM[RdramPos ^3] = state->PIF_Ram[count]; - } - } else { - int32_t count, RdramPos; - - RdramPos = (uint32_t)SI_DRAM_ADDR_REG; - for (count = 0; count < 0x40; count++, RdramPos++) { - if (RdramPos < 0) { continue; } - state->N64MEM[RdramPos ^3] = state->PIF_Ram[count]; - } - } - - MI_INTR_REG |= MI_INTR_SI; - SI_STATUS_REG |= SI_STATUS_INTERRUPT; - CheckInterrupts(state); -} - - -void SI_DMA_WRITE (usf_state_t * state) { - - if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) { - return; - } - - SI_DRAM_ADDR_REG &= 0xFFFFFFF8; - if ((int32_t)SI_DRAM_ADDR_REG < 0) { - int32_t count, RdramPos; - - RdramPos = (int32_t)SI_DRAM_ADDR_REG; - for (count = 0; count < 0x40; count++, RdramPos++) { - if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; } - state->PIF_Ram[count] = state->N64MEM[RdramPos ^3]; - } - } else { - int32_t count, RdramPos; - - RdramPos = (int32_t)SI_DRAM_ADDR_REG; - for (count = 0; count < 0x40; count++, RdramPos++) { - if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; } - state->PIF_Ram[count] = state->N64MEM[RdramPos ^3]; - } - } - - PifRamWrite(state); - - MI_INTR_REG |= MI_INTR_SI; - SI_STATUS_REG |= SI_STATUS_INTERRUPT; - CheckInterrupts(state); - -} - -void SP_DMA_READ (usf_state_t * state) { - SP_DRAM_ADDR_REG &= 0x1FFFFFFF; - - if (SP_DRAM_ADDR_REG > state->RdramSize) { - SP_DMA_BUSY_REG = 0; - SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY; - return; - } - - if (SP_RD_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) { - return; - } - - memcpy( state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF), state->N64MEM + SP_DRAM_ADDR_REG, - SP_RD_LEN_REG + 1 ); - - SP_DMA_BUSY_REG = 0; - SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY; - MI_INTR_REG &= ~MI_INTR_SP; - CheckInterrupts(state); - CheckTimer(state); -} - -void SP_DMA_WRITE (usf_state_t * state) { - if (SP_DRAM_ADDR_REG > state->RdramSize) { - return; - } - - if (SP_WR_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) { - return; - } - - memcpy( state->N64MEM + SP_DRAM_ADDR_REG, state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF), - SP_WR_LEN_REG + 1); - - SP_DMA_BUSY_REG = 0; - SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY; -} - diff --git a/Frameworks/lazyusf/lazyusf/dma.h b/Frameworks/lazyusf/lazyusf/dma.h deleted file mode 100644 index 8d9adb223..000000000 --- a/Frameworks/lazyusf/lazyusf/dma.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -void PI_DMA_READ ( usf_state_t * ); -void PI_DMA_WRITE ( usf_state_t * ); -void SI_DMA_READ ( usf_state_t * ); -void SI_DMA_WRITE ( usf_state_t * ); -void SP_DMA_READ ( usf_state_t * ); -void SP_DMA_WRITE ( usf_state_t * ); - - - diff --git a/Frameworks/lazyusf/lazyusf/exception.c b/Frameworks/lazyusf/lazyusf/exception.c deleted file mode 100644 index d44bfee4d..000000000 --- a/Frameworks/lazyusf/lazyusf/exception.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#include "main.h" -#include "cpu.h" - -#include "usf_internal.h" - -void CheckInterrupts ( usf_state_t * state ) { - - MI_INTR_REG &= ~MI_INTR_AI; - MI_INTR_REG |= (state->AudioIntrReg & MI_INTR_AI); -#ifdef DEBUG_INFO - if (MI_INTR_REG) - fprintf(state->debug_log, "Interrupt %d - ", MI_INTR_REG); -#endif - if ((MI_INTR_MASK_REG & MI_INTR_REG) != 0) { -#ifdef DEBUG_INFO - fprintf(state->debug_log, "triggered\n"); -#endif - FAKE_CAUSE_REGISTER |= CAUSE_IP2; - } else { -#ifdef DEBUG_INFO - if (MI_INTR_REG) - fprintf(state->debug_log, "masked\n"); -#endif - FAKE_CAUSE_REGISTER &= ~CAUSE_IP2; - } - - if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { return; } - if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { return; } - if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { return; } - - if (( STATUS_REGISTER & FAKE_CAUSE_REGISTER & 0xFF00) != 0) { - if (!state->CPU_Action->DoInterrupt) { - state->CPU_Action->DoSomething = 1; - state->CPU_Action->DoInterrupt = 1; - } - } -} - -void DoAddressError ( usf_state_t * state, uint32_t DelaySlot, uint32_t BadVaddr, uint32_t FromRead) { - if (FromRead) { - CAUSE_REGISTER = EXC_RADE; - } else { - CAUSE_REGISTER = EXC_WADE; - } - BAD_VADDR_REGISTER = BadVaddr; - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER = state->PROGRAM_COUNTER - 4; - } else { - EPC_REGISTER = state->PROGRAM_COUNTER; - } - STATUS_REGISTER |= STATUS_EXL; - state->PROGRAM_COUNTER = 0x80000180; -} - -void DoBreakException ( usf_state_t * state, uint32_t DelaySlot) { - CAUSE_REGISTER = EXC_BREAK; - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER = state->PROGRAM_COUNTER - 4; - } else { - EPC_REGISTER = state->PROGRAM_COUNTER; - } - STATUS_REGISTER |= STATUS_EXL; - state->PROGRAM_COUNTER = 0x80000180; -} - -void DoCopUnusableException ( usf_state_t * state, uint32_t DelaySlot, uint32_t Coprocessor ) { - CAUSE_REGISTER = EXC_CPU; - if (Coprocessor == 1) { CAUSE_REGISTER |= 0x10000000; } - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER = state->PROGRAM_COUNTER - 4; - } else { - EPC_REGISTER = state->PROGRAM_COUNTER; - } - STATUS_REGISTER |= STATUS_EXL; - state->PROGRAM_COUNTER = 0x80000180; -} - -void DoIntrException ( usf_state_t * state, uint32_t DelaySlot ) { - - if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { return; } - if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { return; } - if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { return; } - CAUSE_REGISTER = FAKE_CAUSE_REGISTER; - CAUSE_REGISTER |= EXC_INT; - EPC_REGISTER = state->PROGRAM_COUNTER; - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER -= 4; - } - STATUS_REGISTER |= STATUS_EXL; - state->PROGRAM_COUNTER = 0x80000180; -} - -void DoTLBMiss ( usf_state_t * state, uint32_t DelaySlot, uint32_t BadVaddr ) { - - CAUSE_REGISTER = EXC_RMISS; - BAD_VADDR_REGISTER = BadVaddr; - CONTEXT_REGISTER &= 0xFF80000F; - CONTEXT_REGISTER |= (BadVaddr >> 9) & 0x007FFFF0; - ENTRYHI_REGISTER = (BadVaddr & 0xFFFFE000); - if ((STATUS_REGISTER & STATUS_EXL) == 0) { - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER = state->PROGRAM_COUNTER - 4; - } else { - EPC_REGISTER = state->PROGRAM_COUNTER; - } - if (AddressDefined(state, BadVaddr)) { - state->PROGRAM_COUNTER = 0x80000180; - } else { - state->PROGRAM_COUNTER = 0x80000000; - } - STATUS_REGISTER |= STATUS_EXL; - } else { - state->PROGRAM_COUNTER = 0x80000180; - } -} - -void DoSysCallException ( usf_state_t * state, uint32_t DelaySlot) { - CAUSE_REGISTER = EXC_SYSCALL; - if (DelaySlot) { - CAUSE_REGISTER |= CAUSE_BD; - EPC_REGISTER = state->PROGRAM_COUNTER - 4; - } else { - EPC_REGISTER = state->PROGRAM_COUNTER; - } - STATUS_REGISTER |= STATUS_EXL; - state->PROGRAM_COUNTER = 0x80000180; -} diff --git a/Frameworks/lazyusf/lazyusf/exception.h b/Frameworks/lazyusf/lazyusf/exception.h deleted file mode 100644 index 7ee97d58e..000000000 --- a/Frameworks/lazyusf/lazyusf/exception.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#define EXC_CODE(x) ((x)<<2) -#define EXC_INT EXC_CODE(0) /* interrupt */ -#define EXC_MOD EXC_CODE(1) /* TLB mod */ -#define EXC_RMISS EXC_CODE(2) /* Read TLB Miss */ -#define EXC_WMISS EXC_CODE(3) /* Write TLB Miss */ -#define EXC_RADE EXC_CODE(4) /* Read Address Error */ -#define EXC_WADE EXC_CODE(5) /* Write Address Error */ -#define EXC_IBE EXC_CODE(6) /* Instruction Bus Error */ -#define EXC_DBE EXC_CODE(7) /* Data Bus Error */ -#define EXC_SYSCALL EXC_CODE(8) /* SYSCALL */ -#define EXC_BREAK EXC_CODE(9) /* BREAKpoint */ -#define EXC_II EXC_CODE(10)/* Illegal Instruction */ -#define EXC_CPU EXC_CODE(11)/* CoProcessor Unusable */ -#define EXC_OV EXC_CODE(12)/* OVerflow */ -#define EXC_TRAP EXC_CODE(13)/* Trap exception */ -#define EXC_VCEI EXC_CODE(14)/* Virt. Coherency on Inst. fetch */ -#define EXC_FPE EXC_CODE(15)/* Floating Point Exception */ -#define EXC_WATCH EXC_CODE(23)/* Watchpoint reference */ -#define EXC_VCED EXC_CODE(31)/* Virt. Coherency on data read */ - -#define Exception_Name(Except)\ - (Except) == EXC_INT ? "interrupt" :\ - (Except) == EXC_MOD ? "TLB mod" :\ - (Except) == EXC_RMISS ? "Read TLB Miss" :\ - (Except) == EXC_WMISS ? "Write TLB Miss" :\ - (Except) == EXC_RADE ? "Read Address Error" :\ - (Except) == EXC_WADE ? "Write Address Error" :\ - (Except) == EXC_IBE ? "Instruction Bus Error" :\ - (Except) == EXC_DBE ? "Data Bus Error" :\ - (Except) == EXC_SYSCALL ? "SYSCALL" :\ - (Except) == EXC_BREAK ? "Break" :\ - (Except) == EXC_II ? "Illegal Instruction" :\ - (Except) == EXC_CPU ? "CoProcessor Unusable" :\ - (Except) == EXC_OV ? "OVerflow" :\ - (Except) == EXC_TRAP ? "Trap exception" :\ - (Except) == EXC_VCEI ? "Virt. Coherency on Inst. fetch" :\ - (Except) == EXC_FPE ? "Floating Point Exception" :\ - (Except) == EXC_WATCH ? "Watchpoint reference" :\ - (Except) == EXC_VCED ? "Virt. Coherency on data read" :\ - "Unkown" - -void AiCheckInterrupts ( usf_state_t * ); -void CheckInterrupts ( usf_state_t * ); -void DoAddressError ( usf_state_t *, uint32_t DelaySlot, uint32_t BadVaddr, uint32_t FromRead ); -void DoBreakException ( usf_state_t *, uint32_t DelaySlot ); -void DoCopUnusableException ( usf_state_t *, uint32_t DelaySlot, uint32_t Coprocessor ); -void DoIntrException ( usf_state_t *, uint32_t DelaySlot ); -void DoTLBMiss ( usf_state_t *, uint32_t DelaySlot, uint32_t BadVaddr ); -void DoSysCallException ( usf_state_t *, uint32_t DelaySlot); - diff --git a/Frameworks/lazyusf/lazyusf/interpreter_cpu.c b/Frameworks/lazyusf/lazyusf/interpreter_cpu.c deleted file mode 100644 index 75b2f73f9..000000000 --- a/Frameworks/lazyusf/lazyusf/interpreter_cpu.c +++ /dev/null @@ -1,799 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#include -#include "main.h" -#include "cpu.h" -#include "usf.h" -#include "memory.h" -#include "cpu_hle.h" - -#include "usf_internal.h" - -#include - -void (* R4300i_Opcode[64])(usf_state_t *); -void (* R4300i_Special[64])(usf_state_t *); -void (* R4300i_Regimm[32])(usf_state_t *); -void (* R4300i_CoP0[32])(usf_state_t *); -void (* R4300i_CoP0_Function[64])(usf_state_t *); -void (* R4300i_CoP1[32])(usf_state_t *); -void (* R4300i_CoP1_BC[32])(usf_state_t *); -void (* R4300i_CoP1_S[64])(usf_state_t *); -void (* R4300i_CoP1_D[64])(usf_state_t *); -void (* R4300i_CoP1_W[64])(usf_state_t *); -void (* R4300i_CoP1_L[64])(usf_state_t *); - -void R4300i_opcode_SPECIAL (usf_state_t * state) { - R4300i_Special[ state->Opcode.u.e.funct ](state); -} - -void R4300i_opcode_REGIMM (usf_state_t * state) { - R4300i_Regimm[ state->Opcode.u.b.rt ](state); -} - -void R4300i_opcode_COP0 (usf_state_t * state) { - R4300i_CoP0[ state->Opcode.u.b.rs ](state); -} - -void R4300i_opcode_COP0_CO (usf_state_t * state) { - R4300i_CoP0_Function[ state->Opcode.u.e.funct ](state); -} - -void R4300i_opcode_COP1 (usf_state_t * state) { - R4300i_CoP1[ state->Opcode.u.f.fmt ](state); -} - -void R4300i_opcode_COP1_BC (usf_state_t * state) { - R4300i_CoP1_BC[ state->Opcode.u.f.ft ](state); -} - -void R4300i_opcode_COP1_S (usf_state_t * state) { - // controlfp(RoundingModel); - R4300i_CoP1_S[ state->Opcode.u.e.funct ](state); -} - -void R4300i_opcode_COP1_D (usf_state_t * state) { - // controlfp(RoundingModel); - R4300i_CoP1_D[ state->Opcode.u.e.funct ](state); -} - -void R4300i_opcode_COP1_W (usf_state_t * state) { - R4300i_CoP1_W[ state->Opcode.u.e.funct ](state); -} - -void R4300i_opcode_COP1_L (usf_state_t * state) { - R4300i_CoP1_L[ state->Opcode.u.e.funct ](state); -} - - -void BuildInterpreter (usf_state_t * state) { - (void)state; - R4300i_Opcode[ 0] = R4300i_opcode_SPECIAL; - R4300i_Opcode[ 1] = R4300i_opcode_REGIMM; - R4300i_Opcode[ 2] = r4300i_J; - R4300i_Opcode[ 3] = r4300i_JAL; - R4300i_Opcode[ 4] = r4300i_BEQ; - R4300i_Opcode[ 5] = r4300i_BNE; - R4300i_Opcode[ 6] = r4300i_BLEZ; - R4300i_Opcode[ 7] = r4300i_BGTZ; - R4300i_Opcode[ 8] = r4300i_ADDI; - R4300i_Opcode[ 9] = r4300i_ADDIU; - R4300i_Opcode[10] = r4300i_SLTI; - R4300i_Opcode[11] = r4300i_SLTIU; - R4300i_Opcode[12] = r4300i_ANDI; - R4300i_Opcode[13] = r4300i_ORI; - R4300i_Opcode[14] = r4300i_XORI; - R4300i_Opcode[15] = r4300i_LUI; - R4300i_Opcode[16] = R4300i_opcode_COP0; - R4300i_Opcode[17] = R4300i_opcode_COP1; - R4300i_Opcode[18] = R4300i_UnknownOpcode; - R4300i_Opcode[19] = R4300i_UnknownOpcode; - R4300i_Opcode[20] = r4300i_BEQL; - R4300i_Opcode[21] = r4300i_BNEL; - R4300i_Opcode[22] = r4300i_BLEZL; - R4300i_Opcode[23] = r4300i_BGTZL; - R4300i_Opcode[24] = R4300i_UnknownOpcode; - R4300i_Opcode[25] = r4300i_DADDIU; - R4300i_Opcode[26] = r4300i_LDL; - R4300i_Opcode[27] = r4300i_LDR; - R4300i_Opcode[28] = R4300i_UnknownOpcode; - R4300i_Opcode[29] = R4300i_UnknownOpcode; - R4300i_Opcode[30] = R4300i_UnknownOpcode; - R4300i_Opcode[31] = R4300i_UnknownOpcode; - R4300i_Opcode[32] = r4300i_LB; - R4300i_Opcode[33] = r4300i_LH; - R4300i_Opcode[34] = r4300i_LWL; - R4300i_Opcode[35] = r4300i_LW; - R4300i_Opcode[36] = r4300i_LBU; - R4300i_Opcode[37] = r4300i_LHU; - R4300i_Opcode[38] = r4300i_LWR; - R4300i_Opcode[39] = r4300i_LWU; - R4300i_Opcode[40] = r4300i_SB; - R4300i_Opcode[41] = r4300i_SH; - R4300i_Opcode[42] = r4300i_SWL; - R4300i_Opcode[43] = r4300i_SW; - R4300i_Opcode[44] = r4300i_SDL; - R4300i_Opcode[45] = r4300i_SDR; - R4300i_Opcode[46] = r4300i_SWR; - R4300i_Opcode[47] = r4300i_CACHE; - R4300i_Opcode[48] = r4300i_LL; - R4300i_Opcode[49] = r4300i_LWC1; - R4300i_Opcode[50] = R4300i_UnknownOpcode; - R4300i_Opcode[51] = R4300i_UnknownOpcode; - R4300i_Opcode[52] = R4300i_UnknownOpcode; - R4300i_Opcode[53] = r4300i_LDC1; - R4300i_Opcode[54] = R4300i_UnknownOpcode; - R4300i_Opcode[55] = r4300i_LD; - R4300i_Opcode[56] = r4300i_SC; - R4300i_Opcode[57] = r4300i_SWC1; - R4300i_Opcode[58] = R4300i_UnknownOpcode; - R4300i_Opcode[59] = R4300i_UnknownOpcode; - R4300i_Opcode[60] = R4300i_UnknownOpcode; - R4300i_Opcode[61] = r4300i_SDC1; - R4300i_Opcode[62] = R4300i_UnknownOpcode; - R4300i_Opcode[63] = r4300i_SD; - - R4300i_Special[ 0] = r4300i_SPECIAL_SLL; - R4300i_Special[ 1] = R4300i_UnknownOpcode; - R4300i_Special[ 2] = r4300i_SPECIAL_SRL; - R4300i_Special[ 3] = r4300i_SPECIAL_SRA; - R4300i_Special[ 4] = r4300i_SPECIAL_SLLV; - R4300i_Special[ 5] = R4300i_UnknownOpcode; - R4300i_Special[ 6] = r4300i_SPECIAL_SRLV; - R4300i_Special[ 7] = r4300i_SPECIAL_SRAV; - R4300i_Special[ 8] = r4300i_SPECIAL_JR; - R4300i_Special[ 9] = r4300i_SPECIAL_JALR; - R4300i_Special[10] = R4300i_UnknownOpcode; - R4300i_Special[11] = R4300i_UnknownOpcode; - R4300i_Special[12] = r4300i_SPECIAL_SYSCALL; - R4300i_Special[13] = r4300i_SPECIAL_BREAK; - R4300i_Special[14] = R4300i_UnknownOpcode; - R4300i_Special[15] = r4300i_SPECIAL_SYNC; - R4300i_Special[16] = r4300i_SPECIAL_MFHI; - R4300i_Special[17] = r4300i_SPECIAL_MTHI; - R4300i_Special[18] = r4300i_SPECIAL_MFLO; - R4300i_Special[19] = r4300i_SPECIAL_MTLO; - R4300i_Special[20] = r4300i_SPECIAL_DSLLV; - R4300i_Special[21] = R4300i_UnknownOpcode; - R4300i_Special[22] = r4300i_SPECIAL_DSRLV; - R4300i_Special[23] = r4300i_SPECIAL_DSRAV; - R4300i_Special[24] = r4300i_SPECIAL_MULT; - R4300i_Special[25] = r4300i_SPECIAL_MULTU; - R4300i_Special[26] = r4300i_SPECIAL_DIV; - R4300i_Special[27] = r4300i_SPECIAL_DIVU; - R4300i_Special[28] = r4300i_SPECIAL_DMULT; - R4300i_Special[29] = r4300i_SPECIAL_DMULTU; - R4300i_Special[30] = r4300i_SPECIAL_DDIV; - R4300i_Special[31] = r4300i_SPECIAL_DDIVU; - R4300i_Special[32] = r4300i_SPECIAL_ADD; - R4300i_Special[33] = r4300i_SPECIAL_ADDU; - R4300i_Special[34] = r4300i_SPECIAL_SUB; - R4300i_Special[35] = r4300i_SPECIAL_SUBU; - R4300i_Special[36] = r4300i_SPECIAL_AND; - R4300i_Special[37] = r4300i_SPECIAL_OR; - R4300i_Special[38] = r4300i_SPECIAL_XOR; - R4300i_Special[39] = r4300i_SPECIAL_NOR; - R4300i_Special[40] = R4300i_UnknownOpcode; - R4300i_Special[41] = R4300i_UnknownOpcode; - R4300i_Special[42] = r4300i_SPECIAL_SLT; - R4300i_Special[43] = r4300i_SPECIAL_SLTU; - R4300i_Special[44] = r4300i_SPECIAL_DADD; - R4300i_Special[45] = r4300i_SPECIAL_DADDU; - R4300i_Special[46] = r4300i_SPECIAL_DSUB; - R4300i_Special[47] = r4300i_SPECIAL_DSUBU; - R4300i_Special[48] = R4300i_UnknownOpcode; - R4300i_Special[49] = R4300i_UnknownOpcode; - R4300i_Special[50] = R4300i_UnknownOpcode; - R4300i_Special[51] = R4300i_UnknownOpcode; - R4300i_Special[52] = r4300i_SPECIAL_TEQ; - R4300i_Special[53] = R4300i_UnknownOpcode; - R4300i_Special[54] = R4300i_UnknownOpcode; - R4300i_Special[55] = R4300i_UnknownOpcode; - R4300i_Special[56] = r4300i_SPECIAL_DSLL; - R4300i_Special[57] = R4300i_UnknownOpcode; - R4300i_Special[58] = r4300i_SPECIAL_DSRL; - R4300i_Special[59] = r4300i_SPECIAL_DSRA; - R4300i_Special[60] = r4300i_SPECIAL_DSLL32; - R4300i_Special[61] = R4300i_UnknownOpcode; - R4300i_Special[62] = r4300i_SPECIAL_DSRL32; - R4300i_Special[63] = r4300i_SPECIAL_DSRA32; - - R4300i_Regimm[ 0] = r4300i_REGIMM_BLTZ; - R4300i_Regimm[ 1] = r4300i_REGIMM_BGEZ; - R4300i_Regimm[ 2] = r4300i_REGIMM_BLTZL; - R4300i_Regimm[ 3] = r4300i_REGIMM_BGEZL; - R4300i_Regimm[ 4] = R4300i_UnknownOpcode; - R4300i_Regimm[ 5] = R4300i_UnknownOpcode; - R4300i_Regimm[ 6] = R4300i_UnknownOpcode; - R4300i_Regimm[ 7] = R4300i_UnknownOpcode; - R4300i_Regimm[ 8] = R4300i_UnknownOpcode; - R4300i_Regimm[ 9] = R4300i_UnknownOpcode; - R4300i_Regimm[10] = R4300i_UnknownOpcode; - R4300i_Regimm[11] = R4300i_UnknownOpcode; - R4300i_Regimm[12] = R4300i_UnknownOpcode; - R4300i_Regimm[13] = R4300i_UnknownOpcode; - R4300i_Regimm[14] = R4300i_UnknownOpcode; - R4300i_Regimm[15] = R4300i_UnknownOpcode; - R4300i_Regimm[16] = r4300i_REGIMM_BLTZAL; - R4300i_Regimm[17] = r4300i_REGIMM_BGEZAL; - R4300i_Regimm[18] = R4300i_UnknownOpcode; - R4300i_Regimm[19] = R4300i_UnknownOpcode; - R4300i_Regimm[20] = R4300i_UnknownOpcode; - R4300i_Regimm[21] = R4300i_UnknownOpcode; - R4300i_Regimm[22] = R4300i_UnknownOpcode; - R4300i_Regimm[23] = R4300i_UnknownOpcode; - R4300i_Regimm[24] = R4300i_UnknownOpcode; - R4300i_Regimm[25] = R4300i_UnknownOpcode; - R4300i_Regimm[26] = R4300i_UnknownOpcode; - R4300i_Regimm[27] = R4300i_UnknownOpcode; - R4300i_Regimm[28] = R4300i_UnknownOpcode; - R4300i_Regimm[29] = R4300i_UnknownOpcode; - R4300i_Regimm[30] = R4300i_UnknownOpcode; - R4300i_Regimm[31] = R4300i_UnknownOpcode; - - R4300i_CoP0[ 0] = r4300i_COP0_MF; - R4300i_CoP0[ 1] = R4300i_UnknownOpcode; - R4300i_CoP0[ 2] = R4300i_UnknownOpcode; - R4300i_CoP0[ 3] = R4300i_UnknownOpcode; - R4300i_CoP0[ 4] = r4300i_COP0_MT; - R4300i_CoP0[ 5] = R4300i_UnknownOpcode; - R4300i_CoP0[ 6] = R4300i_UnknownOpcode; - R4300i_CoP0[ 7] = R4300i_UnknownOpcode; - R4300i_CoP0[ 8] = R4300i_UnknownOpcode; - R4300i_CoP0[ 9] = R4300i_UnknownOpcode; - R4300i_CoP0[10] = R4300i_UnknownOpcode; - R4300i_CoP0[11] = R4300i_UnknownOpcode; - R4300i_CoP0[12] = R4300i_UnknownOpcode; - R4300i_CoP0[13] = R4300i_UnknownOpcode; - R4300i_CoP0[14] = R4300i_UnknownOpcode; - R4300i_CoP0[15] = R4300i_UnknownOpcode; - R4300i_CoP0[16] = R4300i_opcode_COP0_CO; - R4300i_CoP0[17] = R4300i_opcode_COP0_CO; - R4300i_CoP0[18] = R4300i_opcode_COP0_CO; - R4300i_CoP0[19] = R4300i_opcode_COP0_CO; - R4300i_CoP0[20] = R4300i_opcode_COP0_CO; - R4300i_CoP0[21] = R4300i_opcode_COP0_CO; - R4300i_CoP0[22] = R4300i_opcode_COP0_CO; - R4300i_CoP0[23] = R4300i_opcode_COP0_CO; - R4300i_CoP0[24] = R4300i_opcode_COP0_CO; - R4300i_CoP0[25] = R4300i_opcode_COP0_CO; - R4300i_CoP0[26] = R4300i_opcode_COP0_CO; - R4300i_CoP0[27] = R4300i_opcode_COP0_CO; - R4300i_CoP0[28] = R4300i_opcode_COP0_CO; - R4300i_CoP0[29] = R4300i_opcode_COP0_CO; - R4300i_CoP0[30] = R4300i_opcode_COP0_CO; - R4300i_CoP0[31] = R4300i_opcode_COP0_CO; - - R4300i_CoP0_Function[ 0] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[ 1] = r4300i_COP0_CO_TLBR; - R4300i_CoP0_Function[ 2] = r4300i_COP0_CO_TLBWI; - R4300i_CoP0_Function[ 3] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[ 4] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[ 5] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[ 6] = r4300i_COP0_CO_TLBWR; - R4300i_CoP0_Function[ 7] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[ 8] = r4300i_COP0_CO_TLBP; - R4300i_CoP0_Function[ 9] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[10] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[11] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[12] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[13] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[14] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[15] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[16] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[17] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[18] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[19] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[20] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[21] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[22] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[23] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[24] = r4300i_COP0_CO_ERET; - R4300i_CoP0_Function[25] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[26] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[27] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[28] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[29] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[30] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[31] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[32] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[33] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[34] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[35] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[36] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[37] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[38] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[39] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[40] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[41] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[42] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[43] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[44] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[45] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[46] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[47] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[48] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[49] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[50] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[51] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[52] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[53] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[54] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[55] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[56] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[57] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[58] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[59] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[60] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[61] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[62] = R4300i_UnknownOpcode; - R4300i_CoP0_Function[63] = R4300i_UnknownOpcode; - - R4300i_CoP1[ 0] = r4300i_COP1_MF; - R4300i_CoP1[ 1] = r4300i_COP1_DMF; - R4300i_CoP1[ 2] = r4300i_COP1_CF; - R4300i_CoP1[ 3] = R4300i_UnknownOpcode; - R4300i_CoP1[ 4] = r4300i_COP1_MT; - R4300i_CoP1[ 5] = r4300i_COP1_DMT; - R4300i_CoP1[ 6] = r4300i_COP1_CT; - R4300i_CoP1[ 7] = R4300i_UnknownOpcode; - R4300i_CoP1[ 8] = R4300i_opcode_COP1_BC; - R4300i_CoP1[ 9] = R4300i_UnknownOpcode; - R4300i_CoP1[10] = R4300i_UnknownOpcode; - R4300i_CoP1[11] = R4300i_UnknownOpcode; - R4300i_CoP1[12] = R4300i_UnknownOpcode; - R4300i_CoP1[13] = R4300i_UnknownOpcode; - R4300i_CoP1[14] = R4300i_UnknownOpcode; - R4300i_CoP1[15] = R4300i_UnknownOpcode; - R4300i_CoP1[16] = R4300i_opcode_COP1_S; - R4300i_CoP1[17] = R4300i_opcode_COP1_D; - R4300i_CoP1[18] = R4300i_UnknownOpcode; - R4300i_CoP1[19] = R4300i_UnknownOpcode; - R4300i_CoP1[20] = R4300i_opcode_COP1_W; - R4300i_CoP1[21] = R4300i_opcode_COP1_L; - R4300i_CoP1[22] = R4300i_UnknownOpcode; - R4300i_CoP1[23] = R4300i_UnknownOpcode; - R4300i_CoP1[24] = R4300i_UnknownOpcode; - R4300i_CoP1[25] = R4300i_UnknownOpcode; - R4300i_CoP1[26] = R4300i_UnknownOpcode; - R4300i_CoP1[27] = R4300i_UnknownOpcode; - R4300i_CoP1[28] = R4300i_UnknownOpcode; - R4300i_CoP1[29] = R4300i_UnknownOpcode; - R4300i_CoP1[30] = R4300i_UnknownOpcode; - R4300i_CoP1[31] = R4300i_UnknownOpcode; - - R4300i_CoP1_BC[ 0] = r4300i_COP1_BCF; - R4300i_CoP1_BC[ 1] = r4300i_COP1_BCT; - R4300i_CoP1_BC[ 2] = r4300i_COP1_BCFL; - R4300i_CoP1_BC[ 3] = r4300i_COP1_BCTL; - R4300i_CoP1_BC[ 4] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[ 5] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[ 6] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[ 7] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[ 8] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[ 9] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[10] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[11] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[12] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[13] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[14] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[15] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[16] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[17] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[18] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[19] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[20] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[21] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[22] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[23] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[24] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[25] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[26] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[27] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[28] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[29] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[30] = R4300i_UnknownOpcode; - R4300i_CoP1_BC[31] = R4300i_UnknownOpcode; - - R4300i_CoP1_S[ 0] = r4300i_COP1_S_ADD; - R4300i_CoP1_S[ 1] = r4300i_COP1_S_SUB; - R4300i_CoP1_S[ 2] = r4300i_COP1_S_MUL; - R4300i_CoP1_S[ 3] = r4300i_COP1_S_DIV; - R4300i_CoP1_S[ 4] = r4300i_COP1_S_SQRT; - R4300i_CoP1_S[ 5] = r4300i_COP1_S_ABS; - R4300i_CoP1_S[ 6] = r4300i_COP1_S_MOV; - R4300i_CoP1_S[ 7] = r4300i_COP1_S_NEG; - R4300i_CoP1_S[ 8] = R4300i_UnknownOpcode; - R4300i_CoP1_S[ 9] = r4300i_COP1_S_TRUNC_L; - R4300i_CoP1_S[10] = r4300i_COP1_S_CEIL_L; //added by Witten - R4300i_CoP1_S[11] = r4300i_COP1_S_FLOOR_L; //added by Witten - R4300i_CoP1_S[12] = r4300i_COP1_S_ROUND_W; - R4300i_CoP1_S[13] = r4300i_COP1_S_TRUNC_W; - R4300i_CoP1_S[14] = r4300i_COP1_S_CEIL_W; //added by Witten - R4300i_CoP1_S[15] = r4300i_COP1_S_FLOOR_W; - R4300i_CoP1_S[16] = R4300i_UnknownOpcode; - R4300i_CoP1_S[17] = R4300i_UnknownOpcode; - R4300i_CoP1_S[18] = R4300i_UnknownOpcode; - R4300i_CoP1_S[19] = R4300i_UnknownOpcode; - R4300i_CoP1_S[20] = R4300i_UnknownOpcode; - R4300i_CoP1_S[21] = R4300i_UnknownOpcode; - R4300i_CoP1_S[22] = R4300i_UnknownOpcode; - R4300i_CoP1_S[23] = R4300i_UnknownOpcode; - R4300i_CoP1_S[24] = R4300i_UnknownOpcode; - R4300i_CoP1_S[25] = R4300i_UnknownOpcode; - R4300i_CoP1_S[26] = R4300i_UnknownOpcode; - R4300i_CoP1_S[27] = R4300i_UnknownOpcode; - R4300i_CoP1_S[28] = R4300i_UnknownOpcode; - R4300i_CoP1_S[29] = R4300i_UnknownOpcode; - R4300i_CoP1_S[30] = R4300i_UnknownOpcode; - R4300i_CoP1_S[31] = R4300i_UnknownOpcode; - R4300i_CoP1_S[32] = R4300i_UnknownOpcode; - R4300i_CoP1_S[33] = r4300i_COP1_S_CVT_D; - R4300i_CoP1_S[34] = R4300i_UnknownOpcode; - R4300i_CoP1_S[35] = R4300i_UnknownOpcode; - R4300i_CoP1_S[36] = r4300i_COP1_S_CVT_W; - R4300i_CoP1_S[37] = r4300i_COP1_S_CVT_L; - R4300i_CoP1_S[38] = R4300i_UnknownOpcode; - R4300i_CoP1_S[39] = R4300i_UnknownOpcode; - R4300i_CoP1_S[40] = R4300i_UnknownOpcode; - R4300i_CoP1_S[41] = R4300i_UnknownOpcode; - R4300i_CoP1_S[42] = R4300i_UnknownOpcode; - R4300i_CoP1_S[43] = R4300i_UnknownOpcode; - R4300i_CoP1_S[44] = R4300i_UnknownOpcode; - R4300i_CoP1_S[45] = R4300i_UnknownOpcode; - R4300i_CoP1_S[46] = R4300i_UnknownOpcode; - R4300i_CoP1_S[47] = R4300i_UnknownOpcode; - R4300i_CoP1_S[48] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[49] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[50] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[51] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[52] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[53] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[54] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[55] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[56] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[57] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[58] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[59] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[60] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[61] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[62] = r4300i_COP1_S_CMP; - R4300i_CoP1_S[63] = r4300i_COP1_S_CMP; - - R4300i_CoP1_D[ 0] = r4300i_COP1_D_ADD; - R4300i_CoP1_D[ 1] = r4300i_COP1_D_SUB; - R4300i_CoP1_D[ 2] = r4300i_COP1_D_MUL; - R4300i_CoP1_D[ 3] = r4300i_COP1_D_DIV; - R4300i_CoP1_D[ 4] = r4300i_COP1_D_SQRT; - R4300i_CoP1_D[ 5] = r4300i_COP1_D_ABS; - R4300i_CoP1_D[ 6] = r4300i_COP1_D_MOV; - R4300i_CoP1_D[ 7] = r4300i_COP1_D_NEG; - R4300i_CoP1_D[ 8] = R4300i_UnknownOpcode; - R4300i_CoP1_D[ 9] = r4300i_COP1_D_TRUNC_L; //added by Witten - R4300i_CoP1_D[10] = r4300i_COP1_D_CEIL_L; //added by Witten - R4300i_CoP1_D[11] = r4300i_COP1_D_FLOOR_L; //added by Witten - R4300i_CoP1_D[12] = r4300i_COP1_D_ROUND_W; - R4300i_CoP1_D[13] = r4300i_COP1_D_TRUNC_W; - R4300i_CoP1_D[14] = r4300i_COP1_D_CEIL_W; //added by Witten - R4300i_CoP1_D[15] = r4300i_COP1_D_FLOOR_W; //added by Witten - R4300i_CoP1_D[16] = R4300i_UnknownOpcode; - R4300i_CoP1_D[17] = R4300i_UnknownOpcode; - R4300i_CoP1_D[18] = R4300i_UnknownOpcode; - R4300i_CoP1_D[19] = R4300i_UnknownOpcode; - R4300i_CoP1_D[20] = R4300i_UnknownOpcode; - R4300i_CoP1_D[21] = R4300i_UnknownOpcode; - R4300i_CoP1_D[22] = R4300i_UnknownOpcode; - R4300i_CoP1_D[23] = R4300i_UnknownOpcode; - R4300i_CoP1_D[24] = R4300i_UnknownOpcode; - R4300i_CoP1_D[25] = R4300i_UnknownOpcode; - R4300i_CoP1_D[26] = R4300i_UnknownOpcode; - R4300i_CoP1_D[27] = R4300i_UnknownOpcode; - R4300i_CoP1_D[28] = R4300i_UnknownOpcode; - R4300i_CoP1_D[29] = R4300i_UnknownOpcode; - R4300i_CoP1_D[30] = R4300i_UnknownOpcode; - R4300i_CoP1_D[31] = R4300i_UnknownOpcode; - R4300i_CoP1_D[32] = r4300i_COP1_D_CVT_S; - R4300i_CoP1_D[33] = R4300i_UnknownOpcode; - R4300i_CoP1_D[34] = R4300i_UnknownOpcode; - R4300i_CoP1_D[35] = R4300i_UnknownOpcode; - R4300i_CoP1_D[36] = r4300i_COP1_D_CVT_W; - R4300i_CoP1_D[37] = r4300i_COP1_D_CVT_L; - R4300i_CoP1_D[38] = R4300i_UnknownOpcode; - R4300i_CoP1_D[39] = R4300i_UnknownOpcode; - R4300i_CoP1_D[40] = R4300i_UnknownOpcode; - R4300i_CoP1_D[41] = R4300i_UnknownOpcode; - R4300i_CoP1_D[42] = R4300i_UnknownOpcode; - R4300i_CoP1_D[43] = R4300i_UnknownOpcode; - R4300i_CoP1_D[44] = R4300i_UnknownOpcode; - R4300i_CoP1_D[45] = R4300i_UnknownOpcode; - R4300i_CoP1_D[46] = R4300i_UnknownOpcode; - R4300i_CoP1_D[47] = R4300i_UnknownOpcode; - R4300i_CoP1_D[48] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[49] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[50] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[51] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[52] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[53] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[54] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[55] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[56] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[57] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[58] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[59] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[60] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[61] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[62] = r4300i_COP1_D_CMP; - R4300i_CoP1_D[63] = r4300i_COP1_D_CMP; - - R4300i_CoP1_W[ 0] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 1] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 2] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 3] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 4] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 5] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 6] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 7] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 8] = R4300i_UnknownOpcode; - R4300i_CoP1_W[ 9] = R4300i_UnknownOpcode; - R4300i_CoP1_W[10] = R4300i_UnknownOpcode; - R4300i_CoP1_W[11] = R4300i_UnknownOpcode; - R4300i_CoP1_W[12] = R4300i_UnknownOpcode; - R4300i_CoP1_W[13] = R4300i_UnknownOpcode; - R4300i_CoP1_W[14] = R4300i_UnknownOpcode; - R4300i_CoP1_W[15] = R4300i_UnknownOpcode; - R4300i_CoP1_W[16] = R4300i_UnknownOpcode; - R4300i_CoP1_W[17] = R4300i_UnknownOpcode; - R4300i_CoP1_W[18] = R4300i_UnknownOpcode; - R4300i_CoP1_W[19] = R4300i_UnknownOpcode; - R4300i_CoP1_W[20] = R4300i_UnknownOpcode; - R4300i_CoP1_W[21] = R4300i_UnknownOpcode; - R4300i_CoP1_W[22] = R4300i_UnknownOpcode; - R4300i_CoP1_W[23] = R4300i_UnknownOpcode; - R4300i_CoP1_W[24] = R4300i_UnknownOpcode; - R4300i_CoP1_W[25] = R4300i_UnknownOpcode; - R4300i_CoP1_W[26] = R4300i_UnknownOpcode; - R4300i_CoP1_W[27] = R4300i_UnknownOpcode; - R4300i_CoP1_W[28] = R4300i_UnknownOpcode; - R4300i_CoP1_W[29] = R4300i_UnknownOpcode; - R4300i_CoP1_W[30] = R4300i_UnknownOpcode; - R4300i_CoP1_W[31] = R4300i_UnknownOpcode; - R4300i_CoP1_W[32] = r4300i_COP1_W_CVT_S; - R4300i_CoP1_W[33] = r4300i_COP1_W_CVT_D; - R4300i_CoP1_W[34] = R4300i_UnknownOpcode; - R4300i_CoP1_W[35] = R4300i_UnknownOpcode; - R4300i_CoP1_W[36] = R4300i_UnknownOpcode; - R4300i_CoP1_W[37] = R4300i_UnknownOpcode; - R4300i_CoP1_W[38] = R4300i_UnknownOpcode; - R4300i_CoP1_W[39] = R4300i_UnknownOpcode; - R4300i_CoP1_W[40] = R4300i_UnknownOpcode; - R4300i_CoP1_W[41] = R4300i_UnknownOpcode; - R4300i_CoP1_W[42] = R4300i_UnknownOpcode; - R4300i_CoP1_W[43] = R4300i_UnknownOpcode; - R4300i_CoP1_W[44] = R4300i_UnknownOpcode; - R4300i_CoP1_W[45] = R4300i_UnknownOpcode; - R4300i_CoP1_W[46] = R4300i_UnknownOpcode; - R4300i_CoP1_W[47] = R4300i_UnknownOpcode; - R4300i_CoP1_W[48] = R4300i_UnknownOpcode; - R4300i_CoP1_W[49] = R4300i_UnknownOpcode; - R4300i_CoP1_W[50] = R4300i_UnknownOpcode; - R4300i_CoP1_W[51] = R4300i_UnknownOpcode; - R4300i_CoP1_W[52] = R4300i_UnknownOpcode; - R4300i_CoP1_W[53] = R4300i_UnknownOpcode; - R4300i_CoP1_W[54] = R4300i_UnknownOpcode; - R4300i_CoP1_W[55] = R4300i_UnknownOpcode; - R4300i_CoP1_W[56] = R4300i_UnknownOpcode; - R4300i_CoP1_W[57] = R4300i_UnknownOpcode; - R4300i_CoP1_W[58] = R4300i_UnknownOpcode; - R4300i_CoP1_W[59] = R4300i_UnknownOpcode; - R4300i_CoP1_W[60] = R4300i_UnknownOpcode; - R4300i_CoP1_W[61] = R4300i_UnknownOpcode; - R4300i_CoP1_W[62] = R4300i_UnknownOpcode; - R4300i_CoP1_W[63] = R4300i_UnknownOpcode; - - R4300i_CoP1_L[ 0] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 1] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 2] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 3] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 4] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 5] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 6] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 7] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 8] = R4300i_UnknownOpcode; - R4300i_CoP1_L[ 9] = R4300i_UnknownOpcode; - R4300i_CoP1_L[10] = R4300i_UnknownOpcode; - R4300i_CoP1_L[11] = R4300i_UnknownOpcode; - R4300i_CoP1_L[12] = R4300i_UnknownOpcode; - R4300i_CoP1_L[13] = R4300i_UnknownOpcode; - R4300i_CoP1_L[14] = R4300i_UnknownOpcode; - R4300i_CoP1_L[15] = R4300i_UnknownOpcode; - R4300i_CoP1_L[16] = R4300i_UnknownOpcode; - R4300i_CoP1_L[17] = R4300i_UnknownOpcode; - R4300i_CoP1_L[18] = R4300i_UnknownOpcode; - R4300i_CoP1_L[19] = R4300i_UnknownOpcode; - R4300i_CoP1_L[20] = R4300i_UnknownOpcode; - R4300i_CoP1_L[21] = R4300i_UnknownOpcode; - R4300i_CoP1_L[22] = R4300i_UnknownOpcode; - R4300i_CoP1_L[23] = R4300i_UnknownOpcode; - R4300i_CoP1_L[24] = R4300i_UnknownOpcode; - R4300i_CoP1_L[25] = R4300i_UnknownOpcode; - R4300i_CoP1_L[26] = R4300i_UnknownOpcode; - R4300i_CoP1_L[27] = R4300i_UnknownOpcode; - R4300i_CoP1_L[28] = R4300i_UnknownOpcode; - R4300i_CoP1_L[29] = R4300i_UnknownOpcode; - R4300i_CoP1_L[30] = R4300i_UnknownOpcode; - R4300i_CoP1_L[31] = R4300i_UnknownOpcode; - R4300i_CoP1_L[32] = r4300i_COP1_L_CVT_S; - R4300i_CoP1_L[33] = r4300i_COP1_L_CVT_D; - R4300i_CoP1_L[34] = R4300i_UnknownOpcode; - R4300i_CoP1_L[35] = R4300i_UnknownOpcode; - R4300i_CoP1_L[36] = R4300i_UnknownOpcode; - R4300i_CoP1_L[37] = R4300i_UnknownOpcode; - R4300i_CoP1_L[38] = R4300i_UnknownOpcode; - R4300i_CoP1_L[39] = R4300i_UnknownOpcode; - R4300i_CoP1_L[40] = R4300i_UnknownOpcode; - R4300i_CoP1_L[41] = R4300i_UnknownOpcode; - R4300i_CoP1_L[42] = R4300i_UnknownOpcode; - R4300i_CoP1_L[43] = R4300i_UnknownOpcode; - R4300i_CoP1_L[44] = R4300i_UnknownOpcode; - R4300i_CoP1_L[45] = R4300i_UnknownOpcode; - R4300i_CoP1_L[46] = R4300i_UnknownOpcode; - R4300i_CoP1_L[47] = R4300i_UnknownOpcode; - R4300i_CoP1_L[48] = R4300i_UnknownOpcode; - R4300i_CoP1_L[49] = R4300i_UnknownOpcode; - R4300i_CoP1_L[50] = R4300i_UnknownOpcode; - R4300i_CoP1_L[51] = R4300i_UnknownOpcode; - R4300i_CoP1_L[52] = R4300i_UnknownOpcode; - R4300i_CoP1_L[53] = R4300i_UnknownOpcode; - R4300i_CoP1_L[54] = R4300i_UnknownOpcode; - R4300i_CoP1_L[55] = R4300i_UnknownOpcode; - R4300i_CoP1_L[56] = R4300i_UnknownOpcode; - R4300i_CoP1_L[57] = R4300i_UnknownOpcode; - R4300i_CoP1_L[58] = R4300i_UnknownOpcode; - R4300i_CoP1_L[59] = R4300i_UnknownOpcode; - R4300i_CoP1_L[60] = R4300i_UnknownOpcode; - R4300i_CoP1_L[61] = R4300i_UnknownOpcode; - R4300i_CoP1_L[62] = R4300i_UnknownOpcode; - R4300i_CoP1_L[63] = R4300i_UnknownOpcode; -} - - -void RunFunction(usf_state_t * state, uint32_t address) { - uint32_t oldPC = state->PROGRAM_COUNTER, oldRA = state->GPR[31].UW[0], la = state->NextInstruction; - int callStack = 0; - - state->NextInstruction = NORMAL; - state->PROGRAM_COUNTER = address; - - while( (state->PROGRAM_COUNTER != oldRA) || callStack) { - - if(state->PROGRAM_COUNTER == address) - callStack++; - - ExecuteInterpreterOpCode(state); - - if(state->PROGRAM_COUNTER == oldRA) - callStack--; - } - - state->PROGRAM_COUNTER = oldPC; - state->GPR[31].UW[0] = oldRA; - state->NextInstruction = la; -} - -#ifdef DEBUG_INFO -#include "debugger/dbg_decoder.h" -#endif - -void ExecuteInterpreterOpCode (usf_state_t * state) { - - - if (*state->WaitMode) state->Timers->Timer = -1; - - if (!r4300i_LW_VAddr(state, state->PROGRAM_COUNTER, &state->Opcode.u.Hex)) { - DoTLBMiss(state, state->NextInstruction == JUMP,state->PROGRAM_COUNTER); - state->NextInstruction = NORMAL; - return; - } - -#ifdef DEBUG_INFO - { - char opcode[256]; - char arguments[256]; - r4300_decode_op(state->Opcode.u.Hex, opcode, arguments, state->PROGRAM_COUNTER); - fprintf(state->debug_log, "%08x: %-16s %s\n", state->PROGRAM_COUNTER, opcode, arguments); - } -#endif - - COUNT_REGISTER += 2; - state->Timers->Timer -= 2; - - RANDOM_REGISTER -= 1; - if ((int32_t)RANDOM_REGISTER < (int32_t)WIRED_REGISTER) { - RANDOM_REGISTER = 31; - } - - R4300i_Opcode[ state->Opcode.u.b.op ](state); - - if (state->GPR[0].DW != 0) { - state->GPR[0].DW = 0; - } - - switch (state->NextInstruction) { - case NORMAL: - state->PROGRAM_COUNTER += 4; - break; - case DELAY_SLOT: - state->NextInstruction = JUMP; - state->PROGRAM_COUNTER += 4; - break; - case JUMP: - if ( -#ifdef DEBUG_INFO - 0 && -#endif - state->cpu_hle_entry_count && - DoCPUHLE(state, state->JumpToLocation)) { - state->PROGRAM_COUNTER = state->GPR[31].UW[0]; - state->NextInstruction = NORMAL; - } - else { - state->PROGRAM_COUNTER = state->JumpToLocation; - state->NextInstruction = NORMAL; - } - if ((int32_t)state->Timers->Timer < 0) { TimerDone(state); } - if (state->CPU_Action->DoSomething) { DoSomething(state); } - } -} - -void StartInterpreterCPU (usf_state_t * state) { - const int safety_count_max = 20000000; - int safety_count = safety_count_max; - size_t last_sample_buffer_count = state->sample_buffer_count; - - state->NextInstruction = NORMAL; - - while(state->cpu_running) { - ExecuteInterpreterOpCode(state); - if (!--safety_count) { - if (last_sample_buffer_count == state->sample_buffer_count) { - DisplayError( state, "Emulator core is not generating any samples after 20 million instructions" ); - break; - } else { - safety_count = safety_count_max; - last_sample_buffer_count = state->sample_buffer_count; - } - } - } - - state->cpu_stopped = 1; - -} - -void TestInterpreterJump (usf_state_t * state, uint32_t PC, uint32_t TargetPC, int32_t Reg1, int32_t Reg2) { - if (PC != TargetPC) { return; } - if (DelaySlotEffectsCompare(state,PC,Reg1,Reg2)) { return; } - InPermLoop(state); -} diff --git a/Frameworks/lazyusf/lazyusf/interpreter_cpu.h b/Frameworks/lazyusf/lazyusf/interpreter_cpu.h deleted file mode 100644 index 53dc69534..000000000 --- a/Frameworks/lazyusf/lazyusf/interpreter_cpu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#include - -void BuildInterpreter ( usf_state_t * ); -void ExecuteInterpreterOpCode ( usf_state_t * ); -void StartInterpreterCPU ( usf_state_t * ); -void TestInterpreterJump ( usf_state_t *, uint32_t PC, uint32_t TargetPC, int32_t Reg1, int32_t Reg2 ); - -void RunFunction( usf_state_t *, uint32_t address ); - - - -extern void (* R4300i_Opcode[64])(usf_state_t *); diff --git a/Frameworks/lazyusf/lazyusf/interpreter_ops.c b/Frameworks/lazyusf/lazyusf/interpreter_ops.c deleted file mode 100644 index ba9faa82c..000000000 --- a/Frameworks/lazyusf/lazyusf/interpreter_ops.c +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#include -#include -#include -#include "main.h" -#include "cpu.h" -#include "usf.h" - -#ifdef _MSC_VER -#define INLINE __forceinline -#else -#define INLINE inline __attribute__((always_inline)) -#endif - -#include "usf_internal.h" - -#define ADDRESS_ERROR_EXCEPTION(Address,FromRead) \ - DoAddressError(state,state->NextInstruction == JUMP,Address,FromRead);\ - state->NextInstruction = JUMP;\ - state->JumpToLocation = state->PROGRAM_COUNTER;\ - return; - -//#define TEST_COP1_USABLE_EXCEPTION -#define TEST_COP1_USABLE_EXCEPTION \ - if ((STATUS_REGISTER & STATUS_CU1) == 0) {\ - DoCopUnusableException(state,state->NextInstruction == JUMP,1);\ - state->NextInstruction = JUMP;\ - state->JumpToLocation = state->PROGRAM_COUNTER;\ - return;\ - } - -#define TLB_READ_EXCEPTION(Address) \ - DoTLBMiss(state,state->NextInstruction == JUMP,Address);\ - state->NextInstruction = JUMP;\ - state->JumpToLocation = state->PROGRAM_COUNTER;\ - return; - -/************************* OpCode functions *************************/ -void r4300i_J (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = (state->PROGRAM_COUNTER & 0xF0000000) + (state->Opcode.u.d.target << 2); - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,0,0); -} - -void r4300i_JAL (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = (state->PROGRAM_COUNTER & 0xF0000000) + (state->Opcode.u.d.target << 2); - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,0,0); - state->GPR[31].DW= (int32_t)(state->PROGRAM_COUNTER + 8); -} - -void r4300i_BEQ (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BNE (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW != state->GPR[state->Opcode.u.b.rt].DW) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BLEZ (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW <= 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BGTZ (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW > 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_ADDI (usf_state_t * state) { - if (state->Opcode.u.b.rt == 0) { return; } - state->GPR[state->Opcode.u.b.rt].DW = (state->GPR[state->Opcode.u.b.rs].W[0] + ((int16_t)state->Opcode.u.c.immediate)); -} - -void r4300i_ADDIU (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = (state->GPR[state->Opcode.u.b.rs].W[0] + ((int16_t)state->Opcode.u.c.immediate)); -} - -void r4300i_SLTI (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW < (int64_t)((int16_t)state->Opcode.u.c.immediate)) { - state->GPR[state->Opcode.u.b.rt].DW = 1; - } else { - state->GPR[state->Opcode.u.b.rt].DW = 0; - } -} - -void r4300i_SLTIU (usf_state_t * state) { - int32_t imm32 = (int16_t)state->Opcode.u.c.immediate; - int64_t imm64; - - imm64 = imm32; - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].UDW < (uint64_t)imm64?1:0; -} - -void r4300i_ANDI (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW & state->Opcode.u.c.immediate; -} - -void r4300i_ORI (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW | state->Opcode.u.c.immediate; -} - -void r4300i_XORI (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW ^ state->Opcode.u.c.immediate; -} - -void r4300i_LUI (usf_state_t * state) { - if (state->Opcode.u.b.rt == 0) { return; } - state->GPR[state->Opcode.u.b.rt].DW = (int32_t)((int16_t)state->Opcode.u.b.offset << 16); -} - -void r4300i_BEQL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BNEL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW != state->GPR[state->Opcode.u.b.rt].DW) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BLEZL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW <= 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_BGTZL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW > 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_DADDIU (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW + (int64_t)((int16_t)state->Opcode.u.c.immediate); -} - -uint64_t LDL_MASK[8] = { 0ULL,0xFFULL,0xFFFFULL,0xFFFFFFULL,0xFFFFFFFFULL,0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL }; -int32_t LDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - -void r4300i_LDL (usf_state_t * state) { - uint32_t Offset, Address; - uint64_t Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 7; - - if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { - return; - } - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].DW & LDL_MASK[Offset]; - state->GPR[state->Opcode.u.b.rt].DW += Value << LDL_SHIFT[Offset]; -} - -uint64_t LDR_MASK[8] = { 0xFFFFFFFFFFFFFF00ULL, 0xFFFFFFFFFFFF0000ULL, - 0xFFFFFFFFFF000000ULL, 0xFFFFFFFF00000000ULL, - 0xFFFFFF0000000000ULL, 0xFFFF000000000000ULL, - 0xFF00000000000000ULL, 0 }; -int32_t LDR_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; - -void r4300i_LDR (usf_state_t * state) { - uint32_t Offset, Address; - uint64_t Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 7; - - if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { - return; - } - - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].DW & LDR_MASK[Offset]; - state->GPR[state->Opcode.u.b.rt].DW += Value >> LDR_SHIFT[Offset]; - -} - -void r4300i_LB (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if (state->Opcode.u.b.rt == 0) { return; } - if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) { - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].B[0]; - } -} - -void r4300i_LH (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LH TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].HW[0]; - } -} - -uint32_t LWL_MASK[4] = { 0,0xFF,0xFFFF,0xFFFFFF }; -int32_t LWL_SHIFT[4] = { 0, 8, 16, 24}; - -void r4300i_LWL (usf_state_t * state) { - uint32_t Offset, Address, Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 3; - - if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { - return; - } - - state->GPR[state->Opcode.u.b.rt].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].W[0] & LWL_MASK[Offset]); - state->GPR[state->Opcode.u.b.rt].DW += (int32_t)(Value << LWL_SHIFT[Offset]); -} - -void r4300i_LW (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - - -// if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - - if (state->Opcode.u.b.rt == 0) { return; } - - - if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { - //if (ShowTLBMisses) { - //printf("LW TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].W[0]; - } -} - -void r4300i_LBU (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LBU TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UB[0]; - } -} - -void r4300i_LHU (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LHU TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UHW[0]; - } -} - -uint32_t LWR_MASK[4] = { 0xFFFFFF00, 0xFFFF0000, 0xFF000000, 0 }; -int32_t LWR_SHIFT[4] = { 24, 16 ,8, 0 }; - -void r4300i_LWR (usf_state_t * state) { - uint32_t Offset, Address, Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 3; - - if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { - return; - } - - state->GPR[state->Opcode.u.b.rt].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].W[0] & LWR_MASK[Offset]); - state->GPR[state->Opcode.u.b.rt].DW += (int32_t)(Value >> LWR_SHIFT[Offset]); -} - -void r4300i_LWU (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (state->Opcode.u.b.rt == 0) { return; } - - if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LWU TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UW[0]; - } -} - -void r4300i_SB (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if (!r4300i_SB_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UB[0])) { - } -} - -void r4300i_SH (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - if (!r4300i_SH_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UHW[0])) { - } -} - -uint32_t SWL_MASK[4] = { 0,0xFF000000,0xFFFF0000,0xFFFFFF00 }; -int32_t SWL_SHIFT[4] = { 0, 8, 16, 24 }; - -void r4300i_SWL (usf_state_t * state) { - uint32_t Offset, Address, Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 3; - - if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { - return; - } - - Value &= SWL_MASK[Offset]; - Value += state->GPR[state->Opcode.u.b.rt].UW[0] >> SWL_SHIFT[Offset]; - - if (!r4300i_SW_VAddr(state,(Address & ~0x03),Value)) { - } -} - - -void r4300i_SW (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) { - } - //TranslateVaddr(&Address); - //if (Address == 0x00090AA0) { - // LogMessage("%X: Write %X to %X",state->PROGRAM_COUNTER,state->GPR[state->Opcode.u.b.rt].UW[0],state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset); - //} -} - -uint64_t SDL_MASK[8] = { 0,0xFF00000000000000ULL, - 0xFFFF000000000000ULL, - 0xFFFFFF0000000000ULL, - 0xFFFFFFFF00000000ULL, - 0xFFFFFFFFFF000000ULL, - 0xFFFFFFFFFFFF0000ULL, - 0xFFFFFFFFFFFFFF00ULL - }; -int32_t SDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - -void r4300i_SDL (usf_state_t * state) { - uint32_t Offset, Address; - uint64_t Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 7; - - if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { - return; - } - - Value &= SDL_MASK[Offset]; - Value += state->GPR[state->Opcode.u.b.rt].UDW >> SDL_SHIFT[Offset]; - - if (!r4300i_SD_VAddr(state,(Address & ~7),Value)) { - } -} - -uint64_t SDR_MASK[8] = { 0x00FFFFFFFFFFFFFFULL, - 0x0000FFFFFFFFFFFFULL, - 0x000000FFFFFFFFFFULL, - 0x00000000FFFFFFFFULL, - 0x0000000000FFFFFFULL, - 0x000000000000FFFFULL, - 0x00000000000000FFULL, - 0x0000000000000000ULL - }; -int32_t SDR_SHIFT[8] = { 56,48,40,32,24,16,8,0 }; - -void r4300i_SDR (usf_state_t * state) { - uint32_t Offset, Address; - uint64_t Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 7; - - if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { - return; - } - - Value &= SDR_MASK[Offset]; - Value += state->GPR[state->Opcode.u.b.rt].UDW << SDR_SHIFT[Offset]; - - if (!r4300i_SD_VAddr(state,(Address & ~7),Value)) { - } -} - -uint32_t SWR_MASK[4] = { 0x00FFFFFF,0x0000FFFF,0x000000FF,0x00000000 }; -int32_t SWR_SHIFT[4] = { 24, 16 , 8, 0 }; - -void r4300i_SWR (usf_state_t * state) { - uint32_t Offset, Address, Value; - - Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - Offset = Address & 3; - - if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { - return; - } - - Value &= SWR_MASK[Offset]; - Value += state->GPR[state->Opcode.u.b.rt].UW[0] << SWR_SHIFT[Offset]; - - if (!r4300i_SW_VAddr(state,(Address & ~0x03),Value)) { - } -} - -void r4300i_CACHE (usf_state_t * state) { - (void)state; -} - -void r4300i_LL (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - uintptr_t ll = 0; - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - - if (state->Opcode.u.b.rt == 0) { return; } - - if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LW TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } else { - state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].W[0]; - } - state->LLBit = 1; - state->LLAddr = Address; - ll = state->LLAddr; - TranslateVaddr(state, &ll); - state->LLAddr = (uint32_t) ll; -} - -void r4300i_LWC1 (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (uint32_t)((int16_t)state->Opcode.u.b.offset); - TEST_COP1_USABLE_EXCEPTION - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (!r4300i_LW_VAddr(state,Address,&*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) { - //if (ShowTLBMisses) { - // Too spammy - //DisplayError(state, "LWC1 TLB: %X",Address); - //} - TLB_READ_EXCEPTION(Address); - } -} - -void r4300i_SC (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - if (state->LLBit == 1) { - if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) { - DisplayError(state, "SW TLB: %X",Address); - } - } - state->GPR[state->Opcode.u.b.rt].UW[0] = state->LLBit; -} - -void r4300i_LD (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (!r4300i_LD_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UDW)) { - } -} - - -void r4300i_LDC1 (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - - TEST_COP1_USABLE_EXCEPTION - if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } - if (!r4300i_LD_VAddr(state,Address,&*(uint64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft])) { - } -} - -void r4300i_SWC1 (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - TEST_COP1_USABLE_EXCEPTION - if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - - if (!r4300i_SW_VAddr(state,Address,*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) { - } -} - -void r4300i_SDC1 (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - - TEST_COP1_USABLE_EXCEPTION - if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - if (!r4300i_SD_VAddr(state,Address,*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft])) { - } -} - -void r4300i_SD (usf_state_t * state) { - uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; - if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } - if (!r4300i_SD_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UDW)) { - } -} -/********************** R4300i state->Opcodes: Special **********************/ -void r4300i_SPECIAL_SLL (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] << state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_SRL (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].UW[0] >> state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_SRA (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] >> state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_SLLV (usf_state_t * state) { - if (state->Opcode.u.e.rd == 0) { return; } - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] << (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); -} - -void r4300i_SPECIAL_SRLV (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].UW[0] >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); -} - -void r4300i_SPECIAL_SRAV (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); -} - -void r4300i_SPECIAL_JR (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->GPR[state->Opcode.u.b.rs].UW[0]; -} - -void r4300i_SPECIAL_JALR (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->GPR[state->Opcode.u.b.rs].UW[0]; - state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->PROGRAM_COUNTER + 8); -} - -void r4300i_SPECIAL_SYSCALL (usf_state_t * state) { - DoSysCallException(state, state->NextInstruction == JUMP); - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER; -} - -void r4300i_SPECIAL_BREAK (usf_state_t * state) { - *state->WaitMode=1; -} - -void r4300i_SPECIAL_SYNC (usf_state_t * state) { - (void)state; -} - -void r4300i_SPECIAL_MFHI (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->HI.DW; -} - -void r4300i_SPECIAL_MTHI (usf_state_t * state) { - state->HI.DW = state->GPR[state->Opcode.u.b.rs].DW; -} - -void r4300i_SPECIAL_MFLO (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->LO.DW; -} - -void r4300i_SPECIAL_MTLO (usf_state_t * state) { - state->LO.DW = state->GPR[state->Opcode.u.b.rs].DW; -} - -void r4300i_SPECIAL_DSLLV (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rt].DW << (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); -} - -void r4300i_SPECIAL_DSRLV (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].UDW = state->GPR[state->Opcode.u.b.rt].UDW >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); -} - -void r4300i_SPECIAL_DSRAV (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rt].DW >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); -} - -void r4300i_SPECIAL_MULT (usf_state_t * state) { - state->HI.DW = (int64_t)(state->GPR[state->Opcode.u.b.rs].W[0]) * (int64_t)(state->GPR[state->Opcode.u.b.rt].W[0]); - state->LO.DW = state->HI.W[0]; - state->HI.DW = state->HI.W[1]; -} - -void r4300i_SPECIAL_MULTU (usf_state_t * state) { - state->HI.DW = (uint64_t)(state->GPR[state->Opcode.u.b.rs].UW[0]) * (uint64_t)(state->GPR[state->Opcode.u.b.rt].UW[0]); - state->LO.DW = state->HI.W[0]; - state->HI.DW = state->HI.W[1]; -} - -void r4300i_SPECIAL_DIV (usf_state_t * state) { - if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { - state->LO.DW = state->GPR[state->Opcode.u.b.rs].W[0] / state->GPR[state->Opcode.u.b.rt].W[0]; - state->HI.DW = state->GPR[state->Opcode.u.b.rs].W[0] % state->GPR[state->Opcode.u.b.rt].W[0]; - } else { - } -} - -void r4300i_SPECIAL_DIVU (usf_state_t * state) { - if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { - state->LO.DW = (int32_t)(state->GPR[state->Opcode.u.b.rs].UW[0] / state->GPR[state->Opcode.u.b.rt].UW[0]); - state->HI.DW = (int32_t)(state->GPR[state->Opcode.u.b.rs].UW[0] % state->GPR[state->Opcode.u.b.rt].UW[0]); - } else { - } -} - -void r4300i_SPECIAL_DMULT (usf_state_t * state) { - MIPS_DWORD Tmp[3]; - - state->LO.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; - Tmp[0].UDW = (int64_t)state->GPR[state->Opcode.u.b.rs].W[1] * (int64_t)(uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; - Tmp[1].UDW = (int64_t)(uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (int64_t)state->GPR[state->Opcode.u.b.rt].W[1]; - state->HI.UDW = (int64_t)state->GPR[state->Opcode.u.b.rs].W[1] * (int64_t)state->GPR[state->Opcode.u.b.rt].W[1]; - - Tmp[2].UDW = (uint64_t)state->LO.UW[1] + (uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]; - state->LO.UDW += ((uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]) << 32; - state->HI.UDW += (uint64_t)Tmp[0].W[1] + (uint64_t)Tmp[1].W[1] + Tmp[2].UW[1]; -} - -void r4300i_SPECIAL_DMULTU (usf_state_t * state) { - MIPS_DWORD Tmp[3]; - - state->LO.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; - Tmp[0].UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[1] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; - Tmp[1].UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[1]; - state->HI.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[1] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[1]; - - Tmp[2].UDW = (uint64_t)state->LO.UW[1] + (uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]; - state->LO.UDW += ((uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]) << 32; - state->HI.UDW += (uint64_t)Tmp[0].UW[1] + (uint64_t)Tmp[1].UW[1] + Tmp[2].UW[1]; -} - -void r4300i_SPECIAL_DDIV (usf_state_t * state) { - if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { - state->LO.DW = state->GPR[state->Opcode.u.b.rs].DW / state->GPR[state->Opcode.u.b.rt].DW; - state->HI.DW = state->GPR[state->Opcode.u.b.rs].DW % state->GPR[state->Opcode.u.b.rt].DW; - } else { - } -} - -void r4300i_SPECIAL_DDIVU (usf_state_t * state) { - if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { - state->LO.UDW = state->GPR[state->Opcode.u.b.rs].UDW / state->GPR[state->Opcode.u.b.rt].UDW; - state->HI.UDW = state->GPR[state->Opcode.u.b.rs].UDW % state->GPR[state->Opcode.u.b.rt].UDW; - } else { - } -} - -void r4300i_SPECIAL_ADD (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] + state->GPR[state->Opcode.u.b.rt].W[0]; -} - -void r4300i_SPECIAL_ADDU (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] + state->GPR[state->Opcode.u.b.rt].W[0]; -} - -void r4300i_SPECIAL_SUB (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] - state->GPR[state->Opcode.u.b.rt].W[0]; -} - -void r4300i_SPECIAL_SUBU (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] - state->GPR[state->Opcode.u.b.rt].W[0]; -} - -void r4300i_SPECIAL_AND (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW & state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_OR (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW | state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_XOR (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW ^ state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_NOR (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = ~(state->GPR[state->Opcode.u.b.rs].DW | state->GPR[state->Opcode.u.b.rt].DW); -} - -void r4300i_SPECIAL_SLT (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW < state->GPR[state->Opcode.u.b.rt].DW) { - state->GPR[state->Opcode.u.e.rd].DW = 1; - } else { - state->GPR[state->Opcode.u.e.rd].DW = 0; - } -} - -void r4300i_SPECIAL_SLTU (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].UDW < state->GPR[state->Opcode.u.b.rt].UDW) { - state->GPR[state->Opcode.u.e.rd].DW = 1; - } else { - state->GPR[state->Opcode.u.e.rd].DW = 0; - } -} - -void r4300i_SPECIAL_DADD (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW + state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_DADDU (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW + state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_DSUB (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW - state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_DSUBU (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW - state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_SPECIAL_TEQ (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { - } -} - -void r4300i_SPECIAL_DSLL (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW << state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_DSRL (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].UDW = (state->GPR[state->Opcode.u.b.rt].UDW >> state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_DSRA (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW >> state->Opcode.u.e.sa); -} - -void r4300i_SPECIAL_DSLL32 (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW << (state->Opcode.u.e.sa + 32)); -} - -void r4300i_SPECIAL_DSRL32 (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].UDW = (state->GPR[state->Opcode.u.b.rt].UDW >> (state->Opcode.u.e.sa + 32)); -} - -void r4300i_SPECIAL_DSRA32 (usf_state_t * state) { - state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW >> (state->Opcode.u.e.sa + 32)); -} - -/********************** R4300i state->Opcodes: RegImm **********************/ -void r4300i_REGIMM_BLTZ (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW < 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_REGIMM_BGEZ (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_REGIMM_BLTZL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW < 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_REGIMM_BGEZL (usf_state_t * state) { - if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_REGIMM_BLTZAL (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW < 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } - state->GPR[31].DW= (int32_t)(state->PROGRAM_COUNTER + 8); -} - -void r4300i_REGIMM_BGEZAL (usf_state_t * state) { - state->NextInstruction = DELAY_SLOT; - if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } - state->GPR[31].DW = (int32_t)(state->PROGRAM_COUNTER + 8); -} -/************************** COP0 functions **************************/ -void r4300i_COP0_MF (usf_state_t * state) { - state->GPR[state->Opcode.u.b.rt].DW = (int32_t)state->CP0[state->Opcode.u.e.rd]; -} - -void r4300i_COP0_MT (usf_state_t * state) { - switch (state->Opcode.u.e.rd) { - case 0: //Index - case 2: //EntryLo0 - case 3: //EntryLo1 - case 5: //PageMask - case 6: //Wired - case 10: //Entry Hi - case 14: //EPC - case 16: //Config - case 18: //WatchLo - case 19: //WatchHi - case 28: //Tag lo - case 29: //Tag Hi - case 30: //ErrEPC - state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; - break; - case 4: //Context - state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0] & 0xFF800000; - break; - case 9: //Count - state->CP0[state->Opcode.u.e.rd]= state->GPR[state->Opcode.u.b.rt].UW[0]; - ChangeCompareTimer(state); - break; - case 11: //Compare - state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; - FAKE_CAUSE_REGISTER &= ~CAUSE_IP7; - ChangeCompareTimer(state); - break; - case 12: //Status - if ((state->CP0[state->Opcode.u.e.rd] ^ state->GPR[state->Opcode.u.b.rt].UW[0]) != 0) { - state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; - SetFpuLocations(state); - } else { - state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; - } - if ((state->CP0[state->Opcode.u.e.rd] & 0x18) != 0) { - } - CheckInterrupts(state); - break; - case 13: //cause - state->CP0[state->Opcode.u.e.rd] &= 0xFFFFCFF; - break; - default: - R4300i_UnknownOpcode(state); - } - -} - -/************************** COP0 CO functions ***********************/ -void r4300i_COP0_CO_TLBR (usf_state_t * state) { - TLB_Read(state); -} - -void r4300i_COP0_CO_TLBWI (usf_state_t * state) { - WriteTLBEntry(state, INDEX_REGISTER & 0x1F); -} - -void r4300i_COP0_CO_TLBWR (usf_state_t * state) { - WriteTLBEntry(state, RANDOM_REGISTER & 0x1F); -} - -void r4300i_COP0_CO_TLBP (usf_state_t * state) { - TLB_Probe(state); -} - -void r4300i_COP0_CO_ERET (usf_state_t * state) { - state->NextInstruction = JUMP; - if ((STATUS_REGISTER & STATUS_ERL) != 0) { - state->JumpToLocation = ERROREPC_REGISTER; - STATUS_REGISTER &= ~STATUS_ERL; - } else { - state->JumpToLocation = EPC_REGISTER; - STATUS_REGISTER &= ~STATUS_EXL; - } - state->LLBit = 0; - CheckInterrupts(state); -} - -/************************** COP1 functions **************************/ -void r4300i_COP1_MF (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - state->GPR[state->Opcode.u.b.rt].DW = *(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_DMF (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - state->GPR[state->Opcode.u.b.rt].DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_CF (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - if (state->Opcode.u.f.fs != 31 && state->Opcode.u.f.fs != 0) { - return; - } - state->GPR[state->Opcode.u.b.rt].DW = (int32_t)state->FPCR[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_MT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].W[0]; -} - -void r4300i_COP1_DMT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].DW; -} - -void r4300i_COP1_CT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - if (state->Opcode.u.f.fs == 31) { - state->FPCR[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].W[0]; - return; - } -} - -/************************* COP1: BC1 functions ***********************/ -void r4300i_COP1_BCF (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - state->NextInstruction = DELAY_SLOT; - if ((state->FPCR[31] & FPCSR_C) == 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_COP1_BCT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - state->NextInstruction = DELAY_SLOT; - if ((state->FPCR[31] & FPCSR_C) != 0) { - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - } else { - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_COP1_BCFL (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - if ((state->FPCR[31] & FPCSR_C) == 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} - -void r4300i_COP1_BCTL (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - if ((state->FPCR[31] & FPCSR_C) != 0) { - state->NextInstruction = DELAY_SLOT; - state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; - } else { - state->NextInstruction = JUMP; - state->JumpToLocation = state->PROGRAM_COUNTER + 8; - } -} -/************************** COP1: S functions ************************/ -static INLINE void Float_RoundToInteger32( int32_t * Dest, float * Source ) { - *Dest = (int32_t)*Source; -} - -static INLINE void Float_RoundToInteger64( int64_t * Dest, float * Source ) { - *Dest = (int64_t)*Source; -} - -void r4300i_COP1_S_ADD (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] + *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); -} - -void r4300i_COP1_S_SUB (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] - *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); -} - -void r4300i_COP1_S_MUL (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] * *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); -} - -void r4300i_COP1_S_DIV (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] / *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); -} - -void r4300i_COP1_S_SQRT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)sqrt(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_ABS (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)fabs(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_MOV (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = *(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_S_NEG (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] * -1.0f); -} - -void r4300i_COP1_S_TRUNC_L (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - //_controlfp(_RC_CHOP,_MCW_RC); - Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CEIL_L (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - //_controlfp(_RC_UP,_MCW_RC); - Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_FLOOR_L (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_ROUND_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_TRUNC_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - //_controlfp(_RC_CHOP,_MCW_RC); - Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CEIL_W (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - //_controlfp(_RC_UP,_MCW_RC); - Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_FLOOR_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CVT_D (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CVT_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CVT_L (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_S_CMP (usf_state_t * state) { - int32_t less, equal, unorded, condition; - float Temp0, Temp1; - - TEST_COP1_USABLE_EXCEPTION - - Temp0 = *(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]; - Temp1 = *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]; - - if(0) { - //if (_isnan(Temp0) || _isnan(Temp1)) { - less = 0; - equal = 0; - unorded = 1; - if ((state->Opcode.u.e.funct & 8) != 0) { - } - } else { - less = Temp0 < Temp1; - equal = Temp0 == Temp1; - unorded = 0; - } - - condition = ((state->Opcode.u.e.funct & 4) && less) | ((state->Opcode.u.e.funct & 2) && equal) | - ((state->Opcode.u.e.funct & 1) && unorded); - - if (condition) { - state->FPCR[31] |= FPCSR_C; - } else { - state->FPCR[31] &= ~FPCSR_C; - } - -} - -/************************** COP1: D functions ************************/ -static INLINE void Double_RoundToInteger32( int32_t * Dest, double * Source ) { - *Dest = (int32_t)*Source; -} - -static INLINE void Double_RoundToInteger64( int64_t * Dest, double * Source ) { - *Dest = (int64_t)*Source; -} - -void r4300i_COP1_D_ADD (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] + *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; -} - -void r4300i_COP1_D_SUB (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; -} - -void r4300i_COP1_D_MUL (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] * *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; -} - -void r4300i_COP1_D_DIV (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] / *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; -} - -void r4300i_COP1_D_SQRT (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)sqrt(*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_D_ABS (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = fabs(*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_D_MOV (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_D_NEG (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] * -1.0); -} - -void r4300i_COP1_D_TRUNC_L (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger64(&*(int64_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_CEIL_L (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger64(&*(int64_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_FLOOR_L (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_D_ROUND_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_TRUNC_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_CEIL_W (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_FLOOR_W (usf_state_t * state) { //added by Witten - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger32(&*(int32_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRFloatLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_D_CVT_S (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_D_CVT_W (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); -} - -void r4300i_COP1_D_CVT_L (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - Double_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); -} - -void r4300i_COP1_D_CMP (usf_state_t * state) { - int32_t less, equal, unorded, condition; - MIPS_DWORD Temp0, Temp1; - - TEST_COP1_USABLE_EXCEPTION - - Temp0.DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; - Temp1.DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; - - if(0) { - //if (_isnan(Temp0.D) || _isnan(Temp1.D)) { - less = 0; - equal = 0; - unorded = 1; - if ((state->Opcode.u.e.funct & 8) != 0) { - } - } else { - less = Temp0.D < Temp1.D; - equal = Temp0.D == Temp1.D; - unorded = 0; - } - - condition = ((state->Opcode.u.e.funct & 4) && less) | ((state->Opcode.u.e.funct & 2) && equal) | - ((state->Opcode.u.e.funct & 1) && unorded); - - if (condition) { - state->FPCR[31] |= FPCSR_C; - } else { - state->FPCR[31] &= ~FPCSR_C; - } -} - -/************************** COP1: W functions ************************/ -void r4300i_COP1_W_CVT_S (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_W_CVT_D (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; -} - -/************************** COP1: L functions ************************/ -void r4300i_COP1_L_CVT_S (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; -} - -void r4300i_COP1_L_CVT_D (usf_state_t * state) { - TEST_COP1_USABLE_EXCEPTION - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; -} - -/************************** Other functions **************************/ -void R4300i_UnknownOpcode (usf_state_t * state) { - DisplayError(state, "Unknown R4300i Opcode.\tPC:%08x\tOp:%08x\n", state->PROGRAM_COUNTER,state->Opcode.u.Hex); - StopEmulation(state); -} diff --git a/Frameworks/lazyusf/lazyusf/interpreter_ops.h b/Frameworks/lazyusf/lazyusf/interpreter_ops.h deleted file mode 100644 index d8cc8fcaf..000000000 --- a/Frameworks/lazyusf/lazyusf/interpreter_ops.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -/************************* OpCode functions *************************/ -void r4300i_J ( usf_state_t * ); -void r4300i_JAL ( usf_state_t * ); -void r4300i_BNE ( usf_state_t * ); -void r4300i_BEQ ( usf_state_t * ); -void r4300i_BLEZ ( usf_state_t * ); -void r4300i_BGTZ ( usf_state_t * ); -void r4300i_ADDI ( usf_state_t * ); -void r4300i_ADDIU ( usf_state_t * ); -void r4300i_SLTI ( usf_state_t * ); -void r4300i_SLTIU ( usf_state_t * ); -void r4300i_ANDI ( usf_state_t * ); -void r4300i_ORI ( usf_state_t * ); -void r4300i_XORI ( usf_state_t * ); -void r4300i_LUI ( usf_state_t * ); -void r4300i_BEQL ( usf_state_t * ); -void r4300i_BNEL ( usf_state_t * ); -void r4300i_BLEZL ( usf_state_t * ); -void r4300i_BGTZL ( usf_state_t * ); -void r4300i_DADDIU ( usf_state_t * ); -void r4300i_LDL ( usf_state_t * ); -void r4300i_LDR ( usf_state_t * ); -void r4300i_LB ( usf_state_t * ); -void r4300i_LH ( usf_state_t * ); -void r4300i_LWL ( usf_state_t * ); -void r4300i_LW ( usf_state_t * ); -void r4300i_LBU ( usf_state_t * ); -void r4300i_LHU ( usf_state_t * ); -void r4300i_LWR ( usf_state_t * ); -void r4300i_LWU ( usf_state_t * ); -void r4300i_SB ( usf_state_t * ); -void r4300i_SH ( usf_state_t * ); -void r4300i_SWL ( usf_state_t * ); -void r4300i_SW ( usf_state_t * ); -void r4300i_SDL ( usf_state_t * ); -void r4300i_SDR ( usf_state_t * ); -void r4300i_SWR ( usf_state_t * ); -void r4300i_CACHE ( usf_state_t * ); -void r4300i_LL ( usf_state_t * ); -void r4300i_LWC1 ( usf_state_t * ); -void r4300i_LDC1 ( usf_state_t * ); -void r4300i_LD ( usf_state_t * ); -void r4300i_SC ( usf_state_t * ); -void r4300i_SWC1 ( usf_state_t * ); -void r4300i_SDC1 ( usf_state_t * ); -void r4300i_SD ( usf_state_t * ); - -/********************** R4300i OpCodes: Special **********************/ -void r4300i_SPECIAL_SLL ( usf_state_t * ); -void r4300i_SPECIAL_SRL ( usf_state_t * ); -void r4300i_SPECIAL_SRA ( usf_state_t * ); -void r4300i_SPECIAL_SLLV ( usf_state_t * ); -void r4300i_SPECIAL_SRLV ( usf_state_t * ); -void r4300i_SPECIAL_SRAV ( usf_state_t * ); -void r4300i_SPECIAL_JR ( usf_state_t * ); -void r4300i_SPECIAL_JALR ( usf_state_t * ); -void r4300i_SPECIAL_SYSCALL ( usf_state_t * ); -void r4300i_SPECIAL_BREAK ( usf_state_t * ); -void r4300i_SPECIAL_SYNC ( usf_state_t * ); -void r4300i_SPECIAL_MFHI ( usf_state_t * ); -void r4300i_SPECIAL_MTHI ( usf_state_t * ); -void r4300i_SPECIAL_MFLO ( usf_state_t * ); -void r4300i_SPECIAL_MTLO ( usf_state_t * ); -void r4300i_SPECIAL_DSLLV ( usf_state_t * ); -void r4300i_SPECIAL_DSRLV ( usf_state_t * ); -void r4300i_SPECIAL_DSRAV ( usf_state_t * ); -void r4300i_SPECIAL_MULT ( usf_state_t * ); -void r4300i_SPECIAL_MULTU ( usf_state_t * ); -void r4300i_SPECIAL_DIV ( usf_state_t * ); -void r4300i_SPECIAL_DIVU ( usf_state_t * ); -void r4300i_SPECIAL_DMULT ( usf_state_t * ); -void r4300i_SPECIAL_DMULTU ( usf_state_t * ); -void r4300i_SPECIAL_DDIV ( usf_state_t * ); -void r4300i_SPECIAL_DDIVU ( usf_state_t * ); -void r4300i_SPECIAL_ADD ( usf_state_t * ); -void r4300i_SPECIAL_ADDU ( usf_state_t * ); -void r4300i_SPECIAL_SUB ( usf_state_t * ); -void r4300i_SPECIAL_SUBU ( usf_state_t * ); -void r4300i_SPECIAL_AND ( usf_state_t * ); -void r4300i_SPECIAL_OR ( usf_state_t * ); -void r4300i_SPECIAL_XOR ( usf_state_t * ); -void r4300i_SPECIAL_NOR ( usf_state_t * ); -void r4300i_SPECIAL_SLT ( usf_state_t * ); -void r4300i_SPECIAL_SLTU ( usf_state_t * ); -void r4300i_SPECIAL_DADD ( usf_state_t * ); -void r4300i_SPECIAL_DADDU ( usf_state_t * ); -void r4300i_SPECIAL_DSUB ( usf_state_t * ); -void r4300i_SPECIAL_DSUBU ( usf_state_t * ); -void r4300i_SPECIAL_TEQ ( usf_state_t * ); -void r4300i_SPECIAL_DSLL ( usf_state_t * ); -void r4300i_SPECIAL_DSRL ( usf_state_t * ); -void r4300i_SPECIAL_DSRA ( usf_state_t * ); -void r4300i_SPECIAL_DSLL32 ( usf_state_t * ); -void r4300i_SPECIAL_DSRL32 ( usf_state_t * ); -void r4300i_SPECIAL_DSRA32 ( usf_state_t * ); - -/********************** R4300i OpCodes: RegImm **********************/ -void r4300i_REGIMM_BLTZ ( usf_state_t * ); -void r4300i_REGIMM_BGEZ ( usf_state_t * ); -void r4300i_REGIMM_BLTZL ( usf_state_t * ); -void r4300i_REGIMM_BGEZL ( usf_state_t * ); -void r4300i_REGIMM_BLTZAL ( usf_state_t * ); -void r4300i_REGIMM_BGEZAL ( usf_state_t * ); - -/************************** COP0 functions **************************/ -void r4300i_COP0_MF ( usf_state_t * ); -void r4300i_COP0_MT ( usf_state_t * ); - -/************************** COP0 CO functions ***********************/ -void r4300i_COP0_CO_TLBR ( usf_state_t * ); -void r4300i_COP0_CO_TLBWI ( usf_state_t * ); -void r4300i_COP0_CO_TLBWR ( usf_state_t * ); -void r4300i_COP0_CO_TLBP ( usf_state_t * ); -void r4300i_COP0_CO_ERET ( usf_state_t * ); - -/************************** COP1 functions **************************/ -void r4300i_COP1_MF ( usf_state_t * ); -void r4300i_COP1_DMF ( usf_state_t * ); -void r4300i_COP1_CF ( usf_state_t * ); -void r4300i_COP1_MT ( usf_state_t * ); -void r4300i_COP1_DMT ( usf_state_t * ); -void r4300i_COP1_CT ( usf_state_t * ); - -/************************* COP1: BC1 functions ***********************/ -void r4300i_COP1_BCF ( usf_state_t * ); -void r4300i_COP1_BCT ( usf_state_t * ); -void r4300i_COP1_BCFL ( usf_state_t * ); -void r4300i_COP1_BCTL ( usf_state_t * ); - -/************************** COP1: S functions ************************/ -void r4300i_COP1_S_ADD ( usf_state_t * ); -void r4300i_COP1_S_SUB ( usf_state_t * ); -void r4300i_COP1_S_MUL ( usf_state_t * ); -void r4300i_COP1_S_DIV ( usf_state_t * ); -void r4300i_COP1_S_SQRT ( usf_state_t * ); -void r4300i_COP1_S_ABS ( usf_state_t * ); -void r4300i_COP1_S_MOV ( usf_state_t * ); -void r4300i_COP1_S_NEG ( usf_state_t * ); -void r4300i_COP1_S_TRUNC_L ( usf_state_t * ); -void r4300i_COP1_S_CEIL_L ( usf_state_t * ); //added by Witten -void r4300i_COP1_S_FLOOR_L ( usf_state_t * ); //added by Witten -void r4300i_COP1_S_ROUND_W ( usf_state_t * ); -void r4300i_COP1_S_TRUNC_W ( usf_state_t * ); -void r4300i_COP1_S_CEIL_W ( usf_state_t * ); //added by Witten -void r4300i_COP1_S_FLOOR_W ( usf_state_t * ); -void r4300i_COP1_S_CVT_D ( usf_state_t * ); -void r4300i_COP1_S_CVT_W ( usf_state_t * ); -void r4300i_COP1_S_CVT_L ( usf_state_t * ); -void r4300i_COP1_S_CMP ( usf_state_t * ); - -/************************** COP1: D functions ************************/ -void r4300i_COP1_D_ADD ( usf_state_t * ); -void r4300i_COP1_D_SUB ( usf_state_t * ); -void r4300i_COP1_D_MUL ( usf_state_t * ); -void r4300i_COP1_D_DIV ( usf_state_t * ); -void r4300i_COP1_D_SQRT ( usf_state_t * ); -void r4300i_COP1_D_ABS ( usf_state_t * ); -void r4300i_COP1_D_MOV ( usf_state_t * ); -void r4300i_COP1_D_NEG ( usf_state_t * ); -void r4300i_COP1_D_TRUNC_L ( usf_state_t * ); //added by Witten -void r4300i_COP1_D_CEIL_L ( usf_state_t * ); //added by Witten -void r4300i_COP1_D_FLOOR_L ( usf_state_t * ); //added by Witten -void r4300i_COP1_D_ROUND_W ( usf_state_t * ); -void r4300i_COP1_D_TRUNC_W ( usf_state_t * ); -void r4300i_COP1_D_CEIL_W ( usf_state_t * ); //added by Witten -void r4300i_COP1_D_FLOOR_W ( usf_state_t * ); //added by Witten -void r4300i_COP1_D_CVT_S ( usf_state_t * ); -void r4300i_COP1_D_CVT_W ( usf_state_t * ); -void r4300i_COP1_D_CVT_L ( usf_state_t * ); -void r4300i_COP1_D_CMP ( usf_state_t * ); - -/************************** COP1: W functions ************************/ -void r4300i_COP1_W_CVT_S ( usf_state_t * ); -void r4300i_COP1_W_CVT_D ( usf_state_t * ); - -/************************** COP1: L functions ************************/ -void r4300i_COP1_L_CVT_S ( usf_state_t * ); -void r4300i_COP1_L_CVT_D ( usf_state_t * ); - -/************************** Other functions **************************/ -void R4300i_UnknownOpcode ( usf_state_t * ); diff --git a/Frameworks/lazyusf/lazyusf/main.c b/Frameworks/lazyusf/lazyusf/main.c deleted file mode 100644 index bcc55f390..000000000 --- a/Frameworks/lazyusf/lazyusf/main.c +++ /dev/null @@ -1,37 +0,0 @@ - -#include -#include -#include -#include -#include "usf.h" -#include "cpu.h" -#include "memory.h" - -#include "usf_internal.h" - -void StopEmulation(usf_state_t * state) -{ - //asm("int $3"); - //printf("Arrivederci!\n\n"); - //Release_Memory(); - //exit(0); - state->cpu_running = 0; -} - -void DisplayError (usf_state_t * state, char * Message, ...) { - va_list ap; - - size_t len = strlen( state->error_message ); - - if ( len ) - state->error_message[ len++ ] = '\n'; - - va_start( ap, Message ); - vsprintf( state->error_message + len, Message, ap ); - va_end( ap ); - - state->last_error = state->error_message; - StopEmulation( state ); - - //printf("Error: %s\n", Msg); -} diff --git a/Frameworks/lazyusf/lazyusf/main.h b/Frameworks/lazyusf/lazyusf/main.h deleted file mode 100644 index df5ea9c23..000000000 --- a/Frameworks/lazyusf/lazyusf/main.h +++ /dev/null @@ -1,6 +0,0 @@ -#include - -#include "usf.h" - -void DisplayError (usf_state_t *, char * Message, ...); -void StopEmulation(usf_state_t *); diff --git a/Frameworks/lazyusf/lazyusf/main/list.h b/Frameworks/lazyusf/lazyusf/main/list.h new file mode 100644 index 000000000..7cbcec26f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/list.h @@ -0,0 +1,127 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - util.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 Mupen64plus development team * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __LIST_H__ +#define __LIST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "osal/preproc.h" + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#define LIST_HEAD(list) \ + struct list_head list = { &(list), &(list) } + +static osal_inline void INIT_LIST_HEAD(struct list_head *head) +{ + head->next = head; + head->prev = head; +} + +static osal_inline void list_add(struct list_head *new_item, struct list_head *head) +{ + struct list_head *next = head->next; + + next->prev = new_item; + new_item->next = next; + new_item->prev = head; + head->next = new_item; +} + +static osal_inline void list_add_tail(struct list_head *new_item, struct list_head *head) +{ + struct list_head *prev = head->prev; + + prev->next = new_item; + new_item->next = head; + new_item->prev = prev; + head->prev = new_item; +} + +static osal_inline void list_del(struct list_head *entry) +{ + struct list_head *next = entry->next; + struct list_head *prev = entry->prev; + + next->prev = prev; + prev->next = next; +} + +static osal_inline void list_del_init(struct list_head *entry) +{ + list_del(entry); + INIT_LIST_HEAD(entry); +} + +static osal_inline int list_empty(const struct list_head *head) +{ + return (head->next == head); +} + +#ifdef __GNUC__ + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#else + +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) + +#endif + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_entry_t(pos, head, type, member) \ + for (pos = list_entry((head)->next, type, member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) + +#define list_for_each_safe(pos, safe, head) \ + for (pos = (head)->next, safe = pos->next; pos != (head); \ + pos = safe, safe = pos->next) + +#define list_for_each_entry_safe_t(pos, safe, head, type, member) \ + for (pos = list_entry((head)->next, type, member), \ + safe = list_entry(pos->member.next, type, member); \ + &pos->member != (head); \ + pos = safe, \ + safe = list_entry(safe->member.next, type, member)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Frameworks/lazyusf/lazyusf/main/main.c b/Frameworks/lazyusf/lazyusf/main/main.c new file mode 100644 index 000000000..fd074168e --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/main.c @@ -0,0 +1,185 @@ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - main.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2008-2009 Richard Goedeken * + * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This is MUPEN64's main entry point. It contains code that is common + * to both the gui and non-gui versions of mupen64. See + * gui subdirectories for the gui-specific code. + * if you want to implement an interface, you should look here + */ + +#include +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#define M64P_CORE_PROTOTYPES 1 +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#include "main.h" +#include "rom.h" +#include "savestates.h" +#include "util.h" + +#include "ai/ai_controller.h" +#include "memory/memory.h" +#include "pi/pi_controller.h" +#include "r4300/r4300.h" +#include "r4300/r4300_core.h" +#include "r4300/interupt.h" +#include "r4300/reset.h" +#include "rdp/rdp_core.h" +#include "ri/ri_controller.h" +#include "rsp/rsp_core.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + +/* version number for Core config section */ +#define CONFIG_PARAM_VERSION 1.01 + +/********************************************************************************************************* +* helper functions +*/ + +void main_message(usf_state_t * state, m64p_msg_level level, unsigned int corner, const char *format, ...) +{ + va_list ap; + char buffer[2049]; + va_start(ap, format); + vsnprintf(buffer, 2047, format, ap); + buffer[2048]='\0'; + va_end(ap); + + /* send message to front-end */ + DebugMessage(state, level, "%s", buffer); +} + +/********************************************************************************************************* +* global functions, for adjusting the core emulator behavior +*/ + +m64p_error main_reset(usf_state_t * state, int do_hard_reset) +{ + if (do_hard_reset) + state->reset_hard_job |= 1; + else + reset_soft(state); + return M64ERR_SUCCESS; +} + +/********************************************************************************************************* +* global functions, callbacks from the r4300 core or from other plugins +*/ + +/* called on vertical interrupt. + * Allow the core to perform various things */ +static void connect_all( + usf_state_t* state, + struct r4300_core* r4300, + struct rdp_core* dp, + struct rsp_core* sp, + struct ai_controller* ai, + struct pi_controller* pi, + struct ri_controller* ri, + struct si_controller* si, + struct vi_controller* vi, + uint32_t* dram, + size_t dram_size, + uint8_t* rom, + size_t rom_size) +{ + connect_r4300(r4300, state); + connect_rdp(dp, r4300, sp, ri); + connect_rsp(sp, r4300, dp, ri); + connect_ai(ai, r4300, ri, vi); + connect_pi(pi, r4300, ri, rom, rom_size); + connect_ri(ri, dram, dram_size); + connect_si(si, r4300, ri); + connect_vi(vi, r4300); +} + +/********************************************************************************************************* +* emulation thread - runs the core +*/ +m64p_error main_start(usf_state_t * state) +{ + unsigned int RDRAMSize; + unsigned int disable_extra_mem; + + memcpy(&RDRAMSize, state->save_state + 4, 4); + to_little_endian_buffer(&RDRAMSize, 4, 1); + + /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */ +#ifdef DEBUG_INFO + state->r4300emu = 0; +#else + state->r4300emu = state->enable_trimming_mode ? 1 : 2; +#endif + + /* set some other core parameters based on the config file values */ + state->no_compiled_jump = 0; + //state->g_delay_si = 1; + state->g_delay_sp = 1; + disable_extra_mem = RDRAMSize == 0x400000; + state->count_per_op = COUNT_PER_OP_DEFAULT; + if (state->count_per_op <= 0) + state->count_per_op = state->ROM_PARAMS.countperop; + + connect_all(state, &state->g_r4300, &state->g_dp, &state->g_sp, + &state->g_ai, &state->g_pi, &state->g_ri, &state->g_si, &state->g_vi, + state->g_rdram, (disable_extra_mem == 0) ? 0x800000 : 0x400000, + state->g_rom, state->g_rom_size); + + init_memory(state, (disable_extra_mem == 0) ? 0x800000 : 0x400000); + + /* connect external audio sink to AI component */ + state->g_ai.user_data = state; + state->g_ai.set_audio_format = usf_set_audio_format; + state->g_ai.push_audio_samples = usf_push_audio_samples; + + /* call r4300 CPU core and run the game */ + r4300_reset_hard(state); + r4300_reset_soft(state); + r4300_begin(state); + + if (!savestates_load(state, state->save_state, state->save_state_size, 0)) + return M64ERR_INVALID_STATE; + + if (state->enableFIFOfull) + { + state->g_delay_ai = 1; + ai_fifo_queue_int(&state->g_ai); + state->g_ai.regs[AI_STATUS_REG] |= 0x40000000; + } + + return M64ERR_SUCCESS; +} + +void main_run(usf_state_t * state) +{ + r4300_execute(state); +} diff --git a/Frameworks/lazyusf/lazyusf/main/main.h b/Frameworks/lazyusf/lazyusf/main/main.h new file mode 100644 index 000000000..b8f82a8d1 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/main.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - main.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2002 Blight * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include "api/m64p_types.h" + +#include + +struct r4300_core; +struct rdp_core; +struct rsp_core; +struct ai_controller; +struct pi_controller; +struct ri_controller; +struct si_controller; +struct vi_controller; + +enum { RDRAM_MAX_SIZE = 0x800000 }; + +/* globals */ +void main_message(usf_state_t *, m64p_msg_level level, unsigned int osd_corner, const char *format, ...); + +m64p_error main_start(usf_state_t *); +void main_run(usf_state_t *); + +#endif /* __MAIN_H__ */ + diff --git a/Frameworks/lazyusf/lazyusf/main/rom.c b/Frameworks/lazyusf/lazyusf/main/rom.c new file mode 100644 index 000000000..ca1cebadc --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/rom.c @@ -0,0 +1,133 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rom.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2008 Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#define M64P_CORE_PROTOTYPES 1 +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#include "rom.h" +#include "main.h" +#include "util.h" + +#include "memory/memory.h" +#include "r4300/r4300.h" + +#define DEFAULT 16 + +#define CHUNKSIZE 1024*128 /* Read files 128KB at a time. */ + +static m64p_system_type rom_country_code_to_system_type(unsigned short country_code); +static int rom_system_type_to_ai_dac_rate(m64p_system_type system_type); +static int rom_system_type_to_vi_limit(m64p_system_type system_type); + +m64p_error open_rom(usf_state_t * state) +{ + if (state->g_rom_size >= sizeof(m64p_rom_header)) + memcpy(&state->ROM_HEADER, state->g_rom, sizeof(m64p_rom_header)); + + /* add some useful properties to ROM_PARAMS */ + state->ROM_PARAMS.systemtype = SYSTEM_NTSC /*rom_country_code_to_system_type(ROM_HEADER.Country_code)*/; + state->ROM_PARAMS.vilimit = rom_system_type_to_vi_limit(state->ROM_PARAMS.systemtype); + state->ROM_PARAMS.aidacrate = rom_system_type_to_ai_dac_rate(state->ROM_PARAMS.systemtype); + state->ROM_PARAMS.countperop = COUNT_PER_OP_DEFAULT; + + return M64ERR_SUCCESS; +} + +m64p_error close_rom(usf_state_t * state) +{ + free(state->g_rom); + state->g_rom = NULL; + + DebugMessage(state, M64MSG_STATUS, "Rom closed."); + + return M64ERR_SUCCESS; +} + +/********************************************************************************************/ +/* ROM utility functions */ + +// Get the system type associated to a ROM country code. +static m64p_system_type rom_country_code_to_system_type(unsigned short country_code) +{ + switch (country_code & 0xFF) + { + // PAL codes + case 0x44: + case 0x46: + case 0x49: + case 0x50: + case 0x53: + case 0x55: + case 0x58: + case 0x59: + return SYSTEM_PAL; + + // NTSC codes + case 0x37: + case 0x41: + case 0x45: + case 0x4a: + default: // Fallback for unknown codes + return SYSTEM_NTSC; + } +} + +// Get the VI (vertical interrupt) limit associated to a ROM system type. +static int rom_system_type_to_vi_limit(m64p_system_type system_type) +{ + switch (system_type) + { + case SYSTEM_PAL: + case SYSTEM_MPAL: + return 50; + + case SYSTEM_NTSC: + default: + return 60; + } +} + +static int rom_system_type_to_ai_dac_rate(m64p_system_type system_type) +{ + switch (system_type) + { + case SYSTEM_PAL: + return 49656530; + case SYSTEM_MPAL: + return 48628316; + case SYSTEM_NTSC: + default: + return 48681812; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/main/rom.h b/Frameworks/lazyusf/lazyusf/main/rom.h new file mode 100644 index 000000000..280b9c62c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/rom.h @@ -0,0 +1,92 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rom.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2008 Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __ROM_H__ +#define __ROM_H__ + +#include "api/m64p_types.h" +#include + +#define BIT(bitnr) (1ULL << (bitnr)) +#ifdef __GNUC__ +#define isset_bitmask(x, bitmask) ({ typeof(bitmask) _bitmask = (bitmask); \ + (_bitmask & (x)) == _bitmask; }) +#else +#define isset_bitmask(x, bitmask) ((bitmask & (x)) == bitmask) +#endif + +/* ROM Loading and Saving functions */ + +m64p_error open_rom(usf_state_t *); +m64p_error close_rom(usf_state_t *); + +typedef struct _rom_params +{ + m64p_system_type systemtype; + int vilimit; + int aidacrate; + char headername[21]; /* ROM Name as in the header, removing trailing whitespace */ + unsigned char countperop; +} rom_params; + +/* Supported rom compressiontypes. */ +enum +{ + UNCOMPRESSED, + ZIP_COMPRESSION, + GZIP_COMPRESSION, + BZIP2_COMPRESSION, + LZMA_COMPRESSION, + SZIP_COMPRESSION +}; + +/* Supported rom image types. */ +enum +{ + Z64IMAGE, + V64IMAGE, + N64IMAGE +}; + +/* Supported CIC chips. */ +enum +{ + CIC_NUS_6101, + CIC_NUS_6102, + CIC_NUS_6103, + CIC_NUS_6105, + CIC_NUS_6106 +}; + +/* Supported save types. */ +enum +{ + EEPROM_4KB, + EEPROM_16KB, + SRAM, + FLASH_RAM, + CONTROLLER_PACK, + NONE +}; + +#endif /* __ROM_H__ */ + diff --git a/Frameworks/lazyusf/lazyusf/main/savestates.c b/Frameworks/lazyusf/lazyusf/main/savestates.c new file mode 100644 index 000000000..f16fac546 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/savestates.c @@ -0,0 +1,639 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - savestates.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2009 Olejl Tillin9 * + * Copyright (C) 2008 Richard42 Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#define M64P_CORE_PROTOTYPES 1 +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#include "savestates.h" +#include "main.h" +#include "rom.h" +#include "util.h" + +#include "ai/ai_controller.h" +#include "memory/memory.h" +#include "r4300/tlb.h" +#include "r4300/cp0.h" +#include "r4300/cp1.h" +#include "r4300/r4300.h" +#include "r4300/r4300_core.h" +#include "r4300/cached_interp.h" +#include "r4300/interupt.h" +#include "pi/pi_controller.h" +#ifdef NEW_DYNAREC +#include "r4300/new_dynarec/new_dynarec.h" +#endif +#include "rdp/rdp_core.h" +#include "ri/ri_controller.h" +#include "rsp/rsp_core.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + +static const char* savestate_magic = "M64+SAVE"; +static const int savestate_latest_version = 0x00010000; /* 1.0 */ +static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 }; + +#define GETARRAY(buff, type, count) \ + (to_little_endian_buffer(buff, sizeof(type),count), \ + buff += count*sizeof(type), \ + (type *)(buff-count*sizeof(type))) +#define COPYARRAY(dst, buff, type, count) \ + memcpy(dst, GETARRAY(buff, type, count), sizeof(type)*count) +#define GETDATA(buff, type) *GETARRAY(buff, type, 1) + +#define PUTARRAY(src, buff, type, count) \ + memcpy(buff, src, sizeof(type)*count); \ + to_little_endian_buffer(buff, sizeof(type), count); \ + buff += count*sizeof(type); + +#define PUTDATA(buff, type, value) \ + do { type x = value; PUTARRAY(&x, buff, type, 1); } while(0) + +#define read_bytes(ptr, size) \ +{ \ + if ((size) > state_size) \ + { \ + if (savestateData) free(savestateData); \ + return 0; \ + } \ + memcpy((ptr), state_ptr, (size)); \ + state_ptr += (size); \ + state_size -= (size); \ +} + +static int savestates_load_m64p(usf_state_t * state, unsigned char * ptr, unsigned int size) +{ + unsigned char header[44]; + int version; + int i; + + unsigned char * state_ptr = ptr; + unsigned int state_size = size; + + size_t savestateSize; + unsigned char *savestateData = 0, *curr; + char queue[1024]; + + /* Read and check Mupen64Plus magic number. */ + read_bytes(header, 44); + curr = header; + + if(strncmp((char *)curr, savestate_magic, 8)!=0) + return 0; + curr += 8; + + version = *curr++; + version = (version << 8) | *curr++; + version = (version << 8) | *curr++; + version = (version << 8) | *curr++; + if(version != 0x00010000) + return 0; + + /* skip MD5 */ + curr += 32; + + /* Read the rest of the savestate */ + savestateSize = 16788244; + if (state_size < savestateSize + sizeof(queue)) + return 0; + + savestateData = curr = malloc(savestateSize); + if (!savestateData) + return 0; + + read_bytes(savestateData, savestateSize); + read_bytes(queue, sizeof(queue)); + + // Parse savestate + state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t); + + curr += 4; /* Padding from old implementation */ + state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t); + curr += 4; // Duplicate MI init mode flags from old implementation + state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t); + state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t); + state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t); + curr += 4; /* Padding from old implementation */ + curr += 8; // Duplicated MI intr flags and padding from old implementation + + state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t); + + state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t); + curr += 4; /* Padding from old implementation */ + state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t); + curr += 16; // Duplicated SP flags and padding from old implementation + state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t); + + state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t); + + state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t); + + state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t); + state->g_vi.delay = GETDATA(curr, unsigned int); + + state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t); + + state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t); + state->g_ai.fifo[1].duration = GETDATA(curr, unsigned int); + state->g_ai.fifo[1].length = GETDATA(curr, uint32_t); + state->g_ai.fifo[0].duration = GETDATA(curr, unsigned int); + state->g_ai.fifo[0].length = GETDATA(curr, uint32_t); + /* best effort initialization of fifo addresses... + * You might get a small sound "pop" because address might be wrong. + * Proper initialization requires changes to savestate format + */ + state->g_ai.fifo[0].address = state->g_ai.regs[AI_DRAM_ADDR_REG]; + state->g_ai.fifo[1].address = state->g_ai.regs[AI_DRAM_ADDR_REG]; + state->g_ai.samples_format_changed = 1; + + state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t); + curr += 4; // Padding from old implementation + state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t); + curr += 12; // Duplicated DPC flags and padding from old implementation + state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t); + + state->g_dp.dps_regs[DPS_TBIST_REG] = GETDATA(curr, uint32_t); + state->g_dp.dps_regs[DPS_TEST_MODE_REG] = GETDATA(curr, uint32_t); + state->g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = GETDATA(curr, uint32_t); + + COPYARRAY(state->g_rdram, curr, uint32_t, RDRAM_MAX_SIZE/4); + COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4); + COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE); + + /*state->g_pi.use_flashram =*/ (void)GETDATA(curr, int); + /*state->g_pi.flashram.mode =*/ (void)GETDATA(curr, int); + /*state->g_pi.flashram.status =*/ (void)GETDATA(curr, unsigned long long); + /*state->g_pi.flashram.erase_offset =*/ (void)GETDATA(curr, unsigned int); + /*state->g_pi.flashram.write_pointer =*/ (void)GETDATA(curr, unsigned int); + + COPYARRAY(state->tlb_LUT_r, curr, unsigned int, 0x100000); + COPYARRAY(state->tlb_LUT_w, curr, unsigned int, 0x100000); + + state->llbit = GETDATA(curr, unsigned int); + COPYARRAY(state->reg, curr, long long int, 32); + COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT); + set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]); + state->lo = GETDATA(curr, long long int); + state->hi = GETDATA(curr, long long int); + COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32); + if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // 32-bit FPR mode requires data shuffling because 64-bit layout is always stored in savestate file + shuffle_fpr_data(state, 0x04000000, 0); + state->FCR0 = GETDATA(curr, int); + state->FCR31 = GETDATA(curr, int); + + for (i = 0; i < 32; i++) + { + state->tlb_e[i].mask = GETDATA(curr, short); + curr += 2; + state->tlb_e[i].vpn2 = GETDATA(curr, int); + state->tlb_e[i].g = GETDATA(curr, char); + state->tlb_e[i].asid = GETDATA(curr, unsigned char); + curr += 2; + state->tlb_e[i].pfn_even = GETDATA(curr, int); + state->tlb_e[i].c_even = GETDATA(curr, char); + state->tlb_e[i].d_even = GETDATA(curr, char); + state->tlb_e[i].v_even = GETDATA(curr, char); + curr++; + state->tlb_e[i].pfn_odd = GETDATA(curr, int); + state->tlb_e[i].c_odd = GETDATA(curr, char); + state->tlb_e[i].d_odd = GETDATA(curr, char); + state->tlb_e[i].v_odd = GETDATA(curr, char); + state->tlb_e[i].r = GETDATA(curr, char); + + state->tlb_e[i].start_even = GETDATA(curr, unsigned int); + state->tlb_e[i].end_even = GETDATA(curr, unsigned int); + state->tlb_e[i].phys_even = GETDATA(curr, unsigned int); + state->tlb_e[i].start_odd = GETDATA(curr, unsigned int); + state->tlb_e[i].end_odd = GETDATA(curr, unsigned int); + state->tlb_e[i].phys_odd = GETDATA(curr, unsigned int); + } + +#ifdef NEW_DYNAREC + if (state->r4300emu == CORE_DYNAREC) { + state->pcaddr = GETDATA(curr, unsigned int); + state->pending_exception = 1; + invalidate_all_pages(state); + } else { + if(state->r4300emu != CORE_PURE_INTERPRETER) + { + for (i = 0; i < 0x100000; i++) + state->invalid_code[i] = 1; + } + generic_jump_to(state, GETDATA(curr, unsigned int)); // PC + } +#else + if(state->r4300emu != CORE_PURE_INTERPRETER) + { + for (i = 0; i < 0x100000; i++) + state->invalid_code[i] = 1; + } + generic_jump_to(state, GETDATA(curr, unsigned int)); // PC +#endif + + state->next_interupt = GETDATA(curr, unsigned int); + state->g_vi.next_vi = GETDATA(curr, unsigned int); + state->g_vi.field = GETDATA(curr, unsigned int); + + free(savestateData); + + // assert(savestateData+savestateSize == curr) + + to_little_endian_buffer(queue, 4, 256); + load_eventqueue_infos(state, queue); + +#ifdef NEW_DYNAREC + if (state->r4300emu == CORE_DYNAREC) + state->last_addr = state->pcaddr; + else + state->last_addr = state->PC->addr; +#else + state->last_addr = state->PC->addr; +#endif + + return 1; +} + +static int savestates_load_pj64(usf_state_t * state, unsigned char * ptr, unsigned int size) +{ + char buffer[1024]; + unsigned int vi_timer, SaveRDRAMSize; + int i; +#ifdef DYNAREC + unsigned long long dummy; +#endif + + unsigned char header[8]; + + unsigned char * state_ptr = ptr; + unsigned int state_size = size; + + size_t savestateSize; + unsigned char *savestateData = 0, *curr; + + /* Read and check Project64 magic number. */ + read_bytes(header, 8); + + curr = header; + if (memcmp(curr, pj64_magic, 4) != 0) + { + return 0; + } + curr += 4; + + SaveRDRAMSize = GETDATA(curr, unsigned int); + + /* Read the rest of the savestate into memory. */ + savestateSize = SaveRDRAMSize + 0x2754; + savestateData = curr = malloc(savestateSize); + if (!savestateData) + return 0; + + if (state_size < savestateSize) + { + free(savestateData); + return 0; + } + + read_bytes(savestateData, savestateSize); + + // skip ROM header + curr += 0x40; + + // vi_timer + vi_timer = GETDATA(curr, unsigned int); + + // Program Counter + state->last_addr = GETDATA(curr, unsigned int); + + // GPR + COPYARRAY(state->reg, curr, long long int, 32); + + // FPR + COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32); + + // CP0 + COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT); + + set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]); + if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // TODO not sure how pj64 handles this + shuffle_fpr_data(state, 0x04000000, 0); + + // Initialze the interupts + vi_timer += state->g_cp0_regs[CP0_COUNT_REG]; + state->next_interupt = (state->g_cp0_regs[CP0_COMPARE_REG] < vi_timer) + ? state->g_cp0_regs[CP0_COMPARE_REG] + : vi_timer; + state->g_vi.next_vi = vi_timer; + state->g_vi.field = 0; + *((unsigned int*)&buffer[0]) = VI_INT; + *((unsigned int*)&buffer[4]) = vi_timer; + *((unsigned int*)&buffer[8]) = COMPARE_INT; + *((unsigned int*)&buffer[12]) = state->g_cp0_regs[CP0_COMPARE_REG]; + *((unsigned int*)&buffer[16]) = 0xFFFFFFFF; + + load_eventqueue_infos(state, buffer); + + // FPCR + state->FCR0 = GETDATA(curr, int); + curr += 30 * 4; // FCR1...FCR30 not supported + state->FCR31 = GETDATA(curr, int); + + // hi / lo + state->hi = GETDATA(curr, long long int); + state->lo = GETDATA(curr, long long int); + + // rdram register + state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t); + state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t); + + // sp_register + state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t); + state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t); + + // dpc_register + state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t); + state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t); + (void)GETDATA(curr, unsigned int); // Dummy read + (void)GETDATA(curr, unsigned int); // Dummy read + + // mi_register + state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t); + state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t); + state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t); + state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t); + + // vi_register + state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t); + state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t); + state->g_vi.delay = (state->g_vi.regs[VI_V_SYNC_REG] == 0) + ? 500000 + : (state->g_vi.regs[VI_V_SYNC_REG] + 1)*1500; + + // ai_register + state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t); + state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t); + state->g_ai.samples_format_changed = 1; + // XXX USF + state->g_ai.regs[AI_STATUS_REG] = 0; + + // pi_register + state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t); + state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t); + + // ri_register + state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t); + state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t); + + // si_register + state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t); + state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t); + + // tlb + memset(state->tlb_LUT_r, 0, 0x400000); + memset(state->tlb_LUT_w, 0, 0x400000); + for (i=0; i < 32; i++) + { + unsigned int MyPageMask, MyEntryHi, MyEntryLo0, MyEntryLo1; + + (void)GETDATA(curr, unsigned int); // Dummy read - EntryDefined + MyPageMask = GETDATA(curr, unsigned int); + MyEntryHi = GETDATA(curr, unsigned int); + MyEntryLo0 = GETDATA(curr, unsigned int); + MyEntryLo1 = GETDATA(curr, unsigned int); + + // This is copied from TLBWI instruction + state->tlb_e[i].g = (MyEntryLo0 & MyEntryLo1 & 1); + state->tlb_e[i].pfn_even = (MyEntryLo0 & 0x3FFFFFC0) >> 6; + state->tlb_e[i].pfn_odd = (MyEntryLo1 & 0x3FFFFFC0) >> 6; + state->tlb_e[i].c_even = (MyEntryLo0 & 0x38) >> 3; + state->tlb_e[i].c_odd = (MyEntryLo1 & 0x38) >> 3; + state->tlb_e[i].d_even = (MyEntryLo0 & 0x4) >> 2; + state->tlb_e[i].d_odd = (MyEntryLo1 & 0x4) >> 2; + state->tlb_e[i].v_even = (MyEntryLo0 & 0x2) >> 1; + state->tlb_e[i].v_odd = (MyEntryLo1 & 0x2) >> 1; + state->tlb_e[i].asid = (MyEntryHi & 0xFF); + state->tlb_e[i].vpn2 = (MyEntryHi & 0xFFFFE000) >> 13; + //state->tlb_e[i].r = (MyEntryHi & 0xC000000000000000LL) >> 62; + state->tlb_e[i].mask = (MyPageMask & 0x1FFE000) >> 13; + + state->tlb_e[i].start_even = state->tlb_e[i].vpn2 << 13; + state->tlb_e[i].end_even = state->tlb_e[i].start_even+ + (state->tlb_e[i].mask << 12) + 0xFFF; + state->tlb_e[i].phys_even = state->tlb_e[i].pfn_even << 12; + + state->tlb_e[i].start_odd = state->tlb_e[i].end_even+1; + state->tlb_e[i].end_odd = state->tlb_e[i].start_odd+ + (state->tlb_e[i].mask << 12) + 0xFFF; + state->tlb_e[i].phys_odd = state->tlb_e[i].pfn_odd << 12; + + tlb_map(state, &state->tlb_e[i]); + } + + // pif ram + COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE); + + // RDRAM + memset(state->g_rdram, 0, RDRAM_MAX_SIZE); + COPYARRAY(state->g_rdram, curr, uint32_t, SaveRDRAMSize/4); + + // DMEM + IMEM + COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4); + + // The following values should not matter because we don't have any AI interrupt + // g_ai.fifo[1].delay = 0; g_ai.fifo[1].length = 0; + // g_ai.fifo[0].delay = 0; g_ai.fifo[0].length = 0; + + // The following is not available in PJ64 savestate. Keep the values as is. + // g_dp.dps_regs[DPS_TBIST_REG] = 0; g_dp.dps_regs[DPS_TEST_MODE_REG] = 0; + // g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = 0; g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = 0; llbit = 0; + + // No flashram info in pj64 savestate. + //init_flashram(&state->g_pi.flashram); + +#ifdef NEW_DYNAREC + if (state->r4300emu == CORE_DYNAREC) { + state->pcaddr = state->last_addr; + state->pending_exception = 1; + invalidate_all_pages(state); + } else { + if(state->r4300emu != CORE_PURE_INTERPRETER) + { + for (i = 0; i < 0x100000; i++) + state->invalid_code[i] = 1; + } + generic_jump_to(state, state->last_addr); + } +#else + if(state->r4300emu != CORE_PURE_INTERPRETER) + { + for (i = 0; i < 0x100000; i++) + state->invalid_code[i] = 1; + } +#ifdef DYNAREC + *(void **)&state->return_address = (void *)&dummy; +#endif + generic_jump_to(state, state->last_addr); +#ifdef DYNAREC + *(void **)&state->return_address = (void *)0; +#endif +#endif + + // assert(savestateData+savestateSize == curr) + + free(savestateData); + return 1; +} + +int savestates_load(usf_state_t * state, unsigned char * ptr, unsigned int size, unsigned int is_m64p) +{ + if (is_m64p) + return savestates_load_m64p(state, ptr, size); + else + return savestates_load_pj64(state, ptr, size); +} diff --git a/Frameworks/lazyusf/lazyusf/main/savestates.h b/Frameworks/lazyusf/lazyusf/main/savestates.h new file mode 100644 index 000000000..35fcd4015 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/savestates.h @@ -0,0 +1,31 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - savestates.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2009 Olejl Tillin9 * + * Copyright (C) 2008 Richard42 Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __SAVESTAVES_H__ +#define __SAVESTAVES_H__ + +int savestates_load(usf_state_t *, unsigned char * ptr, unsigned int size, unsigned int is_m64p); + +#endif /* __SAVESTAVES_H__ */ + diff --git a/Frameworks/lazyusf/lazyusf/main/util.c b/Frameworks/lazyusf/lazyusf/main/util.c new file mode 100644 index 000000000..83252868e --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/util.c @@ -0,0 +1,186 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - util.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/** + * Provides common utilities to the rest of the code: + * -String functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usf/usf.h" + +#include "rom.h" +#include "util.h" +#include "osal/preproc.h" + +/********************** + Byte swap utilities + **********************/ +void swap_buffer(void *buffer, size_t length, size_t count) +{ + size_t i; + if (length == 2) + { + unsigned short *pun = (unsigned short *)buffer; + for (i = 0; i < count; i++) + pun[i] = m64p_swap16(pun[i]); + } + else if (length == 4) + { + unsigned int *pun = (unsigned int *)buffer; + for (i = 0; i < count; i++) + pun[i] = m64p_swap32(pun[i]); + } + else if (length == 8) + { + unsigned long long *pun = (unsigned long long *)buffer; + for (i = 0; i < count; i++) + pun[i] = m64p_swap64(pun[i]); + } +} + +void to_little_endian_buffer(void *buffer, size_t length, size_t count) +{ + #ifdef M64P_BIG_ENDIAN + swap_buffer(buffer, length, count); + #endif +} + +void to_big_endian_buffer(void *buffer, size_t length, size_t count) +{ + #ifndef M64P_BIG_ENDIAN + swap_buffer(buffer, length, count); + #endif +} + +/********************** + String utilities + **********************/ +char *trim(char *str) +{ + char *start = str, *end = str + strlen(str); + + while (start < end && isspace(*start)) + start++; + + while (end > start && isspace(*(end-1))) + end--; + + memmove(str, start, end - start); + str[end - start] = '\0'; + + return str; +} + +int string_to_int(const char *str, int *result) +{ + char *endptr; + long int n; + if (*str == '\0' || isspace(*str)) + return 0; + errno = 0; + n = strtol(str, &endptr, 10); + if (*endptr != '\0' || errno != 0 || n < INT_MIN || n > INT_MAX) + return 0; + *result = (int)n; + return 1; +} + +static unsigned char char2hex(char c) +{ + c = tolower(c); + if(c >= '0' && c <= '9') + return c - '0'; + else if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + return 0xFF; +} + +int parse_hex(const char *str, unsigned char *output, size_t output_size) +{ + size_t i, j; + for (i = 0; i < output_size; i++) + { + output[i] = 0; + for (j = 0; j < 2; j++) + { + unsigned char h = char2hex(*str++); + if (h == 0xFF) + return 0; + + output[i] = (output[i] << 4) | h; + } + } + + if (*str != '\0') + return 0; + + return 1; +} + +char *formatstr(const char *fmt, ...) +{ + int size = 128, ret; + char *str = (char *)malloc(size), *newstr; + va_list args; + + /* There are two implementations of vsnprintf we have to deal with: + * C99 version: Returns the number of characters which would have been written + * if the buffer had been large enough, and -1 on failure. + * Windows version: Returns the number of characters actually written, + * and -1 on failure or truncation. + * NOTE: An implementation equivalent to the Windows one appears in glibc <2.1. + */ + while (str != NULL) + { + va_start(args, fmt); + ret = vsnprintf(str, size, fmt, args); + va_end(args); + + // Successful result? + if (ret >= 0 && ret < size) + return str; + + // Increment the capacity of the buffer + if (ret >= size) + size = ret + 1; // C99 version: We got the needed buffer size + else + size *= 2; // Windows version: Keep guessing + + newstr = (char *)realloc(str, size); + if (newstr == NULL) + free(str); + str = newstr; + } + + return NULL; +} + diff --git a/Frameworks/lazyusf/lazyusf/main/util.h b/Frameworks/lazyusf/lazyusf/main/util.h new file mode 100644 index 000000000..c5015f63e --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/util.h @@ -0,0 +1,213 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - util.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 CasualJames * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "osal/preproc.h" + +/********************** + File utilities + **********************/ + +typedef enum _file_status +{ + file_ok, + file_open_error, + file_read_error, + file_write_error +} file_status_t; + +/** read_from_file + * opens a file and reads the specified number of bytes. + * returns zero on success, nonzero on failure + */ +file_status_t read_from_file(const char *filename, void *data, size_t size); + +/** write_to_file + * opens a file and writes the specified number of bytes. + * returns zero on sucess, nonzero on failure + */ +file_status_t write_to_file(const char *filename, const void *data, size_t size); + +/********************** + Byte swap utilities + **********************/ +#ifdef _MSC_VER +#include +#endif + +/* GCC has also byte swap intrinsics (__builtin_bswap32, etc.), but they were + * added in relatively recent versions. In addition, GCC can detect the byte + * swap code and optimize it with a high enough optimization level. */ + +static osal_inline unsigned short m64p_swap16(unsigned short x) +{ + #ifdef _MSC_VER + return _byteswap_ushort(x); + #else + return ((x & 0x00FF) << 8) | + ((x & 0xFF00) >> 8); + #endif +} + +static osal_inline unsigned int m64p_swap32(unsigned int x) +{ + #ifdef _MSC_VER + return _byteswap_ulong(x); // long is always 32-bit in Windows + #else + return ((x & 0x000000FF) << 24) | + ((x & 0x0000FF00) << 8) | + ((x & 0x00FF0000) >> 8) | + ((x & 0xFF000000) >> 24); + #endif +} + +static osal_inline unsigned long long int m64p_swap64(unsigned long long int x) +{ + #ifdef _MSC_VER + return _byteswap_uint64(x); + #else + return ((x & 0x00000000000000FFULL) << 56) | + ((x & 0x000000000000FF00ULL) << 40) | + ((x & 0x0000000000FF0000ULL) << 24) | + ((x & 0x00000000FF000000ULL) << 8) | + ((x & 0x000000FF00000000ULL) >> 8) | + ((x & 0x0000FF0000000000ULL) >> 24) | + ((x & 0x00FF000000000000ULL) >> 40) | + ((x & 0xFF00000000000000ULL) >> 56); + #endif +} + +#ifdef M64P_BIG_ENDIAN +#define big16(x) (x) +#define big32(x) (x) +#define big64(x) (x) +#define little16(x) m64p_swap16(x) +#define little32(x) m64p_swap32(x) +#define little64(x) m64p_swap64(x) +#else +#define big16(x) m64p_swap16(x) +#define big32(x) m64p_swap32(x) +#define big64(x) m64p_swap64(x) +#define little16(x) (x) +#define little32(x) (x) +#define little64(x) (x) +#endif + +/* Byte swaps, converts to little endian or converts to big endian a buffer, + * containing 'count' elements, each of size 'length'. */ +void swap_buffer(void *buffer, size_t length, size_t count); +void to_little_endian_buffer(void *buffer, size_t length, size_t count); +void to_big_endian_buffer(void *buffer, size_t length, size_t count); + +/********************** + GUI utilities + **********************/ +void countrycodestring(unsigned short countrycode, char *string); +void imagestring(unsigned char imagetype, char *string); + +/********************** + Path utilities + **********************/ + +/* Extracts the full file name (with extension) from a path string. + * Returns the same string, advanced until the file name. */ +const char* namefrompath(const char* path); + +/* Creates a path string by joining two path strings. + * The given path strings may or may not start or end with a path separator. + * Returns a malloc'd string with the resulting path. */ +char* combinepath(const char* first, const char *second); + +/********************** + String utilities + **********************/ + +/** trim + * Removes leading and trailing whitespace from str. Function modifies str + * and also returns modified string. + */ +char *trim(char *str); + +/* Converts an string to an integer. + * Returns 1 on success, 0 on failure. 'result' is undefined on failure. + * + * The following conditions cause this function to fail: + * - Empty string + * - Leading characters (including whitespace) + * - Trailing characters (including whitespace) + * - Overflow or underflow. + */ +int string_to_int(const char *str, int *result); + +/* Converts an string of hexadecimal characters to a byte array. + * 'output_size' is the number of bytes (hex digraphs) to convert. + * Returns 1 on success, 0 on failure. 'output' is undefined on failure. */ +int parse_hex(const char *str, unsigned char *output, size_t output_size); + +/* Formats an string, using the same syntax as printf. + * Returns the result in a malloc'd string. */ +char* formatstr(const char* fmt, ...); + +typedef enum _ini_line_type +{ + INI_BLANK, + INI_COMMENT, + INI_SECTION, + INI_PROPERTY, + INI_TRASH +} ini_line_type; + +typedef struct _ini_line +{ + ini_line_type type; + char *name; + char *value; +} ini_line; + +/* Parses the INI file line pointer by 'lineptr'. + * The first line pointed by 'lineptr' may be modifed. + * 'lineptr' will point to the next line after this function runs. + * + * Returns a ini_line structure with information about the line. + * For INI_COMMENT, the value field contains the comment. + * For INI_SECTION, the name field contains the section name. + * For INI_PROPERTY, the name and value fields contain the property parameters. + * The line type is INI_BLANK if the line is blank or invalid. + * + * The name and value fields (if any) of ini_line point to 'lineptr' + * (so their lifetime is associated to that of 'lineptr'). + */ +ini_line ini_parse_line(char **lineptr); + +#ifdef __cplusplus +} +#endif + +#endif // __UTIL_H__ + diff --git a/Frameworks/lazyusf/lazyusf/main/version.h b/Frameworks/lazyusf/lazyusf/main/version.h new file mode 100644 index 000000000..267582120 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/main/version.h @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Mupen64plus - version.h * +* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * +* Copyright (C) 2008-2012 Richard42 DarkJeztr Tillin9 * +* * +* 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., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Version macros automatically replaced by Makefiles. */ + +#ifndef __VERSION_H__ +#define __VERSION_H__ + +#define MUPEN_CORE_NAME "Mupen64Plus Core" +#define MUPEN_CORE_VERSION 0x020000 + +#define FRONTEND_API_VERSION 0x020101 +#define CONFIG_API_VERSION 0x020300 +#define DEBUG_API_VERSION 0x020000 +#define VIDEXT_API_VERSION 0x030000 + +#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) + +#endif /* __VERSION_H__ */ + + diff --git a/Frameworks/lazyusf/lazyusf/memory.c b/Frameworks/lazyusf/lazyusf/memory.c deleted file mode 100644 index 444e501f8..000000000 --- a/Frameworks/lazyusf/lazyusf/memory.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#include -#include -#include - -#include "usf.h" -#include "main.h" -#include "cpu.h" -#include "audio.h" -#include "rsp.h" - -#include "usf_internal.h" - -uint8_t * PageROM(usf_state_t * state, uint32_t addr) { - return (state->ROMPages[addr/0x10000])?state->ROMPages[addr/0x10000]+(addr%0x10000):&state->EmptySpace; -} - -void * large_alloc(size_t); -void large_free(void *, size_t); - -#ifdef _WIN32 -#include - -void * large_alloc(size_t size) -{ - return VirtualAlloc( NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); -} - -void large_free(void * p, size_t size) -{ - VirtualFree( p, size, MEM_RELEASE ); -} -#else -#include - -#ifdef __APPLE__ -#define MAP_ANONYMOUS MAP_ANON -#endif - -void * large_alloc(size_t size) -{ - return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -} - -void large_free(void * p, size_t size) -{ - munmap( p, size ); -} -#endif - -int32_t Allocate_Memory ( void * state ) { - //uint32_t i = 0; - //RdramSize = 0x800000; - - // Allocate the N64MEM and TLB_Map so that they are in each others 4GB range - // Also put the registers there :) - - - // the mmap technique works craptacular when the regions don't overlay - - USF_STATE->MemChunk = (uint8_t *) large_alloc( 0x100000 * sizeof(uintptr_t) + 0x1D000 + USF_STATE->RdramSize ); - - USF_STATE->TLB_Map = (uintptr_t*)USF_STATE->MemChunk; - if (USF_STATE->TLB_Map == NULL) { - return 0; - } - - memset(USF_STATE->TLB_Map, 0, 0x100000 * sizeof(uintptr_t) + 0x10000); - - USF_STATE->N64MEM = USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t) + 0x10000; - if(USF_STATE->N64MEM == NULL) { - DisplayError(USF_STATE, "Failed to allocate N64MEM"); - return 0; - } - - //memset(state->N64MEM, 0, USF_STATE->RdramSize); - - USF_STATE->NOMEM = USF_STATE->N64MEM + USF_STATE->RdramSize; - - //if(USF_STATE->RdramSize == 0x400000) - //{ - // munmap(N64MEM + 0x400000, 0x400000); - //} - - USF_STATE->Registers = (N64_REGISTERS *)((uintptr_t)USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t)); - //USF_STATE->TLBLoadAddress = (uint32_t *)((uintptr_t)USF_STATE->Registers + 0x500); - //USF_STATE->Timers = (SYSTEM_TIMERS*)(USF_STATE->TLBLoadAddress + 4); - USF_STATE->Timers = (SYSTEM_TIMERS*)((uintptr_t)USF_STATE->Registers + 0x500); - USF_STATE->WaitMode = (uint32_t *)(USF_STATE->Timers + sizeof(SYSTEM_TIMERS)); - USF_STATE->CPU_Action = (CPU_ACTION *)(USF_STATE->WaitMode + 4); - //USF_STATE->RSP_GPR = (struct RSP_GPR_TYPE *)(USF_STATE->CPU_Action + sizeof(CPU_ACTION)); - //USF_STATE->DMEM = (uint8_t *)(USF_STATE->RSP_GPR + (32 * 16)); - USF_STATE->DMEM = (uint8_t *)(USF_STATE->CPU_Action + sizeof(CPU_ACTION)); - //state->RSP_ACCUM = (struct RSP_ACCUM_TYPE *)(USF_STATE->DMEM + 0x2000); - - USF_STATE->RDRAM = (uint8_t *)(USF_STATE->N64MEM); - USF_STATE->IMEM = USF_STATE->DMEM + 0x1000; - - USF_STATE->MemoryState = 1; - - return 1; -} - -int PreAllocate_Memory(usf_state_t * state) { - int i = 0; - - // Moved the savestate allocation here :) (for better management later) - state->savestatespace = (uint8_t *) malloc(0x80275C); - - if(state->savestatespace == 0) - return 0; - - memset(state->savestatespace, 0, 0x80275C); - - for (i = 0; i < 0x400; i++) { - state->ROMPages[i] = 0; - } - - return 1; -} - -void Release_Memory ( usf_state_t * state ) { - uint32_t i; - - for (i = 0; i < 0x400; i++) { - if (state->ROMPages[i]) { - free(state->ROMPages[i]); state->ROMPages[i] = 0; - } - } - //printf("Freeing memory\n"); - - state->MemoryState = 0; - - if (state->MemChunk != 0) { large_free( state->MemChunk, 0x100000 * sizeof(uintptr_t) + 0x1D000 + state->RdramSize ); state->MemChunk=0; } - - if(state->cpu_hle_entries) - free(state->cpu_hle_entries); - state->cpu_hle_entries = NULL; - - if(state->savestatespace) - free(state->savestatespace); - state->savestatespace = NULL; -} - - -int32_t r4300i_LB_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value, uint32_t SignExtend ) { - if (PAddr >= 0x10000000 && PAddr < 0x16000000) { - if (state->WrittenToRom) { return 0; } - if ((PAddr & 2) == 0) { PAddr = (PAddr + 4) ^ 2; } - if ((PAddr - 0x10000000) < state->RomFileSize) { - if (SignExtend) { - *Value = (char)*PageROM(state, (PAddr - 0x10000000)^3); - - } else { - *Value = *PageROM(state, (PAddr - 0x10000000)^3); - } - return 1; - } else { - *Value = 0; - return 0; - } - } - - switch (PAddr & 0xFFF00000) { - default: - * Value = 0; - return 0; - break; - } - return 1; -} - -uint32_t r4300i_LB_VAddr ( usf_state_t * state, uint32_t VAddr, uint8_t * Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - if (address == 0) { return 0; } - *Value = *(uint8_t *)(address + (VAddr ^ 3)); - return 1; -} - -uint32_t r4300i_LD_VAddr ( usf_state_t * state, uint32_t VAddr, uint64_t * Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - if (address == 0) { return 0; } - if (address + VAddr + 7 - (uintptr_t)state->N64MEM >= state->RdramSize) - { - *((uint32_t *)(Value) + 1) = 0; - *((uint32_t *)(Value)) = 0; - return 1; - } - *((uint32_t *)(Value) + 1) = *(uint32_t *)(address + VAddr); - *((uint32_t *)(Value)) = *(uint32_t *)(address + VAddr + 4); - return 1; -} - -int32_t r4300i_LH_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value, int32_t SignExtend ) { - (void)state; - (void)SignExtend; - switch (PAddr & 0xFFF00000) { - default: - * Value = 0; - return 0; - break; - } - return 1; -} - -uint32_t r4300i_LH_VAddr ( usf_state_t * state, uint32_t VAddr, uint16_t * Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - if (address == 0) - return 0; - if (address + (VAddr ^ 2) + 1 - (uintptr_t)state->N64MEM >= state->RdramSize) - { - *Value = 0; - return 1; - } - *Value = *(uint16_t *)(address + (VAddr ^ 2)); - return 1; -} - -int32_t r4300i_LW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value ) { - if (PAddr >= 0x10000000 && PAddr < 0x16000000) { - if (state->WrittenToRom) { - *Value = state->WroteToRom; - //LogMessage("%X: Read crap from Rom %X from %X",PROGRAM_COUNTER,*Value,PAddr); - state->WrittenToRom = 0; - return 1; - } - if ((PAddr - 0x10000000) < state->RomFileSize) { - *Value = *(uint32_t *)PageROM(state, (PAddr - 0x10000000)); - return 1; - } else { - *Value = PAddr & 0xFFFF; - *Value = (*Value << 16) | *Value; - return 0; - } - } - - switch (PAddr & 0xFFF00000) { - case 0x03F00000: - switch (PAddr) { - case 0x03F00000: * Value = RDRAM_CONFIG_REG; break; - case 0x03F00004: * Value = RDRAM_DEVICE_ID_REG; break; - case 0x03F00008: * Value = RDRAM_DELAY_REG; break; - case 0x03F0000C: * Value = RDRAM_MODE_REG; break; - case 0x03F00010: * Value = RDRAM_REF_INTERVAL_REG; break; - case 0x03F00014: * Value = RDRAM_REF_ROW_REG; break; - case 0x03F00018: * Value = RDRAM_RAS_INTERVAL_REG; break; - case 0x03F0001C: * Value = RDRAM_MIN_INTERVAL_REG; break; - case 0x03F00020: * Value = RDRAM_ADDR_SELECT_REG; break; - case 0x03F00024: * Value = RDRAM_DEVICE_MANUF_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04000000: - switch (PAddr) { - case 0x04040010: *Value = SP_STATUS_REG; break; - case 0x04040014: *Value = SP_DMA_FULL_REG; break; - case 0x04040018: *Value = SP_DMA_BUSY_REG; break; - case 0x04080000: *Value = SP_PC_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04100000: - switch (PAddr) { - case 0x0410000C: *Value = DPC_STATUS_REG; break; - case 0x04100010: *Value = DPC_CLOCK_REG; break; - case 0x04100014: *Value = DPC_BUFBUSY_REG; break; - case 0x04100018: *Value = DPC_PIPEBUSY_REG; break; - case 0x0410001C: *Value = DPC_TMEM_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04300000: - switch (PAddr) { - case 0x04300000: * Value = MI_MODE_REG; break; - case 0x04300004: * Value = MI_VERSION_REG; break; - case 0x04300008: * Value = MI_INTR_REG; break; - case 0x0430000C: * Value = MI_INTR_MASK_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04400000: - switch (PAddr) { - case 0x04400000: *Value = VI_STATUS_REG; break; - case 0x04400004: *Value = VI_ORIGIN_REG; break; - case 0x04400008: *Value = VI_WIDTH_REG; break; - case 0x0440000C: *Value = VI_INTR_REG; break; - case 0x04400010: - *Value = 0; - break; - case 0x04400014: *Value = VI_BURST_REG; break; - case 0x04400018: *Value = VI_V_SYNC_REG; break; - case 0x0440001C: *Value = VI_H_SYNC_REG; break; - case 0x04400020: *Value = VI_LEAP_REG; break; - case 0x04400024: *Value = VI_H_START_REG; break; - case 0x04400028: *Value = VI_V_START_REG ; break; - case 0x0440002C: *Value = VI_V_BURST_REG; break; - case 0x04400030: *Value = VI_X_SCALE_REG; break; - case 0x04400034: *Value = VI_Y_SCALE_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04500000: - switch (PAddr) { - case 0x04500004: *Value = AiReadLength(state); break; - case 0x0450000C: *Value = AI_STATUS_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04600000: - switch (PAddr) { - case 0x04600010: *Value = PI_STATUS_REG; break; - case 0x04600014: *Value = PI_DOMAIN1_REG; break; - case 0x04600018: *Value = PI_BSD_DOM1_PWD_REG; break; - case 0x0460001C: *Value = PI_BSD_DOM1_PGS_REG; break; - case 0x04600020: *Value = PI_BSD_DOM1_RLS_REG; break; - case 0x04600024: *Value = PI_DOMAIN2_REG; break; - case 0x04600028: *Value = PI_BSD_DOM2_PWD_REG; break; - case 0x0460002C: *Value = PI_BSD_DOM2_PGS_REG; break; - case 0x04600030: *Value = PI_BSD_DOM2_RLS_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04700000: - switch (PAddr) { - case 0x04700000: * Value = RI_MODE_REG; break; - case 0x04700004: * Value = RI_CONFIG_REG; break; - case 0x04700008: * Value = RI_CURRENT_LOAD_REG; break; - case 0x0470000C: * Value = RI_SELECT_REG; break; - case 0x04700010: * Value = RI_REFRESH_REG; break; - case 0x04700014: * Value = RI_LATENCY_REG; break; - case 0x04700018: * Value = RI_RERROR_REG; break; - case 0x0470001C: * Value = RI_WERROR_REG; break; - default: - * Value = 0; - return 0; - } - break; - case 0x04800000: - switch (PAddr) { - case 0x04800018: *Value = SI_STATUS_REG; break; - default: - *Value = 0; - return 0; - } - break; - case 0x05000000: - *Value = PAddr & 0xFFFF; - *Value = (*Value << 16) | *Value; - return 0; - case 0x08000000: - *Value = 0; - break; - default: - *Value = PAddr & 0xFFFF; - *Value = (*Value << 16) | *Value; - return 0; - break; - } - return 1; -} - -void r4300i_LW_PAddr ( usf_state_t * state, uint32_t PAddr, uint32_t * Value ) { - *Value = *(uint32_t *)(state->N64MEM+PAddr); -} - -uint32_t r4300i_LW_VAddr ( usf_state_t * state, uint32_t VAddr, uint32_t * Value ) { - uintptr_t address = state->TLB_Map[VAddr >> 12]; - if (address == 0) - return 0; - - address += VAddr; - - if((address - (uintptr_t)state->RDRAM) > state->RdramSize) { - address = address - (uintptr_t)state->RDRAM; - return r4300i_LW_NonMemory(state, (uint32_t) address, Value); - } - *Value = *(uint32_t *)address; - return 1; -} - -int32_t r4300i_SB_NonMemory ( usf_state_t * state, uint32_t PAddr, uint8_t Value ) { - switch (PAddr & 0xFFF00000) { - case 0x00000000: - case 0x00100000: - case 0x00200000: - case 0x00300000: - case 0x00400000: - case 0x00500000: - case 0x00600000: - case 0x00700000: - if (PAddr < state->RdramSize) { - *(uint8_t *)(state->N64MEM+PAddr) = Value; - } - break; - default: - return 0; - break; - } - return 1; -} - -uint32_t r4300i_SB_VAddr ( usf_state_t * state, uint32_t VAddr, uint8_t Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - - if (address == 0) { return 0; } - if (address + (VAddr ^ 3) - (uintptr_t)state->N64MEM < state->RdramSize) - *(uint8_t *)(address + (VAddr ^ 3)) = Value; - - return 1; -} - -int32_t r4300i_SH_NonMemory ( usf_state_t * state, uint32_t PAddr, uint16_t Value ) { - switch (PAddr & 0xFFF00000) { - case 0x00000000: - case 0x00100000: - case 0x00200000: - case 0x00300000: - case 0x00400000: - case 0x00500000: - case 0x00600000: - case 0x00700000: - if (PAddr < state->RdramSize) { - *(uint16_t *)(state->N64MEM+PAddr) = Value; - } - break; - default: - return 0; - break; - } - return 1; -} - -uint32_t r4300i_SD_VAddr ( usf_state_t * state, uint32_t VAddr, uint64_t Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - if (address == 0) { return 0; } - if (address + VAddr + 7 - (uintptr_t)state->N64MEM < state->RdramSize) - { - *(uint32_t *)(address + VAddr) = *((uint32_t *)(&Value) + 1); - *(uint32_t *)(address + VAddr + 4) = *((uint32_t *)(&Value)); - } - return 1; -} - -uint32_t r4300i_SH_VAddr ( usf_state_t * state, uint32_t VAddr, uint16_t Value ) { - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - - if (address == 0) { return 0; } - if (address + 1 + (VAddr ^ 2) - (uintptr_t)state->N64MEM < state->RdramSize) - *(uint16_t *)(address + (VAddr ^ 2)) = Value; - return 1; -} - -int32_t r4300i_SW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t Value ) { - if (PAddr >= 0x10000000 && PAddr < 0x16000000) { - if ((PAddr - 0x10000000) < state->RomFileSize) { - state->WrittenToRom = 1; - state->WroteToRom = Value; - } else { - return 0; - } - } - - switch (PAddr & 0xFFF00000) { - case 0x00000000: - case 0x00100000: - case 0x00200000: - case 0x00300000: - case 0x00400000: - case 0x00500000: - case 0x00600000: - case 0x00700000: - if (PAddr < state->RdramSize) { - *(uint32_t *)(state->N64MEM+PAddr) = Value; - } - break; - case 0x03F00000: - switch (PAddr) { - case 0x03F00000: RDRAM_CONFIG_REG = Value; break; - case 0x03F00004: RDRAM_DEVICE_ID_REG = Value; break; - case 0x03F00008: RDRAM_DELAY_REG = Value; break; - case 0x03F0000C: RDRAM_MODE_REG = Value; break; - case 0x03F00010: RDRAM_REF_INTERVAL_REG = Value; break; - case 0x03F00014: RDRAM_REF_ROW_REG = Value; break; - case 0x03F00018: RDRAM_RAS_INTERVAL_REG = Value; break; - case 0x03F0001C: RDRAM_MIN_INTERVAL_REG = Value; break; - case 0x03F00020: RDRAM_ADDR_SELECT_REG = Value; break; - case 0x03F00024: RDRAM_DEVICE_MANUF_REG = Value; break; - case 0x03F04004: break; - case 0x03F08004: break; - case 0x03F80004: break; - case 0x03F80008: break; - case 0x03F8000C: break; - case 0x03F80014: break; - default: - return 0; - } - break; - case 0x04000000: - if (PAddr < 0x04002000) { - *(uint32_t *)(state->N64MEM+PAddr) = Value; - return 1; - } - switch (PAddr) { - case 0x04040000: SP_MEM_ADDR_REG = Value; break; - case 0x04040004: SP_DRAM_ADDR_REG = Value; break; - case 0x04040008: - SP_RD_LEN_REG = Value; - SP_DMA_READ(state); - break; - case 0x0404000C: - SP_WR_LEN_REG = Value; - SP_DMA_WRITE(state); - break; - case 0x04040010: - if ( ( Value & SP_CLR_HALT ) != 0) { SP_STATUS_REG &= ~SP_STATUS_HALT; } - if ( ( Value & SP_SET_HALT ) != 0) { SP_STATUS_REG |= SP_STATUS_HALT; } - if ( ( Value & SP_CLR_BROKE ) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; } - if ( ( Value & SP_CLR_INTR ) != 0) { - MI_INTR_REG &= ~MI_INTR_SP; - CheckInterrupts(state); - } - if ( ( Value & SP_CLR_SSTEP ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SSTEP; } - if ( ( Value & SP_SET_SSTEP ) != 0) { SP_STATUS_REG |= SP_STATUS_SSTEP; } - if ( ( Value & SP_CLR_INTR_BREAK ) != 0) { SP_STATUS_REG &= ~SP_STATUS_INTR_BREAK; } - if ( ( Value & SP_SET_INTR_BREAK ) != 0) { SP_STATUS_REG |= SP_STATUS_INTR_BREAK; } - if ( ( Value & SP_CLR_SIG0 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG0; } - if ( ( Value & SP_SET_SIG0 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG0; } - if ( ( Value & SP_CLR_SIG1 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG1; } - if ( ( Value & SP_SET_SIG1 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG1; } - if ( ( Value & SP_CLR_SIG2 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG2; } - if ( ( Value & SP_SET_SIG2 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG2; } - if ( ( Value & SP_CLR_SIG3 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG3; } - if ( ( Value & SP_SET_SIG3 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG3; } - if ( ( Value & SP_CLR_SIG4 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG4; } - if ( ( Value & SP_SET_SIG4 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG4; } - if ( ( Value & SP_CLR_SIG5 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG5; } - if ( ( Value & SP_SET_SIG5 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG5; } - if ( ( Value & SP_CLR_SIG6 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG6; } - if ( ( Value & SP_SET_SIG6 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG6; } - if ( ( Value & SP_CLR_SIG7 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG7; } - if ( ( Value & SP_SET_SIG7 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; } - - RunRsp(state); - - break; - case 0x0404001C: SP_SEMAPHORE_REG = 0; break; - case 0x04080000: SP_PC_REG = Value & 0xFFC; break; - default: - return 0; - } - break; - case 0x04100000: - switch (PAddr) { - case 0x04100000: - DPC_START_REG = Value; - DPC_CURRENT_REG = Value; - break; - case 0x04100004: - DPC_END_REG = Value; - break; - case 0x04100008: DPC_CURRENT_REG = Value; break; - case 0x0410000C: - if ( ( Value & DPC_CLR_XBUS_DMEM_DMA ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_XBUS_DMEM_DMA; } - if ( ( Value & DPC_SET_XBUS_DMEM_DMA ) != 0) { DPC_STATUS_REG |= DPC_STATUS_XBUS_DMEM_DMA; } - if ( ( Value & DPC_CLR_FREEZE ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_FREEZE; } - if ( ( Value & DPC_SET_FREEZE ) != 0) { DPC_STATUS_REG |= DPC_STATUS_FREEZE; } - if ( ( Value & DPC_CLR_FLUSH ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_FLUSH; } - if ( ( Value & DPC_SET_FLUSH ) != 0) { DPC_STATUS_REG |= DPC_STATUS_FLUSH; } - if ( ( Value & DPC_CLR_FREEZE ) != 0) - { - if ( ( SP_STATUS_REG & SP_STATUS_HALT ) == 0) - { - if ( ( SP_STATUS_REG & SP_STATUS_BROKE ) == 0 ) - { - RunRsp(state); - } - } - } - break; - default: - return 0; - } - break; - case 0x04300000: - switch (PAddr) { - case 0x04300000: - MI_MODE_REG &= ~0x7F; - MI_MODE_REG |= (Value & 0x7F); - if ( ( Value & MI_CLR_INIT ) != 0 ) { MI_MODE_REG &= ~MI_MODE_INIT; } - if ( ( Value & MI_SET_INIT ) != 0 ) { MI_MODE_REG |= MI_MODE_INIT; } - if ( ( Value & MI_CLR_EBUS ) != 0 ) { MI_MODE_REG &= ~MI_MODE_EBUS; } - if ( ( Value & MI_SET_EBUS ) != 0 ) { MI_MODE_REG |= MI_MODE_EBUS; } - if ( ( Value & MI_CLR_DP_INTR ) != 0 ) { - MI_INTR_REG &= ~MI_INTR_DP; - CheckInterrupts(state); - } - if ( ( Value & MI_CLR_RDRAM ) != 0 ) { MI_MODE_REG &= ~MI_MODE_RDRAM; } - if ( ( Value & MI_SET_RDRAM ) != 0 ) { MI_MODE_REG |= MI_MODE_RDRAM; } - break; - case 0x0430000C: - if ( ( Value & MI_INTR_MASK_CLR_SP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SP; } - if ( ( Value & MI_INTR_MASK_SET_SP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SP; } - if ( ( Value & MI_INTR_MASK_CLR_SI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SI; } - if ( ( Value & MI_INTR_MASK_SET_SI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SI; } - if ( ( Value & MI_INTR_MASK_CLR_AI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_AI; } - if ( ( Value & MI_INTR_MASK_SET_AI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_AI; } - if ( ( Value & MI_INTR_MASK_CLR_VI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_VI; } - if ( ( Value & MI_INTR_MASK_SET_VI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_VI; } - if ( ( Value & MI_INTR_MASK_CLR_PI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_PI; } - if ( ( Value & MI_INTR_MASK_SET_PI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_PI; } - if ( ( Value & MI_INTR_MASK_CLR_DP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_DP; } - if ( ( Value & MI_INTR_MASK_SET_DP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_DP; } - break; - default: - return 0; - } - break; - case 0x04400000: - switch (PAddr) { - case 0x04400000: - //if (VI_STATUS_REG != Value) { - VI_STATUS_REG = Value; - // if (ViStatusChanged != NULL ) { ViStatusChanged(); } - //} - break; - case 0x04400004: - - VI_ORIGIN_REG = (Value & 0xFFFFFF); - //if (UpdateScreen != NULL ) { UpdateScreen(); } - break; - case 0x04400008: - //if (VI_WIDTH_REG != Value) { - VI_WIDTH_REG = Value; - // if (ViWidthChanged != NULL ) { ViWidthChanged(); } - //} - break; - case 0x0440000C: VI_INTR_REG = Value; break; - case 0x04400010: - MI_INTR_REG &= ~MI_INTR_VI; - CheckInterrupts(state); - break; - case 0x04400014: VI_BURST_REG = Value; break; - case 0x04400018: VI_V_SYNC_REG = Value; break; - case 0x0440001C: VI_H_SYNC_REG = Value; break; - case 0x04400020: VI_LEAP_REG = Value; break; - case 0x04400024: VI_H_START_REG = Value; break; - case 0x04400028: VI_V_START_REG = Value; break; - case 0x0440002C: VI_V_BURST_REG = Value; break; - case 0x04400030: VI_X_SCALE_REG = Value; break; - case 0x04400034: VI_Y_SCALE_REG = Value; break; - default: - return 0; - } - break; - case 0x04500000: - switch (PAddr) { - case 0x04500000: AI_DRAM_ADDR_REG = Value; break; - case 0x04500004: - AI_LEN_REG = Value; - AiLenChanged(state); - break; - case 0x04500008: AI_CONTROL_REG = (Value & 0x1); break; - case 0x0450000C: - /* Clear Interrupt */; - MI_INTR_REG &= ~MI_INTR_AI; - state->AudioIntrReg &= ~MI_INTR_AI; - CheckInterrupts(state); - break; - case 0x04500010: - AI_DACRATE_REG = Value; - //if (AiDacrateChanged != NULL) { AiDacrateChanged(SYSTEM_NTSC); } - break; - case 0x04500014: AI_BITRATE_REG = Value; break; - default: - return 0; - } - break; - case 0x04600000: - switch (PAddr) { - case 0x04600000: PI_DRAM_ADDR_REG = Value; break; - case 0x04600004: PI_CART_ADDR_REG = Value; break; - case 0x04600008: - PI_RD_LEN_REG = Value; - PI_DMA_READ(state); - break; - case 0x0460000C: - PI_WR_LEN_REG = Value; - PI_DMA_WRITE(state); - break; - case 0x04600010: - //if ((Value & PI_SET_RESET) != 0 ) { DisplayError(state, "reset Controller"); } - if ((Value & PI_CLR_INTR) != 0 ) { - MI_INTR_REG &= ~MI_INTR_PI; - CheckInterrupts(state); - } - break; - case 0x04600014: PI_DOMAIN1_REG = (Value & 0xFF); break; - case 0x04600018: PI_BSD_DOM1_PWD_REG = (Value & 0xFF); break; - case 0x0460001C: PI_BSD_DOM1_PGS_REG = (Value & 0xFF); break; - case 0x04600020: PI_BSD_DOM1_RLS_REG = (Value & 0xFF); break; - default: - return 0; - } - break; - case 0x04700000: - switch (PAddr) { - case 0x04700000: RI_MODE_REG = Value; break; - case 0x04700004: RI_CONFIG_REG = Value; break; - case 0x04700008: RI_CURRENT_LOAD_REG = Value; break; - case 0x0470000C: RI_SELECT_REG = Value; break; - case 0x04700010: RI_REFRESH_REG = Value; break; - case 0x04700014: RI_LATENCY_REG = Value; break; - case 0x04700018: RI_RERROR_REG = Value; break; - case 0x0470001C: RI_WERROR_REG = Value; break; - default: - return 0; - } - break; - case 0x04800000: - switch (PAddr) { - case 0x04800000: SI_DRAM_ADDR_REG = Value; break; - case 0x04800004: - SI_PIF_ADDR_RD64B_REG = Value; - SI_DMA_READ (state); - break; - case 0x04800010: - SI_PIF_ADDR_WR64B_REG = Value; - SI_DMA_WRITE(state); - break; - case 0x04800018: - MI_INTR_REG &= ~MI_INTR_SI; - SI_STATUS_REG &= ~SI_STATUS_INTERRUPT; - CheckInterrupts(state); - break; - default: - return 0; - } - break; - case 0x08000000: - if (PAddr != 0x08010000) { return 0; } - break; - case 0x1FC00000: - if (PAddr < 0x1FC007C0) { - return 0; - } else if (PAddr < 0x1FC00800) { - - if (PAddr == 0x1FC007FC) { - PifRamWrite(state); - } - return 1; - } - return 0; - break; - default: - return 0; - break; - } - return 1; -} - -uint32_t r4300i_SW_VAddr ( usf_state_t * state, uint32_t VAddr, uint32_t Value ) { - - uintptr_t address; - address = state->TLB_Map[VAddr >> 12]; - - if (address == 0) { return 0; } - address = (address + VAddr); - - if((address - (uintptr_t)state->RDRAM) > state->RdramSize) { - address = address - (uintptr_t)state->RDRAM; - return r4300i_SW_NonMemory(state, (uint32_t) address, Value); - } - *(uint32_t *)address = Value; - return 1; -} - -void memcpyn642n64(usf_state_t * state, uint32_t dest, uint32_t src, uint32_t len) -{ - uint32_t i; - uint32_t temp; - - for (i = 0; i < len; i += 4) - { - uintptr_t dstAddr = state->TLB_Map[(dest + i) >> 12]; - uintptr_t srcAddr = state->TLB_Map[(src + i) >> 12]; - - if (srcAddr) - temp = *(uint32_t*)(srcAddr + src + i); - else - temp = 0; - - if (dstAddr) - *(uint32_t*)(dstAddr + dest + i) = temp; - } -} diff --git a/Frameworks/lazyusf/lazyusf/memory.h b/Frameworks/lazyusf/lazyusf/memory.h deleted file mode 100644 index 5a2afdebb..000000000 --- a/Frameworks/lazyusf/lazyusf/memory.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#define LargeCompileBufferSize 0x03200000 -#define NormalCompileBufferSize 0x01500000 - -#define RSP_RECOMPMEM_SIZE 0x400000 -#define RSP_SECRECOMPMEM_SIZE 0x200000 - -#define ROM_IN_MAPSPACE - -#define PageRAM2(x) (state->N64MEM+(uint32_t)(x)) -#define PageVRAM(x) (state->TLB_Map[((uint32_t)(x))>>12]+(uint32_t)(x)) -#define PageVRAM2(x) (uint32_t)(PageVRAM(x)-(uintptr_t)state->N64MEM) - -/* Memory Control */ -int Allocate_Memory ( void * ); -void Release_Memory ( usf_state_t * ); -int PreAllocate_Memory( usf_state_t * ); - -/* CPU memory functions */ -//int r4300i_Command_MemoryFilter ( uint32_t dwExptCode, LPEXCEPTION_POINTERS lpEP ); -//int r4300i_CPU_MemoryFilter ( uint32_t dwExptCode, LPEXCEPTION_POINTERS lpEP ); -int32_t r4300i_LB_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value, uint32_t SignExtend ); -uint32_t r4300i_LB_VAddr ( usf_state_t *, uint32_t VAddr, uint8_t * Value ); -uint32_t r4300i_LD_VAddr ( usf_state_t *, uint32_t VAddr, uint64_t * Value ); -int32_t r4300i_LH_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value, int32_t SignExtend ); -uint32_t r4300i_LH_VAddr ( usf_state_t *, uint32_t VAddr, uint16_t * Value ); -int32_t r4300i_LW_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value ); -void r4300i_LW_PAddr ( usf_state_t *, uint32_t PAddr, uint32_t * Value ); -uint32_t r4300i_LW_VAddr ( usf_state_t *, uint32_t VAddr, uint32_t * Value ); -int32_t r4300i_SB_NonMemory ( usf_state_t *, uint32_t PAddr, uint8_t Value ); -uint32_t r4300i_SB_VAddr ( usf_state_t *, uint32_t VAddr, uint8_t Value ); -uint32_t r4300i_SD_VAddr ( usf_state_t *, uint32_t VAddr, uint64_t Value ); -int32_t r4300i_SH_NonMemory ( usf_state_t *, uint32_t PAddr, uint16_t Value ); -uint32_t r4300i_SH_VAddr ( usf_state_t *, uint32_t VAddr, uint16_t Value ); -int32_t r4300i_SW_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t Value ); -uint32_t r4300i_SW_VAddr ( usf_state_t *, uint32_t VAddr, uint32_t Value ); - -uint8_t * PageROM(usf_state_t *, uint32_t addr); - -void memcpyn642n64(usf_state_t *, uint32_t dest, uint32_t src, uint32_t len); diff --git a/Frameworks/lazyusf/lazyusf/memory/memory.c b/Frameworks/lazyusf/lazyusf/memory/memory.c new file mode 100644 index 000000000..b9a318fc9 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/memory/memory.c @@ -0,0 +1,1257 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - memory.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "memory.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#include "main/main.h" +#include "main/rom.h" + +#include "r4300/r4300.h" +#include "r4300/r4300_core.h" +#include "r4300/cached_interp.h" +#include "r4300/new_dynarec/new_dynarec.h" +#include "r4300/recomph.h" +#include "r4300/ops.h" +#include "r4300/tlb.h" + +#include "rdp/rdp_core.h" +#include "rsp/rsp_core.h" + +#include "ai/ai_controller.h" +#include "pi/pi_controller.h" +#include "ri/ri_controller.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + +#ifdef DBG +#include "debugger/dbg_types.h" +#include "debugger/dbg_memory.h" +#include "debugger/dbg_breakpoints.h" + +#include +#endif + +#include +#include + +#include "osal/preproc.h" + +typedef int (*readfn)(void*, uint32_t, uint32_t*); +typedef int (*writefn)(void*, uint32_t, uint32_t, uint32_t); + +static osal_inline unsigned int bshift(uint32_t address) +{ + return ((address & 3) ^ 3) << 3; +} + +static osal_inline unsigned int hshift(uint32_t address) +{ + return ((address & 2) ^ 2) << 3; +} + +static int readb(readfn read_word, void* opaque, uint32_t address, unsigned long long int* value) +{ + uint32_t w; + unsigned shift = bshift(address); + int result = read_word(opaque, address, &w); + *value = (w >> shift) & 0xff; + + return result; +} + +static int readh(readfn read_word, void* opaque, uint32_t address, unsigned long long int* value) +{ + uint32_t w; + unsigned shift = hshift(address); + int result = read_word(opaque, address, &w); + *value = (w >> shift) & 0xffff; + + return result; +} + +static int readw(readfn read_word, void* opaque, uint32_t address, unsigned long long int* value) +{ + uint32_t w; + int result = read_word(opaque, address, &w); + *value = w; + + return result; +} + +static int readd(readfn read_word, void* opaque, uint32_t address, unsigned long long int* value) +{ + uint32_t w[2]; + int result = + read_word(opaque, address , &w[0]); + read_word(opaque, address + 4, &w[1]); + *value = ((uint64_t)w[0] << 32) | w[1]; + + return result; +} + +static int writeb(writefn write_word, void* opaque, uint32_t address, uint8_t value) +{ + unsigned int shift = bshift(address); + uint32_t w = (uint32_t)value << shift; + uint32_t mask = (uint32_t)0xff << shift; + + return write_word(opaque, address, w, mask); +} + +static int writeh(writefn write_word, void* opaque, uint32_t address, uint16_t value) +{ + unsigned int shift = hshift(address); + uint32_t w = (uint32_t)value << shift; + uint32_t mask = (uint32_t)0xffff << shift; + + return write_word(opaque, address, w, mask); +} + +static int writew(writefn write_word, void* opaque, uint32_t address, uint32_t value) +{ + return write_word(opaque, address, value, ~0U); +} + +static int writed(writefn write_word, void* opaque, uint32_t address, uint64_t value) +{ + int result = + write_word(opaque, address , value >> 32, ~0U); + write_word(opaque, address + 4, value , ~0U); + + return result; +} + + +static void osal_fastcall invalidate_code(usf_state_t * state, uint32_t address) +{ + if (state->r4300emu != CORE_PURE_INTERPRETER && !state->invalid_code[address>>12]) + if (state->blocks[address>>12]->block[(address&0xFFF)/4].ops != + state->current_instruction_table.NOTCOMPILED) + state->invalid_code[address>>12] = 1; +} + + +static void osal_fastcall read_nothing(usf_state_t * state) +{ + *state->rdword = 0; +} + +static void osal_fastcall read_nothingb(usf_state_t * state) +{ + *state->rdword = 0; +} + +static void osal_fastcall read_nothingh(usf_state_t * state) +{ + *state->rdword = 0; +} + +static void osal_fastcall read_nothingd(usf_state_t * state) +{ + *state->rdword = 0; +} + +static void osal_fastcall write_nothing(usf_state_t * state) +{ +} + +static void osal_fastcall write_nothingb(usf_state_t * state) +{ +} + +static void osal_fastcall write_nothingh(usf_state_t * state) +{ +} + +static void osal_fastcall write_nothingd(usf_state_t * state) +{ +} + +static void osal_fastcall read_nomem(usf_state_t * state) +{ + state->address = virtual_to_physical_address(state,state->address,0); + if (state->address == 0x00000000) return; + read_word_in_memory(); +} + +static void osal_fastcall read_nomemb(usf_state_t * state) +{ + state->address = virtual_to_physical_address(state,state->address,0); + if (state->address == 0x00000000) return; + read_byte_in_memory(); +} + +static void osal_fastcall read_nomemh(usf_state_t * state) +{ + state->address = virtual_to_physical_address(state,state->address,0); + if (state->address == 0x00000000) return; + read_hword_in_memory(); +} + +static void osal_fastcall read_nomemd(usf_state_t * state) +{ + state->address = virtual_to_physical_address(state,state->address,0); + if (state->address == 0x00000000) return; + read_dword_in_memory(); +} + +static void osal_fastcall write_nomem(usf_state_t * state) +{ + invalidate_code(state,state->address); + state->address = virtual_to_physical_address(state,state->address,1); + if (state->address == 0x00000000) return; + write_word_in_memory(); +} + +static void osal_fastcall write_nomemb(usf_state_t * state) +{ + invalidate_code(state,state->address); + state->address = virtual_to_physical_address(state,state->address,1); + if (state->address == 0x00000000) return; + write_byte_in_memory(); +} + +static void osal_fastcall write_nomemh(usf_state_t * state) +{ + invalidate_code(state,state->address); + state->address = virtual_to_physical_address(state,state->address,1); + if (state->address == 0x00000000) return; + write_hword_in_memory(); +} + +static void osal_fastcall write_nomemd(usf_state_t * state) +{ + invalidate_code(state,state->address); + state->address = virtual_to_physical_address(state,state->address,1); + if (state->address == 0x00000000) return; + write_dword_in_memory(); +} + + +void osal_fastcall read_rdram(usf_state_t * state) +{ + readw(read_rdram_dram, &state->g_ri, state->address, state->rdword); +} + +void osal_fastcall read_rdramb(usf_state_t * state) +{ + readb(read_rdram_dram, &state->g_ri, state->address, state->rdword); +} + +void osal_fastcall read_rdramh(usf_state_t * state) +{ + readh(read_rdram_dram, &state->g_ri, state->address, state->rdword); +} + +void osal_fastcall read_rdramd(usf_state_t * state) +{ + readd(read_rdram_dram, &state->g_ri, state->address, state->rdword); +} + +void osal_fastcall write_rdram(usf_state_t * state) +{ + writew(write_rdram_dram, &state->g_ri, state->address, state->cpu_word); +} + +void osal_fastcall write_rdramb(usf_state_t * state) +{ + writeb(write_rdram_dram, &state->g_ri, state->address, state->cpu_byte); +} + +void osal_fastcall write_rdramh(usf_state_t * state) +{ + writeh(write_rdram_dram, &state->g_ri, state->address, state->cpu_hword); +} + +void osal_fastcall write_rdramd(usf_state_t * state) +{ + writed(write_rdram_dram, &state->g_ri, state->address, state->cpu_dword); +} + + +void osal_fastcall read_rdram_tracked(usf_state_t * state) +{ + readw(read_rdram_dram_tracked, state, state->address, state->rdword); +} + +void osal_fastcall read_rdram_trackedb(usf_state_t * state) +{ + readb(read_rdram_dram_tracked, state, state->address, state->rdword); +} + +void osal_fastcall read_rdram_trackedh(usf_state_t * state) +{ + readh(read_rdram_dram_tracked, state, state->address, state->rdword); +} + +void osal_fastcall read_rdram_trackedd(usf_state_t * state) +{ + readd(read_rdram_dram_tracked, state, state->address, state->rdword); +} + +void osal_fastcall write_rdram_tracked(usf_state_t * state) +{ + writew(write_rdram_dram_tracked, state, state->address, state->cpu_word); +} + +void osal_fastcall write_rdram_trackedb(usf_state_t * state) +{ + writeb(write_rdram_dram_tracked, state, state->address, state->cpu_byte); +} + +void osal_fastcall write_rdram_trackedh(usf_state_t * state) +{ + writeh(write_rdram_dram_tracked, state, state->address, state->cpu_hword); +} + +void osal_fastcall write_rdram_trackedd(usf_state_t * state) +{ + writed(write_rdram_dram_tracked, state, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_rdramreg(usf_state_t * state) +{ + readw(read_rdram_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rdramregb(usf_state_t * state) +{ + readb(read_rdram_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rdramregh(usf_state_t * state) +{ + readh(read_rdram_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rdramregd(usf_state_t * state) +{ + readd(read_rdram_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall write_rdramreg(usf_state_t * state) +{ + writew(write_rdram_regs, &state->g_ri, state->address, state->cpu_word); +} + +static void osal_fastcall write_rdramregb(usf_state_t * state) +{ + writeb(write_rdram_regs, &state->g_ri, state->address, state->cpu_byte); +} + +static void osal_fastcall write_rdramregh(usf_state_t * state) +{ + writeh(write_rdram_regs, &state->g_ri, state->address, state->cpu_hword); +} + +static void osal_fastcall write_rdramregd(usf_state_t * state) +{ + writed(write_rdram_regs, &state->g_ri, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_rspmem(usf_state_t * state) +{ + readw(read_rsp_mem, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspmemb(usf_state_t * state) +{ + readb(read_rsp_mem, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspmemh(usf_state_t * state) +{ + readh(read_rsp_mem, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspmemd(usf_state_t * state) +{ + readd(read_rsp_mem, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall write_rspmem(usf_state_t * state) +{ + writew(write_rsp_mem, &state->g_sp, state->address, state->cpu_word); +} + +static void osal_fastcall write_rspmemb(usf_state_t * state) +{ + writeb(write_rsp_mem, &state->g_sp, state->address, state->cpu_byte); +} + +static void osal_fastcall write_rspmemh(usf_state_t * state) +{ + writeh(write_rsp_mem, &state->g_sp, state->address, state->cpu_hword); +} + +static void osal_fastcall write_rspmemd(usf_state_t * state) +{ + writed(write_rsp_mem, &state->g_sp, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_rspreg(usf_state_t * state) +{ + readw(read_rsp_regs, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspregb(usf_state_t * state) +{ + readb(read_rsp_regs, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspregh(usf_state_t * state) +{ + readh(read_rsp_regs, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspregd(usf_state_t * state) +{ + readd(read_rsp_regs, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall write_rspreg(usf_state_t * state) +{ + writew(write_rsp_regs, &state->g_sp, state->address, state->cpu_word); +} + +static void osal_fastcall write_rspregb(usf_state_t * state) +{ + writeb(write_rsp_regs, &state->g_sp, state->address, state->cpu_byte); +} + +static void osal_fastcall write_rspregh(usf_state_t * state) +{ + writeh(write_rsp_regs, &state->g_sp, state->address, state->cpu_hword); +} + +static void osal_fastcall write_rspregd(usf_state_t * state) +{ + writed(write_rsp_regs, &state->g_sp, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_rspreg2(usf_state_t * state) +{ + readw(read_rsp_regs2, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspreg2b(usf_state_t * state) +{ + readb(read_rsp_regs2, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspreg2h(usf_state_t * state) +{ + readh(read_rsp_regs2, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall read_rspreg2d(usf_state_t * state) +{ + readd(read_rsp_regs2, &state->g_sp, state->address, state->rdword); +} + +static void osal_fastcall write_rspreg2(usf_state_t * state) +{ + writew(write_rsp_regs2, &state->g_sp, state->address, state->cpu_word); +} + +static void osal_fastcall write_rspreg2b(usf_state_t * state) +{ + writeb(write_rsp_regs2, &state->g_sp, state->address, state->cpu_byte); +} + +static void osal_fastcall write_rspreg2h(usf_state_t * state) +{ + writeh(write_rsp_regs2, &state->g_sp, state->address, state->cpu_hword); +} + +static void osal_fastcall write_rspreg2d(usf_state_t * state) +{ + writed(write_rsp_regs2, &state->g_sp, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_dp(usf_state_t * state) +{ + readw(read_dpc_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dpb(usf_state_t * state) +{ + readb(read_dpc_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dph(usf_state_t * state) +{ + readh(read_dpc_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dpd(usf_state_t * state) +{ + readd(read_dpc_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall write_dp(usf_state_t * state) +{ + writew(write_dpc_regs, &state->g_dp, state->address, state->cpu_word); +} + +static void osal_fastcall write_dpb(usf_state_t * state) +{ + writeb(write_dpc_regs, &state->g_dp, state->address, state->cpu_byte); +} + +static void osal_fastcall write_dph(usf_state_t * state) +{ + writeh(write_dpc_regs, &state->g_dp, state->address, state->cpu_hword); +} + +static void osal_fastcall write_dpd(usf_state_t * state) +{ + writed(write_dpc_regs, &state->g_dp, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_dps(usf_state_t * state) +{ + readw(read_dps_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dpsb(usf_state_t * state) +{ + readb(read_dps_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dpsh(usf_state_t * state) +{ + readh(read_dps_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall read_dpsd(usf_state_t * state) +{ + readd(read_dps_regs, &state->g_dp, state->address, state->rdword); +} + +static void osal_fastcall write_dps(usf_state_t * state) +{ + writew(write_dps_regs, &state->g_dp, state->address, state->cpu_word); +} + +static void osal_fastcall write_dpsb(usf_state_t * state) +{ + writeb(write_dps_regs, &state->g_dp, state->address, state->cpu_byte); +} + +static void osal_fastcall write_dpsh(usf_state_t * state) +{ + writeh(write_dps_regs, &state->g_dp, state->address, state->cpu_hword); +} + +static void osal_fastcall write_dpsd(usf_state_t * state) +{ + writed(write_dps_regs, &state->g_dp, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_mi(usf_state_t * state) +{ + readw(read_mi_regs, &state->g_r4300, state->address, state->rdword); +} + +static void osal_fastcall read_mib(usf_state_t * state) +{ + readb(read_mi_regs, &state->g_r4300, state->address, state->rdword); +} + +static void osal_fastcall read_mih(usf_state_t * state) +{ + readh(read_mi_regs, &state->g_r4300, state->address, state->rdword); +} + +static void osal_fastcall read_mid(usf_state_t * state) +{ + readd(read_mi_regs, &state->g_r4300, state->address, state->rdword); +} + +static void osal_fastcall write_mi(usf_state_t * state) +{ + writew(write_mi_regs, &state->g_r4300, state->address, state->cpu_word); +} + +static void osal_fastcall write_mib(usf_state_t * state) +{ + writeb(write_mi_regs, &state->g_r4300, state->address, state->cpu_byte); +} + +static void osal_fastcall write_mih(usf_state_t * state) +{ + writeh(write_mi_regs, &state->g_r4300, state->address, state->cpu_hword); +} + +static void osal_fastcall write_mid(usf_state_t * state) +{ + writed(write_mi_regs, &state->g_r4300, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_vi(usf_state_t * state) +{ + readw(read_vi_regs, &state->g_vi, state->address, state->rdword); +} + +static void osal_fastcall read_vib(usf_state_t * state) +{ + readb(read_vi_regs, &state->g_vi, state->address, state->rdword); +} + +static void osal_fastcall read_vih(usf_state_t * state) +{ + readh(read_vi_regs, &state->g_vi, state->address, state->rdword); +} + +static void osal_fastcall read_vid(usf_state_t * state) +{ + readd(read_vi_regs, &state->g_vi, state->address, state->rdword); +} + +static void osal_fastcall write_vi(usf_state_t * state) +{ + writew(write_vi_regs, &state->g_vi, state->address, state->cpu_word); +} + +static void osal_fastcall write_vib(usf_state_t * state) +{ + writeb(write_vi_regs, &state->g_vi, state->address, state->cpu_byte); +} + +static void osal_fastcall write_vih(usf_state_t * state) +{ + writeh(write_vi_regs, &state->g_vi, state->address, state->cpu_hword); +} + +static void osal_fastcall write_vid(usf_state_t * state) +{ + writed(write_vi_regs, &state->g_vi, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_ai(usf_state_t * state) +{ + readw(read_ai_regs, &state->g_ai, state->address, state->rdword); +} + +static void osal_fastcall read_aib(usf_state_t * state) +{ + readb(read_ai_regs, &state->g_ai, state->address, state->rdword); +} + +static void osal_fastcall read_aih(usf_state_t * state) +{ + readh(read_ai_regs, &state->g_ai, state->address, state->rdword); +} + +static void osal_fastcall read_aid(usf_state_t * state) +{ + readd(read_ai_regs, &state->g_ai, state->address, state->rdword); +} + +static void osal_fastcall write_ai(usf_state_t * state) +{ + writew(write_ai_regs, &state->g_ai, state->address, state->cpu_word); +} + +static void osal_fastcall write_aib(usf_state_t * state) +{ + writeb(write_ai_regs, &state->g_ai, state->address, state->cpu_byte); +} + +static void osal_fastcall write_aih(usf_state_t * state) +{ + writeh(write_ai_regs, &state->g_ai, state->address, state->cpu_hword); +} + +static void osal_fastcall write_aid(usf_state_t * state) +{ + writed(write_ai_regs, &state->g_ai, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_pi(usf_state_t * state) +{ + readw(read_pi_regs, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_pib(usf_state_t * state) +{ + readb(read_pi_regs, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_pih(usf_state_t * state) +{ + readh(read_pi_regs, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_pid(usf_state_t * state) +{ + readd(read_pi_regs, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall write_pi(usf_state_t * state) +{ + writew(write_pi_regs, &state->g_pi, state->address, state->cpu_word); +} + +static void osal_fastcall write_pib(usf_state_t * state) +{ + writeb(write_pi_regs, &state->g_pi, state->address, state->cpu_byte); +} + +static void osal_fastcall write_pih(usf_state_t * state) +{ + writeh(write_pi_regs, &state->g_pi, state->address, state->cpu_hword); +} + +static void osal_fastcall write_pid(usf_state_t * state) +{ + writed(write_pi_regs, &state->g_pi, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_ri(usf_state_t * state) +{ + readw(read_ri_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rib(usf_state_t * state) +{ + readb(read_ri_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rih(usf_state_t * state) +{ + readh(read_ri_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall read_rid(usf_state_t * state) +{ + readd(read_ri_regs, &state->g_ri, state->address, state->rdword); +} + +static void osal_fastcall write_ri(usf_state_t * state) +{ + writew(write_ri_regs, &state->g_ri, state->address, state->cpu_word); +} + +static void osal_fastcall write_rib(usf_state_t * state) +{ + writeb(write_ri_regs, &state->g_ri, state->address, state->cpu_byte); +} + +static void osal_fastcall write_rih(usf_state_t * state) +{ + writeh(write_ri_regs, &state->g_ri, state->address, state->cpu_hword); +} + +static void osal_fastcall write_rid(usf_state_t * state) +{ + writed(write_ri_regs, &state->g_ri, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_si(usf_state_t * state) +{ + readw(read_si_regs, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_sib(usf_state_t * state) +{ + readb(read_si_regs, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_sih(usf_state_t * state) +{ + readh(read_si_regs, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_sid(usf_state_t * state) +{ + readd(read_si_regs, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall write_si(usf_state_t * state) +{ + writew(write_si_regs, &state->g_si, state->address, state->cpu_word); +} + +static void osal_fastcall write_sib(usf_state_t * state) +{ + writeb(write_si_regs, &state->g_si, state->address, state->cpu_byte); +} + +static void osal_fastcall write_sih(usf_state_t * state) +{ + writeh(write_si_regs, &state->g_si, state->address, state->cpu_hword); +} + +static void osal_fastcall write_sid(usf_state_t * state) +{ + writed(write_si_regs, &state->g_si, state->address, state->cpu_dword); +} + + +static void osal_fastcall read_rom(usf_state_t * state) +{ + readw(read_cart_rom, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_romb(usf_state_t * state) +{ + readb(read_cart_rom, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_romh(usf_state_t * state) +{ + readh(read_cart_rom, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall read_romd(usf_state_t * state) +{ + readd(read_cart_rom, &state->g_pi, state->address, state->rdword); +} + +static void osal_fastcall write_rom(usf_state_t * state) +{ + writew(write_cart_rom, &state->g_pi, state->address, state->cpu_word); +} + + +static void osal_fastcall read_rom_tracked(usf_state_t * state) +{ + readw(read_cart_rom_tracked, state, state->address, state->rdword); +} + +static void osal_fastcall read_rom_trackedb(usf_state_t * state) +{ + readb(read_cart_rom_tracked, state, state->address, state->rdword); +} + +static void osal_fastcall read_rom_trackedh(usf_state_t * state) +{ + readh(read_cart_rom_tracked, state, state->address, state->rdword); +} + +static void osal_fastcall read_rom_trackedd(usf_state_t * state) +{ + readd(read_cart_rom_tracked, state, state->address, state->rdword); +} + + +static void osal_fastcall read_pif(usf_state_t * state) +{ + readw(read_pif_ram, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_pifb(usf_state_t * state) +{ + readb(read_pif_ram, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_pifh(usf_state_t * state) +{ + readh(read_pif_ram, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall read_pifd(usf_state_t * state) +{ + readd(read_pif_ram, &state->g_si, state->address, state->rdword); +} + +static void osal_fastcall write_pif(usf_state_t * state) +{ + writew(write_pif_ram, &state->g_si, state->address, state->cpu_word); +} + +static void osal_fastcall write_pifb(usf_state_t * state) +{ + writeb(write_pif_ram, &state->g_si, state->address, state->cpu_byte); +} + +static void osal_fastcall write_pifh(usf_state_t * state) +{ + writeh(write_pif_ram, &state->g_si, state->address, state->cpu_hword); +} + +static void osal_fastcall write_pifd(usf_state_t * state) +{ + writed(write_pif_ram, &state->g_si, state->address, state->cpu_dword); +} + +/* HACK: just to get F-Zero to boot + * TODO: implement a real DD module + */ +static int read_dd_regs(void* opaque, uint32_t address, uint32_t* value) +{ + *value = (address == 0xa5000508) + ? 0xffffffff + : 0x00000000; + + return 0; +} + +static int write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + return 0; +} + +static void osal_fastcall read_dd(usf_state_t * state) +{ + readw(read_dd_regs, NULL, state->address, state->rdword); +} + +static void osal_fastcall read_ddb(usf_state_t * state) +{ + readb(read_dd_regs, NULL, state->address, state->rdword); +} + +static void osal_fastcall read_ddh(usf_state_t * state) +{ + readh(read_dd_regs, NULL, state->address, state->rdword); +} + +static void osal_fastcall read_ddd(usf_state_t * state) +{ + readd(read_dd_regs, NULL, state->address, state->rdword); +} + +static void osal_fastcall write_dd(usf_state_t * state) +{ + writew(write_dd_regs, NULL, state->address, state->cpu_word); +} + +static void osal_fastcall write_ddb(usf_state_t * state) +{ + writeb(write_dd_regs, NULL, state->address, state->cpu_byte); +} + +static void osal_fastcall write_ddh(usf_state_t * state) +{ + writeh(write_dd_regs, NULL, state->address, state->cpu_hword); +} + +static void osal_fastcall write_ddd(usf_state_t * state) +{ + writed(write_dd_regs, NULL, state->address, state->cpu_dword); +} + +#define R(x) read_ ## x ## b, read_ ## x ## h, read_ ## x, read_ ## x ## d +#define W(x) write_ ## x ## b, write_ ## x ## h, write_ ## x, write_ ## x ## d +#define RW(x) R(x), W(x) + +int init_memory(usf_state_t * state, uint32_t rdram_size) +{ + int i; + + /* clear mappings */ + for(i = 0; i < 0x10000; ++i) + { + map_region(state, i, M64P_MEM_NOMEM, RW(nomem)); + } + + /* map RDRAM */ + if (state->enable_trimming_mode) + { + for(i = 0; i < /*0x40*/(rdram_size >> 16); ++i) + { + map_region(state, 0x8000+i, M64P_MEM_RDRAM, RW(rdram_tracked)); + map_region(state, 0xa000+i, M64P_MEM_RDRAM, RW(rdram_tracked)); + } + } + else + { + for(i = 0; i < /*0x40*/(rdram_size >> 16); ++i) + { + map_region(state, 0x8000+i, M64P_MEM_RDRAM, RW(rdram)); + map_region(state, 0xa000+i, M64P_MEM_RDRAM, RW(rdram)); + } + } + for(i = /*0x40*/(rdram_size >> 16); i < 0x3f0; ++i) + { + map_region(state, 0x8000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map RDRAM registers */ + map_region(state, 0x83f0, M64P_MEM_RDRAMREG, RW(rdramreg)); + map_region(state, 0xa3f0, M64P_MEM_RDRAMREG, RW(rdramreg)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x83f0+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa3f0+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map RSP memory */ + map_region(state, 0x8400, M64P_MEM_RSPMEM, RW(rspmem)); + map_region(state, 0xa400, M64P_MEM_RSPMEM, RW(rspmem)); + for(i = 1; i < 0x4; ++i) + { + map_region(state, 0x8400+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa400+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map RSP registers (1) */ + map_region(state, 0x8404, M64P_MEM_RSPREG, RW(rspreg)); + map_region(state, 0xa404, M64P_MEM_RSPREG, RW(rspreg)); + for(i = 0x5; i < 0x8; ++i) + { + map_region(state, 0x8400+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa400+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map RSP registers (2) */ + map_region(state, 0x8408, M64P_MEM_RSP, RW(rspreg2)); + map_region(state, 0xa408, M64P_MEM_RSP, RW(rspreg2)); + for(i = 0x9; i < 0x10; ++i) + { + map_region(state, 0x8400+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa400+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map DPC registers */ + map_region(state, 0x8410, M64P_MEM_DP, RW(dp)); + map_region(state, 0xa410, M64P_MEM_DP, RW(dp)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8410+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa410+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map DPS registers */ + map_region(state, 0x8420, M64P_MEM_DPS, RW(dps)); + map_region(state, 0xa420, M64P_MEM_DPS, RW(dps)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8420+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa420+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map MI registers */ + map_region(state, 0x8430, M64P_MEM_MI, RW(mi)); + map_region(state, 0xa430, M64P_MEM_MI, RW(mi)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8430+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa430+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map VI registers */ + map_region(state, 0x8440, M64P_MEM_VI, RW(vi)); + map_region(state, 0xa440, M64P_MEM_VI, RW(vi)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8440+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa440+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map AI registers */ + map_region(state, 0x8450, M64P_MEM_AI, RW(ai)); + map_region(state, 0xa450, M64P_MEM_AI, RW(ai)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8450+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa450+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map PI registers */ + map_region(state, 0x8460, M64P_MEM_PI, RW(pi)); + map_region(state, 0xa460, M64P_MEM_PI, RW(pi)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8460+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa460+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map RI registers */ + map_region(state, 0x8470, M64P_MEM_RI, RW(ri)); + map_region(state, 0xa470, M64P_MEM_RI, RW(ri)); + for(i = 1; i < 0x10; ++i) + { + map_region(state, 0x8470+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa470+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map SI registers */ + map_region(state, 0x8480, M64P_MEM_SI, RW(si)); + map_region(state, 0xa480, M64P_MEM_SI, RW(si)); + for(i = 0x481; i < 0x500; ++i) + { + map_region(state, 0x8000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map DD regsiters */ + map_region(state, 0x8500, M64P_MEM_NOTHING, RW(dd)); + map_region(state, 0xa500, M64P_MEM_NOTHING, RW(dd)); + for(i = 0x501; i < 0x800; ++i) + { + map_region(state, 0x8000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map flashram/sram */ + for(i = 0x800; i < 0x1000; ++i) + { + map_region(state, 0x8000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xa000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map cart ROM */ + if (state->enable_trimming_mode) + { + for(i = 0; i < (state->g_rom_size >> 16); ++i) + { + map_region(state, 0x9000+i, M64P_MEM_ROM, R(rom_tracked), W(nothing)); + map_region(state, 0xb000+i, M64P_MEM_ROM, R(rom_tracked), + write_nothingb, write_nothingh, write_rom, write_nothingd); + } + } + else + { + for(i = 0; i < (state->g_rom_size >> 16); ++i) + { + map_region(state, 0x9000+i, M64P_MEM_ROM, R(rom), W(nothing)); + map_region(state, 0xb000+i, M64P_MEM_ROM, R(rom), + write_nothingb, write_nothingh, write_rom, write_nothingd); + } + } + for(i = (state->g_rom_size >> 16); i < 0xfc0; ++i) + { + map_region(state, 0x9000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xb000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + /* map PIF RAM */ + map_region(state, 0x9fc0, M64P_MEM_PIF, RW(pif)); + map_region(state, 0xbfc0, M64P_MEM_PIF, RW(pif)); + for(i = 0xfc1; i < 0x1000; ++i) + { + map_region(state, 0x9000+i, M64P_MEM_NOTHING, RW(nothing)); + map_region(state, 0xb000+i, M64P_MEM_NOTHING, RW(nothing)); + } + + state->fast_memory = 1; + + if (state->g_rom && state->g_rom_size >= 0xfc0) + init_cic_using_ipl3(state, &state->g_si.pif.cic, state->g_rom + 0x40); + + init_r4300(&state->g_r4300); + init_rdp(&state->g_dp); + init_rsp(&state->g_sp); + init_ai(&state->g_ai); + init_pi(&state->g_pi); + init_ri(&state->g_ri); + init_si(&state->g_si); + init_vi(&state->g_vi); + + DebugMessage(state, M64MSG_VERBOSE, "Memory initialized"); + return 0; +} + +static void map_region_r(usf_state_t * state, + uint16_t region, + void (osal_fastcall *read8)(usf_state_t *), + void (osal_fastcall *read16)(usf_state_t *), + void (osal_fastcall *read32)(usf_state_t *), + void (osal_fastcall *read64)(usf_state_t *)) +{ + { + state->readmemb[region] = read8; + state->readmemh[region] = read16; + state->readmem [region] = read32; + state->readmemd[region] = read64; + } +} + +static void map_region_w(usf_state_t * state, + uint16_t region, + void (osal_fastcall *write8)(usf_state_t *), + void (osal_fastcall *write16)(usf_state_t *), + void (osal_fastcall *write32)(usf_state_t *), + void (osal_fastcall *write64)(usf_state_t *)) +{ + { + state->writememb[region] = write8; + state->writememh[region] = write16; + state->writemem [region] = write32; + state->writememd[region] = write64; + } +} + +void map_region(usf_state_t * state, + uint16_t region, + int type, + void (osal_fastcall *read8)(usf_state_t *), + void (osal_fastcall *read16)(usf_state_t *), + void (osal_fastcall *read32)(usf_state_t *), + void (osal_fastcall *read64)(usf_state_t *), + void (osal_fastcall *write8)(usf_state_t *), + void (osal_fastcall *write16)(usf_state_t *), + void (osal_fastcall *write32)(usf_state_t *), + void (osal_fastcall *write64)(usf_state_t *)) +{ + (void)type; + map_region_r(state, region, read8, read16, read32, read64); + map_region_w(state, region, write8, write16, write32, write64); +} + +unsigned int * osal_fastcall fast_mem_access(usf_state_t * state, unsigned int address) +{ + /* This code is performance critical, specially on pure interpreter mode. + * Removing error checking saves some time, but the emulator may crash. */ + + if ((address & 0xc0000000) != 0x80000000) + address = virtual_to_physical_address(state, address, 2); + + address &= 0x1ffffffc; + + if (address < RDRAM_MAX_SIZE) + return (unsigned int*)((unsigned char*)state->g_rdram + address); + else if (address >= 0x10000000) + { + if ((address - 0x10000000) < state->g_rom_size) + return (unsigned int*)((unsigned char*)state->g_rom + address - 0x10000000); + else + return (unsigned int*)((unsigned char*)state->EmptySpace + (address & 0xFFFF)); + } + else if ((address & 0xffffe000) == 0x04000000) + return (unsigned int*)((unsigned char*)state->g_sp.mem + (address & 0x1ffc)); + else + return NULL; +} diff --git a/Frameworks/lazyusf/lazyusf/memory/memory.h b/Frameworks/lazyusf/lazyusf/memory/memory.h new file mode 100644 index 000000000..4923d7983 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/memory/memory.h @@ -0,0 +1,106 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - memory.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_MEMORY_MEMORY_H +#define M64P_MEMORY_MEMORY_H + +#include + +#define read_word_in_memory() state->readmem[state->address>>16](state) +#define read_byte_in_memory() state->readmemb[state->address>>16](state) +#define read_hword_in_memory() state->readmemh[state->address>>16](state) +#define read_dword_in_memory() state->readmemd[state->address>>16](state) +#define write_word_in_memory() state->writemem[state->address>>16](state) +#define write_byte_in_memory() state->writememb[state->address >>16](state) +#define write_hword_in_memory() state->writememh[state->address >>16](state) +#define write_dword_in_memory() state->writememd[state->address >>16](state) + +#ifndef M64P_BIG_ENDIAN +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#define sl(x) __builtin_bswap32(x) +#else +#define sl(mot) \ +( \ +((mot & 0x000000FF) << 24) | \ +((mot & 0x0000FF00) << 8) | \ +((mot & 0x00FF0000) >> 8) | \ +((mot & 0xFF000000) >> 24) \ +) +#endif +#define S8 3 +#define S16 2 +#define Sh16 1 + +#else + +#define sl(mot) mot +#define S8 0 +#define S16 0 +#define Sh16 0 + +#endif + +#include "osal/preproc.h" + +static osal_inline void masked_write(uint32_t* dst, uint32_t value, uint32_t mask) +{ + *dst = (*dst & ~mask) | (value & mask); +} + +int init_memory(usf_state_t *, uint32_t rdram_size); + +void map_region(usf_state_t *, + uint16_t region, + int type, + void (osal_fastcall *read8)(usf_state_t *), + void (osal_fastcall *read16)(usf_state_t *), + void (osal_fastcall *read32)(usf_state_t *), + void (osal_fastcall *read64)(usf_state_t *), + void (osal_fastcall *write8)(usf_state_t *), + void (osal_fastcall *write16)(usf_state_t *), + void (osal_fastcall *write32)(usf_state_t *), + void (osal_fastcall *write64)(usf_state_t *)); + +/* XXX: cannot make them static because of dynarec + rdp fb */ +void osal_fastcall read_rdram(usf_state_t *); +void osal_fastcall read_rdramb(usf_state_t *); +void osal_fastcall read_rdramh(usf_state_t *); +void osal_fastcall read_rdramd(usf_state_t *); +void osal_fastcall write_rdram(usf_state_t *); +void osal_fastcall write_rdramb(usf_state_t *); +void osal_fastcall write_rdramh(usf_state_t *); +void osal_fastcall write_rdramd(usf_state_t *); +void osal_fastcall read_rdramFB(usf_state_t *); +void osal_fastcall read_rdramFBb(usf_state_t *); +void osal_fastcall read_rdramFBh(usf_state_t *); +void osal_fastcall read_rdramFBd(usf_state_t *); +void osal_fastcall write_rdramFB(usf_state_t *); +void osal_fastcall write_rdramFBb(usf_state_t *); +void osal_fastcall write_rdramFBh(usf_state_t *); +void osal_fastcall write_rdramFBd(usf_state_t *); + +/* Returns a pointer to a block of contiguous memory + * Can access RDRAM, SP_DMEM, SP_IMEM and ROM, using TLB if necessary + * Useful for getting fast access to a zone with executable code. */ +unsigned int * osal_fastcall fast_mem_access(usf_state_t *, unsigned int address); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/opcode.h b/Frameworks/lazyusf/lazyusf/opcode.h deleted file mode 100644 index 636f32374..000000000 --- a/Frameworks/lazyusf/lazyusf/opcode.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#ifndef __OpCode -#define __OpCode - -#include "types.h" - -typedef struct { - union { - - uint32_t Hex; - uint8_t Ascii[4]; - - struct { - unsigned offset : 16; - unsigned rt : 5; - unsigned rs : 5; - unsigned op : 6; - } b; - - struct { - unsigned immediate : 16; - unsigned : 5; - unsigned base : 5; - unsigned : 6; - } c; - - struct { - unsigned target : 26; - unsigned : 6; - } d; - - struct { - unsigned funct : 6; - unsigned sa : 5; - unsigned rd : 5; - unsigned : 5; - unsigned : 5; - unsigned : 6; - } e; - - struct { - unsigned : 6; - unsigned fd : 5; - unsigned fs : 5; - unsigned ft : 5; - unsigned fmt : 5; - unsigned : 6; - } f; - } u; - -} OPCODE; - -//R4300i OpCodes -#define R4300i_SPECIAL 0 -#define R4300i_REGIMM 1 -#define R4300i_J 2 -#define R4300i_JAL 3 -#define R4300i_BEQ 4 -#define R4300i_BNE 5 -#define R4300i_BLEZ 6 -#define R4300i_BGTZ 7 -#define R4300i_ADDI 8 -#define R4300i_ADDIU 9 -#define R4300i_SLTI 10 -#define R4300i_SLTIU 11 -#define R4300i_ANDI 12 -#define R4300i_ORI 13 -#define R4300i_XORI 14 -#define R4300i_LUI 15 -#define R4300i_CP0 16 -#define R4300i_CP1 17 -#define R4300i_BEQL 20 -#define R4300i_BNEL 21 -#define R4300i_BLEZL 22 -#define R4300i_BGTZL 23 -#define R4300i_DADDI 24 -#define R4300i_DADDIU 25 -#define R4300i_LDL 26 -#define R4300i_LDR 27 -#define R4300i_LB 32 -#define R4300i_LH 33 -#define R4300i_LWL 34 -#define R4300i_LW 35 -#define R4300i_LBU 36 -#define R4300i_LHU 37 -#define R4300i_LWR 38 -#define R4300i_LWU 39 -#define R4300i_SB 40 -#define R4300i_SH 41 -#define R4300i_SWL 42 -#define R4300i_SW 43 -#define R4300i_SDL 44 -#define R4300i_SDR 45 -#define R4300i_SWR 46 -#define R4300i_CACHE 47 -#define R4300i_LL 48 -#define R4300i_LWC1 49 -#define R4300i_LWC2 0x32 -#define R4300i_LLD 0x34 -#define R4300i_LDC1 53 -#define R4300i_LDC2 0x36 -#define R4300i_LD 55 -#define R4300i_SC 0x38 -#define R4300i_SWC1 57 -#define R4300i_SWC2 0x3A -#define R4300i_SCD 0x3C -#define R4300i_SDC1 61 -#define R4300i_SDC2 62 -#define R4300i_SD 63 - -/* R4300i Special opcodes */ -#define R4300i_SPECIAL_SLL 0 -#define R4300i_SPECIAL_SRL 2 -#define R4300i_SPECIAL_SRA 3 -#define R4300i_SPECIAL_SLLV 4 -#define R4300i_SPECIAL_SRLV 6 -#define R4300i_SPECIAL_SRAV 7 -#define R4300i_SPECIAL_JR 8 -#define R4300i_SPECIAL_JALR 9 -#define R4300i_SPECIAL_SYSCALL 12 -#define R4300i_SPECIAL_BREAK 13 -#define R4300i_SPECIAL_SYNC 15 -#define R4300i_SPECIAL_MFHI 16 -#define R4300i_SPECIAL_MTHI 17 -#define R4300i_SPECIAL_MFLO 18 -#define R4300i_SPECIAL_MTLO 19 -#define R4300i_SPECIAL_DSLLV 20 -#define R4300i_SPECIAL_DSRLV 22 -#define R4300i_SPECIAL_DSRAV 23 -#define R4300i_SPECIAL_MULT 24 -#define R4300i_SPECIAL_MULTU 25 -#define R4300i_SPECIAL_DIV 26 -#define R4300i_SPECIAL_DIVU 27 -#define R4300i_SPECIAL_DMULT 28 -#define R4300i_SPECIAL_DMULTU 29 -#define R4300i_SPECIAL_DDIV 30 -#define R4300i_SPECIAL_DDIVU 31 -#define R4300i_SPECIAL_ADD 32 -#define R4300i_SPECIAL_ADDU 33 -#define R4300i_SPECIAL_SUB 34 -#define R4300i_SPECIAL_SUBU 35 -#define R4300i_SPECIAL_AND 36 -#define R4300i_SPECIAL_OR 37 -#define R4300i_SPECIAL_XOR 38 -#define R4300i_SPECIAL_NOR 39 -#define R4300i_SPECIAL_SLT 42 -#define R4300i_SPECIAL_SLTU 43 -#define R4300i_SPECIAL_DADD 44 -#define R4300i_SPECIAL_DADDU 45 -#define R4300i_SPECIAL_DSUB 46 -#define R4300i_SPECIAL_DSUBU 47 -#define R4300i_SPECIAL_TGE 48 -#define R4300i_SPECIAL_TGEU 49 -#define R4300i_SPECIAL_TLT 50 -#define R4300i_SPECIAL_TLTU 51 -#define R4300i_SPECIAL_TEQ 52 -#define R4300i_SPECIAL_TNE 54 -#define R4300i_SPECIAL_DSLL 56 -#define R4300i_SPECIAL_DSRL 58 -#define R4300i_SPECIAL_DSRA 59 -#define R4300i_SPECIAL_DSLL32 60 -#define R4300i_SPECIAL_DSRL32 62 -#define R4300i_SPECIAL_DSRA32 63 - -/* R4300i RegImm opcodes */ -#define R4300i_REGIMM_BLTZ 0 -#define R4300i_REGIMM_BGEZ 1 -#define R4300i_REGIMM_BLTZL 2 -#define R4300i_REGIMM_BGEZL 3 -#define R4300i_REGIMM_TGEI 0x08 -#define R4300i_REGIMM_TGEIU 0x09 -#define R4300i_REGIMM_TLTI 0x0A -#define R4300i_REGIMM_TLTIU 0x0B -#define R4300i_REGIMM_TEQI 0x0C -#define R4300i_REGIMM_TNEI 0x0E -#define R4300i_REGIMM_BLTZAL 0x10 -#define R4300i_REGIMM_BGEZAL 17 -#define R4300i_REGIMM_BLTZALL 0x12 -#define R4300i_REGIMM_BGEZALL 0x13 - -/* R4300i COP0 opcodes */ -#define R4300i_COP0_MF 0 -#define R4300i_COP0_MT 4 - -/* R4300i COP0 CO opcodes */ -#define R4300i_COP0_CO_TLBR 1 -#define R4300i_COP0_CO_TLBWI 2 -#define R4300i_COP0_CO_TLBWR 6 -#define R4300i_COP0_CO_TLBP 8 -#define R4300i_COP0_CO_ERET 24 - -/* R4300i COP1 opcodes */ -#define R4300i_COP1_MF 0 -#define R4300i_COP1_DMF 1 -#define R4300i_COP1_CF 2 -#define R4300i_COP1_MT 4 -#define R4300i_COP1_DMT 5 -#define R4300i_COP1_CT 6 -#define R4300i_COP1_BC 8 -#define R4300i_COP1_S 16 -#define R4300i_COP1_D 17 -#define R4300i_COP1_W 20 -#define R4300i_COP1_L 21 - -/* R4300i COP1 BC opcodes */ -#define R4300i_COP1_BC_BCF 0 -#define R4300i_COP1_BC_BCT 1 -#define R4300i_COP1_BC_BCFL 2 -#define R4300i_COP1_BC_BCTL 3 - -#define R4300i_COP1_FUNCT_ADD 0 -#define R4300i_COP1_FUNCT_SUB 1 -#define R4300i_COP1_FUNCT_MUL 2 -#define R4300i_COP1_FUNCT_DIV 3 -#define R4300i_COP1_FUNCT_SQRT 4 -#define R4300i_COP1_FUNCT_ABS 5 -#define R4300i_COP1_FUNCT_MOV 6 -#define R4300i_COP1_FUNCT_NEG 7 -#define R4300i_COP1_FUNCT_ROUND_L 8 -#define R4300i_COP1_FUNCT_TRUNC_L 9 -#define R4300i_COP1_FUNCT_CEIL_L 10 -#define R4300i_COP1_FUNCT_FLOOR_L 11 -#define R4300i_COP1_FUNCT_ROUND_W 12 -#define R4300i_COP1_FUNCT_TRUNC_W 13 -#define R4300i_COP1_FUNCT_CEIL_W 14 -#define R4300i_COP1_FUNCT_FLOOR_W 15 -#define R4300i_COP1_FUNCT_CVT_S 32 -#define R4300i_COP1_FUNCT_CVT_D 33 -#define R4300i_COP1_FUNCT_CVT_W 36 -#define R4300i_COP1_FUNCT_CVT_L 37 -#define R4300i_COP1_FUNCT_C_F 48 -#define R4300i_COP1_FUNCT_C_UN 49 -#define R4300i_COP1_FUNCT_C_EQ 50 -#define R4300i_COP1_FUNCT_C_UEQ 51 -#define R4300i_COP1_FUNCT_C_OLT 52 -#define R4300i_COP1_FUNCT_C_ULT 53 -#define R4300i_COP1_FUNCT_C_OLE 54 -#define R4300i_COP1_FUNCT_C_ULE 55 -#define R4300i_COP1_FUNCT_C_SF 56 -#define R4300i_COP1_FUNCT_C_NGLE 57 -#define R4300i_COP1_FUNCT_C_SEQ 58 -#define R4300i_COP1_FUNCT_C_NGL 59 -#define R4300i_COP1_FUNCT_C_LT 60 -#define R4300i_COP1_FUNCT_C_NGE 61 -#define R4300i_COP1_FUNCT_C_LE 62 -#define R4300i_COP1_FUNCT_C_NGT 63 - -#endif - - diff --git a/Frameworks/lazyusf/lazyusf/os.c b/Frameworks/lazyusf/lazyusf/os.c deleted file mode 100644 index 9e1c7d267..000000000 --- a/Frameworks/lazyusf/lazyusf/os.c +++ /dev/null @@ -1,285 +0,0 @@ -#include - -#include "usf.h" -#include "usf_internal.h" - -#include "os.h" -#include "cpu_hle.h" - -#include "audio.h" -#include "interpreter_cpu.h" -#include "main.h" -#include "memory.h" - - -#define N64WORD(x) (*(uint32_t*)PageVRAM((x))) -#define N64HALF(x) (*(uint16_t*)PageVRAM((x))) -#define N64BYTE(x) (*(uint8_t*)PageVRAM((x^3))) - -#define N64DWORD(addr) (((long long)N64WORD((addr))) << 32) + N64WORD((addr)+4); - - - -int __osRestoreInt(usf_state_t * state, int n) -{ - STATUS_REGISTER |= state->GPR[0x4].UW[0]; - return 1; -} - -int __osDisableInt(usf_state_t * state, int n) -{ - state->GPR[0x2].UW[0] = STATUS_REGISTER & 1; - STATUS_REGISTER &= 0xFFFFFFFE; - return 1; -} - - -void osEnqueueThread(usf_state_t * state, uint32_t osThreadQueueAddr, uint32_t threadVAddr) -{ - - OSThread *thread = (OSThread*) PageVRAM(threadVAddr); - OSThread *oldThread = (OSThread*) PageVRAM(osThreadQueueAddr); - OSThread *curThread = (OSThread*) PageVRAM(oldThread->next); - - while((int32_t)curThread->priority >= (int32_t)thread->priority) { - oldThread = curThread; - curThread = (OSThread*) PageVRAM(curThread->next); - } - - thread->next = oldThread->next; - oldThread->next = threadVAddr; - thread->queue = osThreadQueueAddr; -} - -int __osEnqueueThread(usf_state_t * state, int n) { - osEnqueueThread(state, state->GPR[4].UW[0],state->GPR[5].UW[0]); - return 1; -} - -int osStartThread(usf_state_t * state, int n) -{ - OSMesgQueue *osThreadQueue = NULL; - uint32_t osThreadQueueAddr = 0; - uint32_t oldStatus = STATUS_REGISTER & 1; - uint32_t osActiveThreadAddr = 0; - uint32_t osActiveThread = 0; - - OSThread *thread = (OSThread*)PageVRAM(state->GPR[4].UW[0]); - - STATUS_REGISTER &= 0xFFFFFFFE; - - osThreadQueueAddr = ((*(uint32_t*)PageRAM2(n + 0x40)) & 0xFFFF) << 16; - osThreadQueueAddr += *(int16_t*)PageRAM2(n + 0x50); - - osThreadQueue = (OSMesgQueue*) PageVRAM(osThreadQueueAddr); - - if(thread->state != 8 ) { - DisplayError(state, "OMG, thread state is not OS_STATE_WAITING!\n"); - return 0; - } - - thread->state = OS_STATE_RUNNABLE; - osEnqueueThread(state,osThreadQueueAddr,state->GPR[4].UW[0]); - - osActiveThreadAddr = ((*(uint32_t*)PageRAM2(n + 0xDC)) & 0xFFFF) << 16; - osActiveThreadAddr += *(int16_t*)PageRAM2(n + 0xE0); - - osActiveThread = *(uint32_t*)PageVRAM(osActiveThreadAddr); - - if(osActiveThread==0) { - DisplayError(state,"OMG, active thread is NULL!\n"); - return 0; - } - - STATUS_REGISTER |= oldStatus; -// CheckInterrupts(); - - return 1; -} - - -int osRecvMesg(usf_state_t * state, int n) -{ - //unsigned long devAddr = state->GPR[7].UW[0]; - //unsigned long vAddr = state->GPR[0x11].UW[0]; - //unsigned long nbytes = state->GPR[0x10].UW[0]; - - //unsigned long oldStatus = STATUS_REGISTER & 1; - - RunFunction(state, n | (state->PROGRAM_COUNTER & 0xF0000000)); - - //DisplayError("%08x\n%08x\n%08x",devAddr, vAddr, nbytes); - - return 1; -} - -// doesnt even use? -int osSetIntMask(usf_state_t * state, int paddr) { -#if 0 - uint32_t globalIntMask = 0; - uint32_t mask = STATUS_REGISTER & 0xFF01; - uint32_t interrupts = 0; - uint32_t intAddress = 0, newMask = 0, workMask = 0; - - uint32_t baseAddress = 0; - - globalIntMask = ((*(uint16_t*)PageRAM2(paddr + 0x8)) & 0xFFFF) << 16; - globalIntMask += *(uint16_t*)PageRAM2(paddr + 0xc); - globalIntMask = *(uint32_t*)PageVRAM(globalIntMask); - - interrupts = (globalIntMask ^ 0xffffffff) & 0xff00; - mask |= interrupts; - newMask = MI_INTR_MASK_REG; - - if(!newMask) - newMask = ((globalIntMask >> 16) ^ 0xFFFFFFFF) & 0x3F; - - mask |= (newMask << 16); - - baseAddress = ((*(uint16_t*)PageRAM2(paddr + 0x5C)) & 0xFFFF) << 16; - baseAddress += *(int16_t*)PageRAM2(paddr + 0x64); - baseAddress += ((state->GPR[4].UW[0] & 0x3F0000) & globalIntMask) >> 15;; - - MI_INTR_MASK_REG = *(uint16_t*)PageVRAM(baseAddress); - - state->STATUS_REGISTER = ((state->GPR[4].UW[0] & 0xff01) & (globalIntMask & 0xff00)) | (STATUS_REGISTER & 0xFFFF00FF); - -#endif - return 1; -} - - -int osVirtualToPhysical(usf_state_t * state, int paddr) { - uintptr_t address = 0; - uintptr_t vaddr = state->GPR[4].UW[0]; - - address = (state->TLB_Map[vaddr >> 12] + vaddr) - (uintptr_t)state->N64MEM; - - if(address < 0x800000) { - state->GPR[2].UW[0] = (uint32_t)address; - } else - state->GPR[2].UW[0] = 0xFFFFFFFF; - - return 1; -} - -int osAiSetNextBuffer(usf_state_t * state, int paddr) { - uint32_t var = 0, var2 = 0; - var = ((*(int16_t*)PageRAM2(paddr + 0x4)) & 0xFFFF) << 16; - var += *(int16_t*)PageRAM2(paddr + 0x8); - - var2 = N64WORD(var); - if(AI_CONTROL_REG & 0x80000000) - state->GPR[2].UW[0] = -1; - - AI_DRAM_ADDR_REG = state->GPR[4].UW[0]; - AI_LEN_REG = state->GPR[5].UW[0]&0x3FFF; - AiLenChanged(state); - state->GPR[2].UW[0] = 0; - return 1; -} - -int saveThreadContext(usf_state_t * state, int paddr) { -#if 0 - uint32_t OSThreadContextAddr = 0; - - OSThreadContextAddr = ((*(int16_t*)PageRAM2(paddr)) & 0xFFFF) << 16; - OSThreadContextAddr += *(int16_t*)PageRAM2(paddr + 0x4); - - OSThreadContextAddr = N64WORD(OSThreadContextAddr); - - if((PageVRAM2(OSThreadContextAddr) & 0xffff) > 0xFF00) { - DisplayError(state,"OMG! Too high!"); - return 0; - } -#endif - return 0; -} - -int loadThreadContext(usf_state_t * state, int paddr) { -#if 0 - uint32_t i = 0, OSThreadContextAddr = 0, T9 = 0, osOSThread = 0, Addr2 = 0, GlobalBitMask = 0, Tmp = 0; - uint32_t K0 = 0, K1 = 0, T0 = 0, R1 = 0, RCP = 0, intrList = 0; - OSThread t; - OSThreadContextAddr = ((*(int16_t*)PageRAM2(paddr)) & 0xFFFF) << 16; - OSThreadContextAddr += *(int16_t*)PageRAM2(paddr + 0x8); - - Addr2 = ((*(int16_t*)PageRAM2(paddr + 0xC)) & 0xFFFF) << 16; - Addr2 += *(int16_t*)PageRAM2(paddr + 0x10); - - GlobalBitMask = ((*(int16_t*)PageRAM2(paddr + 0x20)) & 0xFFFF) << 16; - GlobalBitMask += *(int16_t*)PageRAM2(paddr + 0x28); - GlobalBitMask = N64WORD(GlobalBitMask); - - intrList = ((*(int16_t*)PageRAM2(paddr + 0x14C + 0x0)) & 0xFFFF) << 16; - intrList += *(int16_t*)PageRAM2(paddr + 0x150 + 0x0); - - return 0; - - if((PageVRAM2(OSThreadContextAddr) & 0xffff) > 0xFE80) { - DisplayError(state, "OMG this number is too high!!!!\n"); - } - - osOSThread = N64WORD(OSThreadContextAddr); - T9 = N64WORD(osOSThread); - - N64WORD(OSThreadContextAddr) = T9; - N64WORD(Addr2) = osOSThread; - - N64WORD(osOSThread + 0x10) = OS_STATE_RUNNING; //T0 is globalbitmask - - K1 = N64WORD(osOSThread + 0x118); //osOSThread.context.k0 - - STATUS_REGISTER = (K1 & 0xFFFF00FF) | (GlobalBitMask & 0xFF00); - - for(i = 1; i <= 0x19; i++) { - state->GPR[i].DW = N64DWORD(osOSThread + 0x18 + (i * 8)); - } - - for(i = 0x1C; i <= 0x1F; i++) { - state->GPR[i].DW = N64DWORD(osOSThread + 0x8 + (i * 8)); - } - - state->LO.DW = N64DWORD(osOSThread + 0x108); - state->HI.DW = N64DWORD(osOSThread + 0x110); - - EPC_REGISTER = (uint32_t) N64WORD(osOSThread + 0x11C); - - state->FPCR[31] = (uint32_t) N64WORD(osOSThread + 0x12C); - - if(N64WORD(osOSThread + 0x18)) { - for(i = 0; i <= 30; i+=2) { - (*(uint64_t *)state->FPRDoubleLocation[i]) = N64DWORD(osOSThread + 0x130 + (i * 4)); - } - } else { - } - - state->GPR[0x1A].UW[0] = (uint32_t) osOSThread; - - RCP = N64WORD(osOSThread + 0x128); - - K0 = (intrList + ((RCP & (GlobalBitMask >> 16)) << 1)); - K1 = 0; - - r4300i_LH_VAddr(state, K0, &K1); - - // cheap hack? - //K1 = 0xAAA; - - SW_Register(0x0430000C, K1); - - NextInstruction = JUMP; - - if ((STATUS_REGISTER & STATUS_ERL) != 0) { - JumpToLocation = ERROREPC_REGISTER; - STATUS_REGISTER &= ~STATUS_ERL; - } else { - JumpToLocation = EPC_REGISTER; - STATUS_REGISTER &= ~STATUS_EXL; - } - - LLBit = 0; - CheckInterrupts(); -#endif - return 0; -} diff --git a/Frameworks/lazyusf/lazyusf/os.h b/Frameworks/lazyusf/lazyusf/os.h deleted file mode 100644 index 8ff0a697c..000000000 --- a/Frameworks/lazyusf/lazyusf/os.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _CPU_HLE_OS_ -#define _CPU_HLE_OS_ - -#include "cpu_hle.h" - - -#pragma pack(1) - - -#define OS_STATE_STOPPED 1 -#define OS_STATE_RUNNABLE 2 -#define OS_STATE_RUNNING 4 -#define OS_STATE_WAITING 8 - -typedef uint32_t OSPri; -typedef uint32_t OSId; -typedef - union - { - struct - { - float f_odd; - float f_even; - } f; - double d; - } -__OSfp; - -typedef struct { - uint64_t at, v0, v1, a0, a1, a2, a3; - uint64_t t0, t1, t2, t3, t4, t5, t6, t7; - uint64_t s0, s1, s2, s3, s4, s5, s6, s7; - uint64_t t8, t9, gp, sp, s8, ra; - uint64_t lo, hi; - uint32_t sr, pc, cause, badvaddr, rcp; - uint32_t fpcsr; - __OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14; - __OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30; -} __OSThreadContext; - -typedef struct OSThread_s -{ - uint32_t next; // run/mesg queue link - OSPri priority; // run/mesg queue priority - uint32_t queue; // queue thread is on - uint32_t tlnext; // all threads queue link -#if 0 - uint16_t state; // OS_STATE_* - uint16_t flags; // flags for rmon -#endif - //swap these because of byteswapping - uint16_t flags; // flags for rmon - uint16_t state; // OS_STATE_* - OSId id; // id for debugging - int fp; // thread has used fp unit - __OSThreadContext context; // register/interrupt mask -} OSThread; - -typedef void * OSMesg; - -// -// Structure for message queue -// -typedef struct OSMesgQueue_s -{ - OSThread *mtqueue; // Queue to store threads blocked - // on empty mailboxes (receive) - OSThread *fullqueue; // Queue to store threads blocked - // on full mailboxes (send) - int32_t validCount; // Contains number of valid message - int32_t first; // Points to first valid message - int32_t msgCount; // Contains total # of messages - OSMesg *msg; // Points to message buffer array -} OSMesgQueue; - - -int __osRestoreInt(usf_state_t *, int n); -int __osDisableInt(usf_state_t *, int n); -int __osEnqueueThread(usf_state_t *, int n) ; - -int osStartThread(usf_state_t *, int n); -int osRecvMesg(usf_state_t *, int n); -int osSetIntMask(usf_state_t *, int paddr) ; -int osVirtualToPhysical(usf_state_t *, int paddr); -int osAiSetNextBuffer(usf_state_t *, int paddr); - -int saveThreadContext(usf_state_t *, int paddr); -int loadThreadContext(usf_state_t *, int paddr); -#endif diff --git a/Frameworks/lazyusf/lazyusf/osal/preproc.h b/Frameworks/lazyusf/lazyusf/osal/preproc.h index c107506e1..cf03df45c 100644 --- a/Frameworks/lazyusf/lazyusf/osal/preproc.h +++ b/Frameworks/lazyusf/lazyusf/osal/preproc.h @@ -30,6 +30,7 @@ #define OSAL_BREAKPOINT_INTERRUPT __asm{ int 3 }; #define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA #define osal_inline __inline + #define osal_fastcall __fastcall /* string functions */ #define osal_insensitive_strcmp(x, y) _stricmp(x, y) @@ -46,6 +47,11 @@ #define OSAL_BREAKPOINT_INTERRUPT __asm__(" int $3; "); #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))) #define osal_inline inline + #ifdef __i386__ + #define osal_fastcall __attribute__((fastcall)) + #else + #define osal_fastcall + #endif /* string functions */ #define osal_insensitive_strcmp(x, y) strcasecmp(x, y) diff --git a/Frameworks/lazyusf/lazyusf/pi/cart_rom.c b/Frameworks/lazyusf/lazyusf/pi/cart_rom.c new file mode 100644 index 000000000..825c95006 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/pi/cart_rom.c @@ -0,0 +1,91 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cart_rom.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "usf/barray.h" + +#include "cart_rom.h" +#include "pi_controller.h" + +void connect_cart_rom(struct cart_rom* cart_rom, + uint8_t* rom, size_t rom_size) +{ + cart_rom->rom = rom; + cart_rom->rom_size = rom_size; +} + +void init_cart_rom(struct cart_rom* cart_rom) +{ + cart_rom->last_write = 0; +} + + +int read_cart_rom(void* opaque, uint32_t address, uint32_t* value) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + uint32_t addr = rom_address(address); + + if (pi->cart_rom.last_write != 0) + { + *value = pi->cart_rom.last_write; + pi->cart_rom.last_write = 0; + } + else + { + *value = *(uint32_t*)(pi->cart_rom.rom + addr); + } + + return 0; +} + +int write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + pi->cart_rom.last_write = value & mask; + + return 0; +} + + +int read_cart_rom_tracked(void* opaque, uint32_t address, uint32_t* value) +{ + usf_state_t* state = (usf_state_t*)opaque; + struct pi_controller* pi = &state->g_pi; + uint32_t addr = rom_address(address); + + if (pi->cart_rom.last_write != 0) + { + *value = pi->cart_rom.last_write; + pi->cart_rom.last_write = 0; + } + else + { + bit_array_set(state->barray_rom, addr / 4); + + *value = *(uint32_t*)(pi->cart_rom.rom + addr); + } + + return 0; +} + diff --git a/Frameworks/lazyusf/lazyusf/pi/cart_rom.h b/Frameworks/lazyusf/lazyusf/pi/cart_rom.h new file mode 100644 index 000000000..acb688bdb --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/pi/cart_rom.h @@ -0,0 +1,53 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cart_rom.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_PI_CART_ROM_H +#define M64P_PI_CART_ROM_H + +#include +#include + +#include "osal/preproc.h" + +struct cart_rom +{ + uint8_t* rom; + size_t rom_size; + + uint32_t last_write; +}; + +static osal_inline uint32_t rom_address(uint32_t address) +{ + return (address & 0x03fffffc); +} + +void connect_cart_rom(struct cart_rom* cart_rom, + uint8_t* rom, size_t rom_size); + +void init_cart_rom(struct cart_rom* cart_rom); + +int read_cart_rom(void* opaque, uint32_t address, uint32_t* value); +int write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_cart_rom_tracked(void* opaque, uint32_t address, uint32_t* value); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/pi/pi_controller.c b/Frameworks/lazyusf/lazyusf/pi/pi_controller.c new file mode 100644 index 000000000..f3c04b974 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/pi/pi_controller.c @@ -0,0 +1,249 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pi_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "usf/barray.h" + +#include "pi_controller.h" + +#define M64P_CORE_PROTOTYPES 1 +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "main/rom.h" +#include "memory/memory.h" +#include "r4300/cached_interp.h" +#include "r4300/cp0.h" +#include "r4300/interupt.h" +#include "r4300/new_dynarec/new_dynarec.h" +#include "r4300/ops.h" +#include "r4300/r4300.h" +#include "r4300/r4300_core.h" +#include "ri/rdram_detection_hack.h" +#include "ri/ri_controller.h" + +#include + +static void dma_pi_read(usf_state_t * state, struct pi_controller* pi) +{ + if (pi->regs[PI_CART_ADDR_REG] >= 0x08000000 && pi->regs[PI_CART_ADDR_REG] < 0x08010000) + { + } + else + { + DebugMessage(state, M64MSG_WARNING, "Unknown dma read in dma_pi_read()"); + } + + pi->regs[PI_STATUS_REG] |= 1; + update_count(state); + add_interupt_event(state, PI_INT, state->g_delay_pi ? 0x1000/*pi->regs[PI_RD_LEN_REG]*/ : 0); +} + +static void dma_pi_write(usf_state_t * state, struct pi_controller* pi) +{ + unsigned int longueur; + int i; + +#ifdef DEBUG_INFO + fprintf(state->debug_log, "PI DMA WRITE: %08x to %08x for %08x bytes\n", pi->regs[PI_CART_ADDR_REG], pi->regs[PI_DRAM_ADDR_REG], pi->regs[PI_WR_LEN_REG] + 1); +#endif + + if (pi->regs[PI_CART_ADDR_REG] < 0x10000000) + { + if (pi->regs[PI_CART_ADDR_REG] >= 0x08000000 && pi->regs[PI_CART_ADDR_REG] < 0x08010000) + { + } + else if (pi->regs[PI_CART_ADDR_REG] >= 0x06000000 && pi->regs[PI_CART_ADDR_REG] < 0x08000000) + { + } + else + { + DebugMessage(state, M64MSG_WARNING, "Unknown dma write 0x%x in dma_pi_write()", (int)pi->regs[PI_CART_ADDR_REG]); + } + + pi->regs[PI_STATUS_REG] |= 1; + update_count(state); + add_interupt_event(state, PI_INT, state->g_delay_pi ? /*pi->regs[PI_WR_LEN_REG]*/0x1000 : 0); + + return; + } + + if (pi->regs[PI_CART_ADDR_REG] >= 0x1fc00000) // for paper mario + { + pi->regs[PI_STATUS_REG] |= 1; + update_count(state); + add_interupt_event(state, PI_INT, state->g_delay_pi ? 0x1000 : 0); + + return; + } + + longueur = (pi->regs[PI_WR_LEN_REG] & 0xFFFFFF)+1; + i = (pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF; + longueur = (i + (int) longueur) > pi->cart_rom.rom_size ? + (pi->cart_rom.rom_size - i) : longueur; + longueur = (pi->regs[PI_DRAM_ADDR_REG] + longueur) > 0x7FFFFF ? + (0x7FFFFF - pi->regs[PI_DRAM_ADDR_REG]) : longueur; + + if (i > pi->cart_rom.rom_size || pi->regs[PI_DRAM_ADDR_REG] > 0x7FFFFF) + { + pi->regs[PI_STATUS_REG] |= 3; + update_count(state); + add_interupt_event(state, PI_INT, state->g_delay_pi ? longueur/8 : 0); + + return; + } + + if (state->r4300emu != CORE_PURE_INTERPRETER) + { + for (i=0; i<(int)longueur; i++) + { + unsigned long rdram_address1 = pi->regs[PI_DRAM_ADDR_REG]+i+0x80000000; + unsigned long rdram_address2 = pi->regs[PI_DRAM_ADDR_REG]+i+0xa0000000; + unsigned long rom_address = (((pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF)+i); + + if (state->enable_trimming_mode) + bit_array_set(state->barray_rom, rom_address / 4); + + ((unsigned char*)pi->ri->rdram.dram)[(pi->regs[PI_DRAM_ADDR_REG]+i)^S8]= + pi->cart_rom.rom[rom_address^S8]; + + if (!state->invalid_code[rdram_address1>>12]) + { + if (!state->blocks[rdram_address1>>12] || + state->blocks[rdram_address1>>12]->block[(rdram_address1&0xFFF)/4].ops != + state->current_instruction_table.NOTCOMPILED) + { + state->invalid_code[rdram_address1>>12] = 1; + } +#ifdef NEW_DYNAREC + invalidate_block(state, rdram_address1>>12); +#endif + } + if (!state->invalid_code[rdram_address2>>12]) + { + if (!state->blocks[rdram_address1>>12] || + state->blocks[rdram_address2>>12]->block[(rdram_address2&0xFFF)/4].ops != + state->current_instruction_table.NOTCOMPILED) + { + state->invalid_code[rdram_address2>>12] = 1; + } + } + } + } + else + { + for (i=0; i<(int)longueur; i++) + { + unsigned long rom_address = (((pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF)+i); + if (state->enable_trimming_mode) + bit_array_set(state->barray_rom, rom_address / 4); + ((unsigned char*)pi->ri->rdram.dram)[(pi->regs[PI_DRAM_ADDR_REG]+i)^S8]= + pi->cart_rom.rom[rom_address^S8]; + } + } + + /* HACK: monitor PI DMA to trigger RDRAM size detection + * hack just before initial cart ROM loading. */ + if (pi->regs[PI_CART_ADDR_REG] == 0x10001000) + { + force_detected_rdram_size_hack(state); + } + + pi->regs[PI_STATUS_REG] |= 3; + update_count(state); + add_interupt_event(state, PI_INT, state->g_delay_pi ? longueur/8 : 0); + + return; +} + +void connect_pi(struct pi_controller* pi, + struct r4300_core* r4300, + struct ri_controller* ri, + uint8_t* rom, size_t rom_size) +{ + connect_cart_rom(&pi->cart_rom, rom, rom_size); + + pi->r4300 = r4300; + pi->ri = ri; +} + +void init_pi(struct pi_controller* pi) +{ + memset(pi->regs, 0, PI_REGS_COUNT*sizeof(uint32_t)); +} + + +int read_pi_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + uint32_t reg = pi_reg(address); + + *value = pi->regs[reg]; + + return 0; +} + +int write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + uint32_t reg = pi_reg(address); + + switch (reg) + { + case PI_RD_LEN_REG: + masked_write(&pi->regs[PI_RD_LEN_REG], value, mask); + dma_pi_read(pi->r4300->state, pi); + return 0; + + case PI_WR_LEN_REG: + masked_write(&pi->regs[PI_WR_LEN_REG], value, mask); + dma_pi_write(pi->r4300->state, pi); + return 0; + + case PI_STATUS_REG: + if (value & mask & 2) + clear_rcp_interrupt(pi->r4300, MI_INTR_PI); + return 0; + + case PI_BSD_DOM1_LAT_REG: + case PI_BSD_DOM1_PWD_REG: + case PI_BSD_DOM1_PGS_REG: + case PI_BSD_DOM1_RLS_REG: + case PI_BSD_DOM2_LAT_REG: + case PI_BSD_DOM2_PWD_REG: + case PI_BSD_DOM2_PGS_REG: + case PI_BSD_DOM2_RLS_REG: + masked_write(&pi->regs[reg], value & 0xff, mask); + return 0; + } + + masked_write(&pi->regs[reg], value, mask); + + return 0; +} + +void pi_end_of_dma_event(struct pi_controller* pi) +{ + pi->regs[PI_STATUS_REG] &= ~3; + raise_rcp_interrupt(pi->r4300, MI_INTR_PI); +} diff --git a/Frameworks/lazyusf/lazyusf/pi/pi_controller.h b/Frameworks/lazyusf/lazyusf/pi/pi_controller.h new file mode 100644 index 000000000..59abfa24d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/pi/pi_controller.h @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pi_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_PI_PI_CONTROLLER_H +#define M64P_PI_PI_CONTROLLER_H + +#include +#include + +#include "cart_rom.h" + +struct r4300_core; +struct ri_controller; + +enum pi_registers +{ + PI_DRAM_ADDR_REG, + PI_CART_ADDR_REG, + PI_RD_LEN_REG, + PI_WR_LEN_REG, + PI_STATUS_REG, + PI_BSD_DOM1_LAT_REG, + PI_BSD_DOM1_PWD_REG, + PI_BSD_DOM1_PGS_REG, + PI_BSD_DOM1_RLS_REG, + PI_BSD_DOM2_LAT_REG, + PI_BSD_DOM2_PWD_REG, + PI_BSD_DOM2_PGS_REG, + PI_BSD_DOM2_RLS_REG, + PI_REGS_COUNT +}; + +struct pi_controller +{ + uint32_t regs[PI_REGS_COUNT]; + + struct cart_rom cart_rom; + + struct r4300_core* r4300; + struct ri_controller* ri; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t pi_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + + +void connect_pi(struct pi_controller* pi, + struct r4300_core* r4300, + struct ri_controller* ri, + uint8_t* rom, size_t rom_size); + +void init_pi(struct pi_controller* pi); + +int read_pi_regs(void* opaque, uint32_t address, uint32_t* value); +int write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void pi_end_of_dma_event(struct pi_controller* pi); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/pif.c b/Frameworks/lazyusf/lazyusf/pif.c deleted file mode 100644 index 6f60210f3..000000000 --- a/Frameworks/lazyusf/lazyusf/pif.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#include "usf.h" -#include "main.h" -#include "cpu.h" - -#include "usf_internal.h" - -// Skeletal support so USFs that read the controller won't fail (bad practice, though) - -void ProcessControllerCommand ( usf_state_t * state, int32_t Control, uint8_t * Command); - -void PifRamRead (usf_state_t * state) { - int32_t Channel, CurPos; - - Channel = 0; - CurPos = 0; - - do { - switch(state->PIF_Ram[CurPos]) { - case 0x00: - Channel += 1; - if (Channel > 6) { CurPos = 0x40; } - break; - case 0xFE: CurPos = 0x40; break; - case 0xFF: break; - case 0xB4: case 0x56: case 0xB8: break; /* ??? */ - default: - if ((state->PIF_Ram[CurPos] & 0xC0) == 0) { - CurPos += state->PIF_Ram[CurPos] + (state->PIF_Ram[CurPos + 1] & 0x3F) + 1; - Channel += 1; - } else { - CurPos = 0x40; - } - break; - } - CurPos += 1; - } while( CurPos < 0x40 ); -} - -void PifRamWrite (usf_state_t * state) { - int Channel, CurPos; - - Channel = 0; - - for (CurPos = 0; CurPos < 0x40; CurPos++){ - switch(state->PIF_Ram[CurPos]) { - case 0x00: - Channel += 1; - if (Channel > 6) { CurPos = 0x40; } - break; - case 0xFE: CurPos = 0x40; break; - case 0xFF: break; - case 0xB4: case 0x56: case 0xB8: break; /* ??? */ - default: - if ((state->PIF_Ram[CurPos] & 0xC0) == 0) { - if (Channel < 4) { - ProcessControllerCommand(state,Channel,&state->PIF_Ram[CurPos]); - } - CurPos += state->PIF_Ram[CurPos] + (state->PIF_Ram[CurPos + 1] & 0x3F) + 1; - Channel += 1; - } else - CurPos = 0x40; - - break; - } - } - state->PIF_Ram[0x3F] = 0; -} - -// always return failure -void ProcessControllerCommand ( usf_state_t * state, int32_t Control, uint8_t * Command) { - (void)state; - (void)Control; - Command[1] |= 0x80; -} diff --git a/Frameworks/lazyusf/lazyusf/pif.h b/Frameworks/lazyusf/lazyusf/pif.h deleted file mode 100644 index d46ec4de6..000000000 --- a/Frameworks/lazyusf/lazyusf/pif.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -extern uint8_t *PIF_Ram; - -void PifRamWrite ( usf_state_t * ); -void PifRamRead ( usf_state_t * ); diff --git a/Frameworks/lazyusf/lazyusf/r4300/cached_interp.c b/Frameworks/lazyusf/lazyusf/r4300/cached_interp.c new file mode 100644 index 000000000..ccdc87fbd --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cached_interp.c @@ -0,0 +1,567 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cached_interp.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "cached_interp.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "main/main.h" +#include "memory/memory.h" + +#include "r4300.h" +#include "cp0.h" +#include "cp1.h" +#include "ops.h" +#include "exception.h" +#include "interupt.h" +#include "macros.h" +#include "recomp.h" +#include "tlb.h" + +// ----------------------------------------------------------- +// Cached interpreter functions (and fallback for dynarec). +// ----------------------------------------------------------- +#define UPDATE_DEBUGGER() do { } while(0) + +#define PCADDR state->PC->addr +#define ADD_TO_PC(x) state->PC += x; +#define DECLARE_INSTRUCTION(name) static void osal_fastcall name(usf_state_t * state) + +#define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ + static void osal_fastcall name(usf_state_t * state) \ + { \ + const int take_jump = (condition); \ + const unsigned int jump_target = (destination); \ + long long int *link_register = (link); \ + if (cop1 && check_cop1_unusable(state)) return; \ + if (link_register != &state->reg[0]) \ + { \ + *link_register=state->PC->addr + 8; \ + sign_extended(*link_register); \ + } \ + if (!likely || take_jump) \ + { \ + state->PC++; \ + state->delay_slot=1; \ + UPDATE_DEBUGGER(); \ + state->PC->ops(state); \ + update_count(state); \ + state->delay_slot=0; \ + if (take_jump && !state->skip_jump) \ + { \ + state->PC=state->actual->block+((jump_target-state->actual->start)>>2); \ + } \ + } \ + else \ + { \ + state->PC += 2; \ + update_count(state); \ + } \ + state->last_addr = state->PC->addr; \ + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ + } \ + static void osal_fastcall name##_OUT(usf_state_t * state) \ + { \ + const int take_jump = (condition); \ + const unsigned int jump_target = (destination); \ + long long int *link_register = (link); \ + if (cop1 && check_cop1_unusable(state)) return; \ + if (link_register != &state->reg[0]) \ + { \ + *link_register=state->PC->addr + 8; \ + sign_extended(*link_register); \ + } \ + if (!likely || take_jump) \ + { \ + state->PC++; \ + state->delay_slot=1; \ + UPDATE_DEBUGGER(); \ + state->PC->ops(state); \ + update_count(state); \ + state->delay_slot=0; \ + if (take_jump && !state->skip_jump) \ + { \ + jump_to(jump_target); \ + } \ + } \ + else \ + { \ + state->PC += 2; \ + update_count(state); \ + } \ + state->last_addr = state->PC->addr; \ + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ + } \ + static void osal_fastcall name##_IDLE(usf_state_t * state) \ + { \ + const int take_jump = (condition); \ + int skip; \ + if (cop1 && check_cop1_unusable(state)) return; \ + if (take_jump) \ + { \ + update_count(state); \ + skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \ + if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \ + else name(state); \ + } \ + else name(state); \ + } + +#define CHECK_MEMORY() \ + if (!state->invalid_code[state->address>>12]) \ + if (state->blocks[state->address>>12]->block[(state->address&0xFFF)/4].ops != \ + state->current_instruction_table.NOTCOMPILED) \ + state->invalid_code[state->address>>12] = 1; + +// two functions are defined from the macros above but never used +// these prototype declarations will prevent a warning +#if defined(__GNUC__) + static void osal_fastcall JR_IDLE(usf_state_t *) __attribute__((used)); + static void osal_fastcall JALR_IDLE(usf_state_t *) __attribute__((used)); +#endif + +#include "interpreter.def" + +// ----------------------------------------------------------- +// Flow control 'fake' instructions +// ----------------------------------------------------------- +static void osal_fastcall FIN_BLOCK(usf_state_t * state) +{ + if (!state->delay_slot) + { + jump_to((state->PC-1)->addr+4); +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +Used by dynarec only, check should be unnecessary +*/ + state->PC->ops(state); + if (state->r4300emu == CORE_DYNAREC) dyna_jump(state); + } + else + { + precomp_block *blk = state->actual; + precomp_instr *inst = state->PC; + jump_to((state->PC-1)->addr+4); + +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +Used by dynarec only, check should be unnecessary +*/ + if (!state->skip_jump) + { + state->PC->ops(state); + state->actual = blk; + state->PC = inst+1; + } + else + state->PC->ops(state); + + if (state->r4300emu == CORE_DYNAREC) dyna_jump(state); + } +} + +static void osal_fastcall NOTCOMPILED(usf_state_t * state) +{ + unsigned int *mem = fast_mem_access(state, state->blocks[state->PC->addr>>12]->start); + + if (mem != NULL) + recompile_block(state, (int *)mem, state->blocks[state->PC->addr >> 12], state->PC->addr); + else + DebugMessage(state, M64MSG_ERROR, "not compiled exception"); + +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +The preceeding update_debugger SHOULD be unnecessary since it should have been +called before NOTCOMPILED would have been executed +*/ + state->PC->ops(state); + if (state->r4300emu == CORE_DYNAREC) + dyna_jump(state); +} + +static void osal_fastcall NOTCOMPILED2(usf_state_t * state) +{ + NOTCOMPILED(state); +} + +// ----------------------------------------------------------- +// Cached interpreter instruction table +// ----------------------------------------------------------- +const cpu_instruction_table cached_interpreter_table = { + LB, + LBU, + LH, + LHU, + LW, + LWL, + LWR, + SB, + SH, + SW, + SWL, + SWR, + + LD, + LDL, + LDR, + LL, + LWU, + SC, + SD, + SDL, + SDR, + SYNC, + + ADDI, + ADDIU, + SLTI, + SLTIU, + ANDI, + ORI, + XORI, + LUI, + + DADDI, + DADDIU, + + ADD, + ADDU, + SUB, + SUBU, + SLT, + SLTU, + AND, + OR, + XOR, + NOR, + + DADD, + DADDU, + DSUB, + DSUBU, + + MULT, + MULTU, + DIV, + DIVU, + MFHI, + MTHI, + MFLO, + MTLO, + + DMULT, + DMULTU, + DDIV, + DDIVU, + + J, + J_OUT, + J_IDLE, + JAL, + JAL_OUT, + JAL_IDLE, + // Use the _OUT versions of JR and JALR, since we don't know + // until runtime if they're going to jump inside or outside the block + JR_OUT, + JALR_OUT, + BEQ, + BEQ_OUT, + BEQ_IDLE, + BNE, + BNE_OUT, + BNE_IDLE, + BLEZ, + BLEZ_OUT, + BLEZ_IDLE, + BGTZ, + BGTZ_OUT, + BGTZ_IDLE, + BLTZ, + BLTZ_OUT, + BLTZ_IDLE, + BGEZ, + BGEZ_OUT, + BGEZ_IDLE, + BLTZAL, + BLTZAL_OUT, + BLTZAL_IDLE, + BGEZAL, + BGEZAL_OUT, + BGEZAL_IDLE, + + BEQL, + BEQL_OUT, + BEQL_IDLE, + BNEL, + BNEL_OUT, + BNEL_IDLE, + BLEZL, + BLEZL_OUT, + BLEZL_IDLE, + BGTZL, + BGTZL_OUT, + BGTZL_IDLE, + BLTZL, + BLTZL_OUT, + BLTZL_IDLE, + BGEZL, + BGEZL_OUT, + BGEZL_IDLE, + BLTZALL, + BLTZALL_OUT, + BLTZALL_IDLE, + BGEZALL, + BGEZALL_OUT, + BGEZALL_IDLE, + BC1TL, + BC1TL_OUT, + BC1TL_IDLE, + BC1FL, + BC1FL_OUT, + BC1FL_IDLE, + + SLL, + SRL, + SRA, + SLLV, + SRLV, + SRAV, + + DSLL, + DSRL, + DSRA, + DSLLV, + DSRLV, + DSRAV, + DSLL32, + DSRL32, + DSRA32, + + MTC0, + MFC0, + + TLBR, + TLBWI, + TLBWR, + TLBP, + CACHE, + ERET, + + LWC1, + SWC1, + MTC1, + MFC1, + CTC1, + CFC1, + BC1T, + BC1T_OUT, + BC1T_IDLE, + BC1F, + BC1F_OUT, + BC1F_IDLE, + + DMFC1, + DMTC1, + LDC1, + SDC1, + + CVT_S_D, + CVT_S_W, + CVT_S_L, + CVT_D_S, + CVT_D_W, + CVT_D_L, + CVT_W_S, + CVT_W_D, + CVT_L_S, + CVT_L_D, + + ROUND_W_S, + ROUND_W_D, + ROUND_L_S, + ROUND_L_D, + + TRUNC_W_S, + TRUNC_W_D, + TRUNC_L_S, + TRUNC_L_D, + + CEIL_W_S, + CEIL_W_D, + CEIL_L_S, + CEIL_L_D, + + FLOOR_W_S, + FLOOR_W_D, + FLOOR_L_S, + FLOOR_L_D, + + ADD_S, + ADD_D, + + SUB_S, + SUB_D, + + MUL_S, + MUL_D, + + DIV_S, + DIV_D, + + ABS_S, + ABS_D, + + MOV_S, + MOV_D, + + NEG_S, + NEG_D, + + SQRT_S, + SQRT_D, + + C_F_S, + C_F_D, + C_UN_S, + C_UN_D, + C_EQ_S, + C_EQ_D, + C_UEQ_S, + C_UEQ_D, + C_OLT_S, + C_OLT_D, + C_ULT_S, + C_ULT_D, + C_OLE_S, + C_OLE_D, + C_ULE_S, + C_ULE_D, + C_SF_S, + C_SF_D, + C_NGLE_S, + C_NGLE_D, + C_SEQ_S, + C_SEQ_D, + C_NGL_S, + C_NGL_D, + C_LT_S, + C_LT_D, + C_NGE_S, + C_NGE_D, + C_LE_S, + C_LE_D, + C_NGT_S, + C_NGT_D, + + SYSCALL, + BREAK, + + TEQ, + + NOP, + RESERVED, + NI, + + FIN_BLOCK, + NOTCOMPILED, + NOTCOMPILED2 +}; + +static unsigned int osal_fastcall update_invalid_addr(usf_state_t * state, unsigned int addr) +{ + if (addr >= 0x80000000 && addr < 0xc0000000) + { + if (state->invalid_code[addr>>12]) state->invalid_code[(addr^0x20000000)>>12] = 1; + if (state->invalid_code[(addr^0x20000000)>>12]) state->invalid_code[addr>>12] = 1; + return addr; + } + else + { + unsigned int paddr = virtual_to_physical_address(state, addr, 2); + if (paddr) + { + unsigned int beg_paddr = paddr - (addr - (addr&~0xFFF)); + update_invalid_addr(state, paddr); + if (state->invalid_code[(beg_paddr+0x000)>>12]) state->invalid_code[addr>>12] = 1; + if (state->invalid_code[(beg_paddr+0xFFC)>>12]) state->invalid_code[addr>>12] = 1; + if (state->invalid_code[addr>>12]) state->invalid_code[(beg_paddr+0x000)>>12] = 1; + if (state->invalid_code[addr>>12]) state->invalid_code[(beg_paddr+0xFFC)>>12] = 1; + } + return paddr; + } +} + +#define addr state->jump_to_address +void osal_fastcall jump_to_func(usf_state_t * state) +{ + unsigned int paddr; + if (state->skip_jump) return; + paddr = update_invalid_addr(state, addr); + if (!paddr) return; + state->actual = state->blocks[addr>>12]; + if (state->invalid_code[addr>>12]) + { + if (!state->blocks[addr>>12]) + { + state->blocks[addr>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + state->actual = state->blocks[addr>>12]; + state->blocks[addr>>12]->code = NULL; + state->blocks[addr>>12]->block = NULL; + state->blocks[addr>>12]->jumps_table = NULL; + state->blocks[addr>>12]->riprel_table = NULL; + } + state->blocks[addr>>12]->start = addr & ~0xFFF; + state->blocks[addr>>12]->end = (addr & ~0xFFF) + 0x1000; + init_block(state, state->blocks[addr>>12]); + } + state->PC=state->actual->block+((addr-state->actual->start)>>2); + + if (state->r4300emu == CORE_DYNAREC) dyna_jump(state); +} +#undef addr + +void osal_fastcall init_blocks(usf_state_t * state) +{ + int i; + for (i=0; i<0x100000; i++) + { + state->invalid_code[i] = 1; + state->blocks[i] = NULL; + } +} + +void osal_fastcall free_blocks(usf_state_t * state) +{ + int i; + for (i=0; i<0x100000; i++) + { + if (state->blocks[i]) + { + free_block(state, state->blocks[i]); + free(state->blocks[i]); + state->blocks[i] = NULL; + } + } +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/cached_interp.h b/Frameworks/lazyusf/lazyusf/r4300/cached_interp.h new file mode 100644 index 000000000..6c2c9f95b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cached_interp.h @@ -0,0 +1,44 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cached_interp.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_CACHED_INTERP_H +#define M64P_R4300_CACHED_INTERP_H + +#include "usf/usf.h" + +#include "osal/preproc.h" + +#include "ops.h" +/* FIXME: use forward declaration for precomp_block */ +#include "recomp.h" + +#include "osal/preproc.h" + +extern const cpu_instruction_table cached_interpreter_table; + +void osal_fastcall init_blocks(usf_state_t *); +void osal_fastcall free_blocks(usf_state_t *); +void osal_fastcall jump_to_func(usf_state_t *); + +/* Jumps to the given address. This is for the cached interpreter / dynarec. */ +#define jump_to(a) { state->jump_to_address = a; jump_to_func(state); } + +#endif /* M64P_R4300_CACHED_INTERP_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/cp0.c b/Frameworks/lazyusf/lazyusf/r4300/cp0.c new file mode 100644 index 000000000..3fa87a9e8 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cp0.c @@ -0,0 +1,70 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cp0.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "r4300.h" +#include "cp0.h" +#include "exception.h" + +#include "new_dynarec/new_dynarec.h" + +#ifdef COMPARE_CORE +#include "api/debugger.h" +#endif + +#ifdef DBG +#include "debugger/dbg_types.h" +#include "debugger/debugger.h" +#endif + +/* global functions */ +int osal_fastcall check_cop1_unusable(usf_state_t * state) +{ + if (!(state->g_cp0_regs[CP0_STATUS_REG] & 0x20000000)) + { + state->g_cp0_regs[CP0_CAUSE_REG] = (11 << 2) | 0x10000000; + exception_general(state); + return 1; + } + return 0; +} + +void update_count(usf_state_t * state) +{ +#ifdef NEW_DYNAREC + if (r4300emu != CORE_DYNAREC) + { +#endif + state->g_cp0_regs[CP0_COUNT_REG] += ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op; + state->last_addr = state->PC->addr; +#ifdef NEW_DYNAREC + } +#endif + +/*#ifdef DBG + if (g_DebuggerActive && !delay_slot) update_debugger(PC->addr); +#endif +*/ +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/cp0.h b/Frameworks/lazyusf/lazyusf/r4300/cp0.h new file mode 100644 index 000000000..e5885b711 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cp0.h @@ -0,0 +1,61 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cp0.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_CP0_H +#define M64P_R4300_CP0_H + +#include "usf/usf.h" + +enum { + CP0_INDEX_REG, + CP0_RANDOM_REG, + CP0_ENTRYLO0_REG, + CP0_ENTRYLO1_REG, + CP0_CONTEXT_REG, + CP0_PAGEMASK_REG, + CP0_WIRED_REG, + /* 7 is unused */ + CP0_BADVADDR_REG = 8, + CP0_COUNT_REG, + CP0_ENTRYHI_REG, + CP0_COMPARE_REG, + CP0_STATUS_REG, + CP0_CAUSE_REG, + CP0_EPC_REG, + CP0_PREVID_REG, + CP0_CONFIG_REG, + CP0_LLADDR_REG, + CP0_WATCHLO_REG, + CP0_WATCHHI_REG, + CP0_XCONTEXT_REG, + /* 21 - 27 are unused */ + CP0_TAGLO_REG = 28, + CP0_TAGHI_REG, + CP0_ERROREPC_REG, + /* 31 is unused */ + CP0_REGS_COUNT = 32 +}; + +int osal_fastcall check_cop1_unusable(usf_state_t *); +void update_count(usf_state_t *); + +#endif /* M64P_R4300_CP0_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/cp1.c b/Frameworks/lazyusf/lazyusf/r4300/cp1.c new file mode 100644 index 000000000..2fbe6c451 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cp1.c @@ -0,0 +1,110 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cp1.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "new_dynarec/new_dynarec.h" + +#include "usf/usf_internal.h" + +/* Refer to Figure 6-2 on page 155 and explanation on page B-11 + of MIPS R4000 Microprocessor User's Manual (Second Edition) + by Joe Heinrich. +*/ +void shuffle_fpr_data(usf_state_t * state, int oldStatus, int newStatus) +{ +#if defined(M64P_BIG_ENDIAN) + const int isBigEndian = 1; +#else + const int isBigEndian = 0; +#endif + + if ((newStatus & 0x04000000) != (oldStatus & 0x04000000)) + { + int i; + int temp_fgr_32[32]; + + // pack or unpack the FGR register data + if (newStatus & 0x04000000) + { // switching into 64-bit mode + // retrieve 32 FPR values from packed 32-bit FGR registers + for (i = 0; i < 32; i++) + { + temp_fgr_32[i] = *((int *) &state->reg_cop1_fgr_64[i>>1] + ((i & 1) ^ isBigEndian)); + } + // unpack them into 32 64-bit registers, taking the high 32-bits from their temporary place in the upper 16 FGRs + for (i = 0; i < 32; i++) + { + int high32 = *((int *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1)); + *((int *) &state->reg_cop1_fgr_64[i] + isBigEndian) = temp_fgr_32[i]; + *((int *) &state->reg_cop1_fgr_64[i] + (isBigEndian^1)) = high32; + } + } + else + { // switching into 32-bit mode + // retrieve the high 32 bits from each 64-bit FGR register and store in temp array + for (i = 0; i < 32; i++) + { + temp_fgr_32[i] = *((int *) &state->reg_cop1_fgr_64[i] + (isBigEndian^1)); + } + // take the low 32 bits from each register and pack them together into 64-bit pairs + for (i = 0; i < 16; i++) + { + unsigned int least32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2] + isBigEndian); + unsigned int most32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2+1] + isBigEndian); + state->reg_cop1_fgr_64[i] = ((unsigned long long) most32 << 32) | (unsigned long long) least32; + } + // store the high bits in the upper 16 FGRs, which wont be accessible in 32-bit mode + for (i = 0; i < 32; i++) + { + *((int *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1)) = temp_fgr_32[i]; + } + } + } +} + +void set_fpr_pointers(usf_state_t * state, int newStatus) +{ + int i; +#if defined(M64P_BIG_ENDIAN) + const int isBigEndian = 1; +#else + const int isBigEndian = 0; +#endif + + // update the FPR register pointers + if (newStatus & 0x04000000) + { + for (i = 0; i < 32; i++) + { + state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i]; + state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i]) + isBigEndian; + } + } + else + { + for (i = 0; i < 32; i++) + { + state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i>>1]; + state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i>>1]) + ((i & 1) ^ isBigEndian); + } + } +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/cp1.h b/Frameworks/lazyusf/lazyusf/r4300/cp1.h new file mode 100644 index 000000000..ad21d4ccd --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/cp1.h @@ -0,0 +1,31 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cp1.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_CP1_H +#define M64P_R4300_CP1_H + +#include "usf/usf.h" + +void shuffle_fpr_data(usf_state_t *, int oldStatus, int newStatus); +void set_fpr_pointers(usf_state_t *, int newStatus); + +#endif /* M64P_R4300_CP1_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/empty_dynarec.c b/Frameworks/lazyusf/lazyusf/r4300/empty_dynarec.c new file mode 100644 index 000000000..64391705e --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/empty_dynarec.c @@ -0,0 +1,1052 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - empty_dynarec.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Richard42, Nmn * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "recomp.h" + +/* From assemble.c */ + +void init_assembler(usf_state_t * state, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number) +{ +} + +void free_assembler(usf_state_t * state, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number) +{ +} + +void passe2(usf_state_t * state, precomp_instr *dest, int start, int end, precomp_block *block) +{ +} + +/* From gbc.c */ + +void genbc1f(usf_state_t * state) +{ +} + +void genbc1f_out(usf_state_t * state) +{ +} + +void genbc1f_idle(usf_state_t * state) +{ +} + +void genbc1t(usf_state_t * state) +{ +} + +void genbc1t_out(usf_state_t * state) +{ +} + +void genbc1t_idle(usf_state_t * state) +{ +} + +void genbc1fl(usf_state_t * state) +{ +} + +void genbc1fl_out(usf_state_t * state) +{ +} + +void genbc1fl_idle(usf_state_t * state) +{ +} + +void genbc1tl(usf_state_t * state) +{ +} + +void genbc1tl_out(usf_state_t * state) +{ +} + +void genbc1tl_idle(usf_state_t * state) +{ +} + +/* From gcop0.c */ + +void genmfc0(usf_state_t * state) +{ +} + +void genmtc0(usf_state_t * state) +{ +} + +/* From gcop1.c */ + +void genmfc1(usf_state_t * state) +{ +} + +void gendmfc1(usf_state_t * state) +{ +} + +void gencfc1(usf_state_t * state) +{ +} + +void genmtc1(usf_state_t * state) +{ +} + +void gendmtc1(usf_state_t * state) +{ +} + +void genctc1(usf_state_t * state) +{ +} + +/* From gcop1_d.c */ + +void genadd_d(usf_state_t * state) +{ +} + +void gensub_d(usf_state_t * state) +{ +} + +void genmul_d(usf_state_t * state) +{ +} + +void gendiv_d(usf_state_t * state) +{ +} + +void gensqrt_d(usf_state_t * state) +{ +} + +void genabs_d(usf_state_t * state) +{ +} + +void genmov_d(usf_state_t * state) +{ +} + +void genneg_d(usf_state_t * state) +{ +} + +void genround_l_d(usf_state_t * state) +{ +} + +void gentrunc_l_d(usf_state_t * state) +{ +} + +void genceil_l_d(usf_state_t * state) +{ +} + +void genfloor_l_d(usf_state_t * state) +{ +} + +void genround_w_d(usf_state_t * state) +{ +} + +void gentrunc_w_d(usf_state_t * state) +{ +} + +void genceil_w_d(usf_state_t * state) +{ +} + +void genfloor_w_d(usf_state_t * state) +{ +} + +void gencvt_s_d(usf_state_t * state) +{ +} + +void gencvt_w_d(usf_state_t * state) +{ +} + +void gencvt_l_d(usf_state_t * state) +{ +} + +void genc_f_d(usf_state_t * state) +{ +} + +void genc_un_d(usf_state_t * state) +{ +} + +void genc_eq_d(usf_state_t * state) +{ +} + +void genc_ueq_d(usf_state_t * state) +{ +} + +void genc_olt_d(usf_state_t * state) +{ +} + +void genc_ult_d(usf_state_t * state) +{ +} + +void genc_ole_d(usf_state_t * state) +{ +} + +void genc_ule_d(usf_state_t * state) +{ +} + +void genc_sf_d(usf_state_t * state) +{ +} + +void genc_ngle_d(usf_state_t * state) +{ +} + +void genc_seq_d(usf_state_t * state) +{ +} + +void genc_ngl_d(usf_state_t * state) +{ +} + +void genc_lt_d(usf_state_t * state) +{ +} + +void genc_nge_d(usf_state_t * state) +{ +} + +void genc_le_d(usf_state_t * state) +{ +} + +void genc_ngt_d(usf_state_t * state) +{ +} + +/* From gcop1_l.c */ + +void gencvt_s_l(usf_state_t * state) +{ +} + +void gencvt_d_l(usf_state_t * state) +{ +} + +/* From gcop1_s.c */ + +void genadd_s(usf_state_t * state) +{ +} + +void gensub_s(usf_state_t * state) +{ +} + +void genmul_s(usf_state_t * state) +{ +} + +void gendiv_s(usf_state_t * state) +{ +} + +void gensqrt_s(usf_state_t * state) +{ +} + +void genabs_s(usf_state_t * state) +{ +} + +void genmov_s(usf_state_t * state) +{ +} + +void genneg_s(usf_state_t * state) +{ +} + +void genround_l_s(usf_state_t * state) +{ +} + +void gentrunc_l_s(usf_state_t * state) +{ +} + +void genceil_l_s(usf_state_t * state) +{ +} + +void genfloor_l_s(usf_state_t * state) +{ +} + +void genround_w_s(usf_state_t * state) +{ +} + +void gentrunc_w_s(usf_state_t * state) +{ +} + +void genceil_w_s(usf_state_t * state) +{ +} + +void genfloor_w_s(usf_state_t * state) +{ +} + +void gencvt_d_s(usf_state_t * state) +{ +} + +void gencvt_w_s(usf_state_t * state) +{ +} + +void gencvt_l_s(usf_state_t * state) +{ +} + +void genc_f_s(usf_state_t * state) +{ +} + +void genc_un_s(usf_state_t * state) +{ +} + +void genc_eq_s(usf_state_t * state) +{ +} + +void genc_ueq_s(usf_state_t * state) +{ +} + +void genc_olt_s(usf_state_t * state) +{ +} + +void genc_ult_s(usf_state_t * state) +{ +} + +void genc_ole_s(usf_state_t * state) +{ +} + +void genc_ule_s(usf_state_t * state) +{ +} + +void genc_sf_s(usf_state_t * state) +{ +} + +void genc_ngle_s(usf_state_t * state) +{ +} + +void genc_seq_s(usf_state_t * state) +{ +} + +void genc_ngl_s(usf_state_t * state) +{ +} + +void genc_lt_s(usf_state_t * state) +{ +} + +void genc_nge_s(usf_state_t * state) +{ +} + +void genc_le_s(usf_state_t * state) +{ +} + +void genc_ngt_s(usf_state_t * state) +{ +} + +/* From gcop1_w.c */ + +void gencvt_s_w(usf_state_t * state) +{ +} + +void gencvt_d_w(usf_state_t * state) +{ +} + +/* From gr4300.c */ + +void gennotcompiled(usf_state_t * state) +{ +} + +void genlink_subblock(usf_state_t * state) +{ +} + +void genni(usf_state_t * state) +{ +} + +void genreserved(usf_state_t * state) +{ +} + +void genfin_block(usf_state_t * state) +{ +} + +void gennop(usf_state_t * state) +{ +} + +void genj(usf_state_t * state) +{ +} + +void genj_out(usf_state_t * state) +{ +} + +void genj_idle(usf_state_t * state) +{ +} + +void genjal(usf_state_t * state) +{ +} + +void genjal_out(usf_state_t * state) +{ +} + +void genjal_idle(usf_state_t * state) +{ +} + +void genbne(usf_state_t * state) +{ +} + +void genbne_out(usf_state_t * state) +{ +} + +void genbne_idle(usf_state_t * state) +{ +} + +void genblez(usf_state_t * state) +{ +} + +void genblez_idle(usf_state_t * state) +{ +} + +void genbgtz(usf_state_t * state) +{ +} + +void genbgtz_out(usf_state_t * state) +{ +} + +void genbgtz_idle(usf_state_t * state) +{ +} + +void genaddi(usf_state_t * state) +{ +} + +void genaddiu(usf_state_t * state) +{ +} + +void genslti(usf_state_t * state) +{ +} + +void gensltiu(usf_state_t * state) +{ +} + +void genandi(usf_state_t * state) +{ +} + +void genori(usf_state_t * state) +{ +} + +void genxori(usf_state_t * state) +{ +} + +void genlui(usf_state_t * state) +{ +} + +void genbeql(usf_state_t * state) +{ +} + +void genbeql_out(usf_state_t * state) +{ +} + +void genbeql_idle(usf_state_t * state) +{ +} + +void genbeq(usf_state_t * state) +{ +} + +void genbeq_out(usf_state_t * state) +{ +} + +void genbeq_idle(usf_state_t * state) +{ +} + +void genbnel(usf_state_t * state) +{ +} + +void genbnel_out(usf_state_t * state) +{ +} + +void genbnel_idle(usf_state_t * state) +{ +} + +void genblezl(usf_state_t * state) +{ +} + +void genblezl_out(usf_state_t * state) +{ +} + +void genblezl_idle(usf_state_t * state) +{ +} + +void genbgtzl(usf_state_t * state) +{ +} + +void genbgtzl_out(usf_state_t * state) +{ +} + +void genbgtzl_idle(usf_state_t * state) +{ +} + +void gendaddi(usf_state_t * state) +{ +} + +void gendaddiu(usf_state_t * state) +{ +} + +void genldl(usf_state_t * state) +{ +} + +void genldr(usf_state_t * state) +{ +} + +void genlb(usf_state_t * state) +{ +} + +void genlh(usf_state_t * state) +{ +} + +void genlwl(usf_state_t * state) +{ +} + +void genlw(usf_state_t * state) +{ +} + +void genlbu(usf_state_t * state) +{ +} + +void genlhu(usf_state_t * state) +{ +} + +void genlwr(usf_state_t * state) +{ +} + +void genlwu(usf_state_t * state) +{ +} + +void gensb(usf_state_t * state) +{ +} + +void gensh(usf_state_t * state) +{ +} + +void genswl(usf_state_t * state) +{ +} + +void gensw(usf_state_t * state) +{ +} + +void gensdl(usf_state_t * state) +{ +} + +void gensdr(usf_state_t * state) +{ +} + +void genswr(usf_state_t * state) +{ +} + +void genlwc1(usf_state_t * state) +{ +} + +void genldc1(usf_state_t * state) +{ +} + +void gencache(usf_state_t * state) +{ +} + +void genld(usf_state_t * state) +{ +} + +void genswc1(usf_state_t * state) +{ +} + +void gensdc1(usf_state_t * state) +{ +} + +void gensd(usf_state_t * state) +{ +} + +void genll(usf_state_t * state) +{ +} + +void gensc(usf_state_t * state) +{ +} + +void genblez_out(usf_state_t * state) +{ +} + +/* From gregimm.c */ + +void genbltz(usf_state_t * state) +{ +} + +void genbltz_out(usf_state_t * state) +{ +} + +void genbltz_idle(usf_state_t * state) +{ +} + +void genbgez(usf_state_t * state) +{ +} + +void genbgez_out(usf_state_t * state) +{ +} + +void genbgez_idle(usf_state_t * state) +{ +} + +void genbltzl(usf_state_t * state) +{ +} + +void genbltzl_out(usf_state_t * state) +{ +} + +void genbltzl_idle(usf_state_t * state) +{ +} + +void genbgezl(usf_state_t * state) +{ +} + +void genbgezl_out(usf_state_t * state) +{ +} + +void genbgezl_idle(usf_state_t * state) +{ +} + +void genbltzal(usf_state_t * state) +{ +} + +void genbltzal_out(usf_state_t * state) +{ +} + +void genbltzal_idle(usf_state_t * state) +{ +} + +void genbgezal(usf_state_t * state) +{ +} + +void genbgezal_out(usf_state_t * state) +{ +} + +void genbgezal_idle(usf_state_t * state) +{ +} + +void genbltzall(usf_state_t * state) +{ +} + +void genbltzall_out(usf_state_t * state) +{ +} + +void genbltzall_idle(usf_state_t * state) +{ +} + +void genbgezall(usf_state_t * state) +{ +} + +void genbgezall_out(usf_state_t * state) +{ +} + +void genbgezall_idle(usf_state_t * state) +{ +} + +/* From gspecial.c */ + +void gensll(usf_state_t * state) +{ +} + +void gensrl(usf_state_t * state) +{ +} + +void gensra(usf_state_t * state) +{ +} + +void gensllv(usf_state_t * state) +{ +} + +void gensrlv(usf_state_t * state) +{ +} + +void gensrav(usf_state_t * state) +{ +} + +void genjr(usf_state_t * state) +{ +} + +void genjalr(usf_state_t * state) +{ +} + +void gensyscall(usf_state_t * state) +{ +} + +void gensync(usf_state_t * state) +{ +} + +void genmfhi(usf_state_t * state) +{ +} + +void genmthi(usf_state_t * state) +{ +} + +void genmflo(usf_state_t * state) +{ +} + +void genmtlo(usf_state_t * state) +{ +} + +void gendsllv(usf_state_t * state) +{ +} + +void gendsrlv(usf_state_t * state) +{ +} + +void gendsrav(usf_state_t * state) +{ +} + +void genmult(usf_state_t * state) +{ +} + +void genmultu(usf_state_t * state) +{ +} + +void gendiv(usf_state_t * state) +{ +} + +void gendivu(usf_state_t * state) +{ +} + +void gendmult(usf_state_t * state) +{ +} + +void gendmultu(usf_state_t * state) +{ +} + +void genddiv(usf_state_t * state) +{ +} + +void genddivu(usf_state_t * state) +{ +} + +void genadd(usf_state_t * state) +{ +} + +void genaddu(usf_state_t * state) +{ +} + +void gensub(usf_state_t * state) +{ +} + +void gensubu(usf_state_t * state) +{ +} + +void genand(usf_state_t * state) +{ +} + +void genor(usf_state_t * state) +{ +} + +void genxor(usf_state_t * state) +{ +} + +void gennor(usf_state_t * state) +{ +} + +void genslt(usf_state_t * state) +{ +} + +void gensltu(usf_state_t * state) +{ +} + +void gendadd(usf_state_t * state) +{ +} + +void gendaddu(usf_state_t * state) +{ +} + +void gendsub(usf_state_t * state) +{ +} + +void gendsubu(usf_state_t * state) +{ +} + +void genteq(usf_state_t * state) +{ +} + +void gendsll(usf_state_t * state) +{ +} + +void gendsrl(usf_state_t * state) +{ +} + +void gendsra(usf_state_t * state) +{ +} + +void gendsll32(usf_state_t * state) +{ +} + +void gendsrl32(usf_state_t * state) +{ +} + +void gendsra32(usf_state_t * state) +{ +} + +void genbreak(usf_state_t * state) +{ +} + +/* From gtlb.c */ + +void gentlbwi(usf_state_t * state) +{ +} + +void gentlbp(usf_state_t * state) +{ +} + +void gentlbr(usf_state_t * state) +{ +} + +void generet(usf_state_t * state) +{ +} + +void gentlbwr(usf_state_t * state) +{ +} + +/* From regcache.c */ + +void init_cache(usf_state_t * state, precomp_instr* start) +{ +} + +void free_all_registers(usf_state_t * state) +{ +} + +/* From rjump.c */ + +void dyna_jump(usf_state_t * state) +{ +} + +void dyna_stop(usf_state_t * state) +{ +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/exception.c b/Frameworks/lazyusf/lazyusf/r4300/exception.c new file mode 100644 index 000000000..41c185726 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/exception.c @@ -0,0 +1,149 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - exception.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "memory/memory.h" + +#include "exception.h" +#include "r4300.h" +#include "cp0.h" +#include "recomph.h" +#include "tlb.h" + +void TLB_refill_exception(usf_state_t * state, unsigned int address, int w) +{ + int usual_handler = 0, i; + + if (state->r4300emu != CORE_DYNAREC && w != 2) update_count(state); + if (w == 1) state->g_cp0_regs[CP0_CAUSE_REG] = (3 << 2); + else state->g_cp0_regs[CP0_CAUSE_REG] = (2 << 2); + state->g_cp0_regs[CP0_BADVADDR_REG] = address; + state->g_cp0_regs[CP0_CONTEXT_REG] = (state->g_cp0_regs[CP0_CONTEXT_REG] & 0xFF80000F) | ((address >> 9) & 0x007FFFF0); + state->g_cp0_regs[CP0_ENTRYHI_REG] = address & 0xFFFFE000; + if (state->g_cp0_regs[CP0_STATUS_REG] & 0x2) // Test de EXL + { + generic_jump_to(state, 0x80000180); + if(state->delay_slot==1 || state->delay_slot==3) state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000; + else state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF; + } + else + { + if (state->r4300emu != CORE_PURE_INTERPRETER) + { + if (w!=2) + state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr; + else + state->g_cp0_regs[CP0_EPC_REG] = address; + } + else state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr; + + state->g_cp0_regs[CP0_CAUSE_REG] &= ~0x80000000; + state->g_cp0_regs[CP0_STATUS_REG] |= 0x2; //EXL=1 + + if (address >= 0x80000000 && address < 0xc0000000) + usual_handler = 1; + for (i=0; i<32; i++) + { + if (/*state->tlb_e[i].v_even &&*/ address >= state->tlb_e[i].start_even && + address <= state->tlb_e[i].end_even) + usual_handler = 1; + if (/*state->tlb_e[i].v_odd &&*/ address >= state->tlb_e[i].start_odd && + address <= state->tlb_e[i].end_odd) + usual_handler = 1; + } + if (usual_handler) + { + generic_jump_to(state, 0x80000180); + } + else + { + generic_jump_to(state, 0x80000000); + } + } + if(state->delay_slot==1 || state->delay_slot==3) + { + state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000; + state->g_cp0_regs[CP0_EPC_REG]-=4; + } + else + { + state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF; + } + if(w != 2) state->g_cp0_regs[CP0_EPC_REG]-=4; + + state->last_addr = state->PC->addr; + + if (state->r4300emu == CORE_DYNAREC) + { + dyna_jump(state); + if (!state->dyna_interp) state->delay_slot = 0; + } + + if (state->r4300emu != CORE_DYNAREC || state->dyna_interp) + { + state->dyna_interp = 0; + if (state->delay_slot) + { + state->skip_jump = state->PC->addr; + state->next_interupt = 0; + } + } +} + +void osal_fastcall exception_general(usf_state_t * state) +{ + update_count(state); + state->g_cp0_regs[CP0_STATUS_REG] |= 2; + + state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr; + + if(state->delay_slot==1 || state->delay_slot==3) + { + state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000; + state->g_cp0_regs[CP0_EPC_REG]-=4; + } + else + { + state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF; + } + generic_jump_to(state, 0x80000180); + state->last_addr = state->PC->addr; + if (state->r4300emu == CORE_DYNAREC) + { + dyna_jump(state); + if (!state->dyna_interp) state->delay_slot = 0; + } + if (state->r4300emu != CORE_DYNAREC || state->dyna_interp) + { + state->dyna_interp = 0; + if (state->delay_slot) + { + state->skip_jump = state->PC->addr; + state->next_interupt = 0; + } + } +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/exception.h b/Frameworks/lazyusf/lazyusf/r4300/exception.h new file mode 100644 index 000000000..ec80cc74c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/exception.h @@ -0,0 +1,31 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - exception.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_EXCEPTION_H +#define M64P_R4300_EXCEPTION_H + +#include "usf/usf.h" + +void TLB_refill_exception(usf_state_t *, unsigned int addresse, int w); +void osal_fastcall exception_general(usf_state_t *); + +#endif /* M64P_R4300_EXCEPTION_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/fpu.h b/Frameworks/lazyusf/lazyusf/r4300/fpu.h new file mode 100644 index 000000000..da20e50f1 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/fpu.h @@ -0,0 +1,465 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - fpu.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2010 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_FPU_H +#define M64P_R4300_FPU_H + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "r4300.h" + +#ifdef _MSC_VER + #define M64P_FPU_INLINE static __inline + #include + typedef enum { FE_TONEAREST = 0, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD } eRoundType; + static void fesetround(eRoundType RoundType) + { + static const unsigned int msRound[4] = { _RC_NEAR, _RC_CHOP, _RC_UP, _RC_DOWN }; + unsigned int oldX87, oldSSE2; + __control87_2(msRound[RoundType], _MCW_RC, &oldX87, &oldSSE2); + } + static __inline double round(double x) { return floor(x + 0.5); } + static __inline float roundf(float x) { return (float) floor(x + 0.5); } + static __inline double trunc(double x) { return (double) (int) x; } + static __inline float truncf(float x) { return (float) (int) x; } + #define isnan _isnan +#else + #define M64P_FPU_INLINE static inline + #include +#endif + + +M64P_FPU_INLINE void set_rounding(usf_state_t * state) +{ + switch(state->rounding_mode) { + case 0x33F: + fesetround(FE_TONEAREST); + break; + case 0xF3F: + fesetround(FE_TOWARDZERO); + break; + case 0xB3F: + fesetround(FE_UPWARD); + break; + case 0x73F: + fesetround(FE_DOWNWARD); + break; + } +} + +M64P_FPU_INLINE void cvt_s_w(usf_state_t * state, int *source,float *dest) +{ + set_rounding(state); + *dest = (float) *source; +} +M64P_FPU_INLINE void cvt_d_w(usf_state_t * state, int *source,double *dest) +{ + (void)state; + *dest = (double) *source; +} +M64P_FPU_INLINE void cvt_s_l(usf_state_t * state, long long *source,float *dest) +{ + set_rounding(state); + *dest = (float) *source; +} +M64P_FPU_INLINE void cvt_d_l(usf_state_t * state, long long *source,double *dest) +{ + set_rounding(state); + *dest = (double) *source; +} +M64P_FPU_INLINE void cvt_d_s(usf_state_t * state, float *source,double *dest) +{ + (void)state; + *dest = (double) *source; +} +M64P_FPU_INLINE void cvt_s_d(usf_state_t * state, double *source,float *dest) +{ + set_rounding(state); + *dest = (float) *source; +} + +M64P_FPU_INLINE void round_l_s(float *source,long long *dest) +{ + *dest = (long long) roundf(*source); +} +M64P_FPU_INLINE void round_w_s(float *source,int *dest) +{ + *dest = (int) roundf(*source); +} +M64P_FPU_INLINE void trunc_l_s(float *source,long long *dest) +{ + *dest = (long long) truncf(*source); +} +M64P_FPU_INLINE void trunc_w_s(float *source,int *dest) +{ + *dest = (int) truncf(*source); +} +M64P_FPU_INLINE void ceil_l_s(float *source,long long *dest) +{ + *dest = (long long) ceilf(*source); +} +M64P_FPU_INLINE void ceil_w_s(float *source,int *dest) +{ + *dest = (int) ceilf(*source); +} +M64P_FPU_INLINE void floor_l_s(float *source,long long *dest) +{ + *dest = (long long) floorf(*source); +} +M64P_FPU_INLINE void floor_w_s(float *source,int *dest) +{ + *dest = (int) floorf(*source); +} + +M64P_FPU_INLINE void round_l_d(double *source,long long *dest) +{ + *dest = (long long) round(*source); +} +M64P_FPU_INLINE void round_w_d(double *source,int *dest) +{ + *dest = (int) round(*source); +} +M64P_FPU_INLINE void trunc_l_d(double *source,long long *dest) +{ + *dest = (long long) trunc(*source); +} +M64P_FPU_INLINE void trunc_w_d(double *source,int *dest) +{ + *dest = (int) trunc(*source); +} +M64P_FPU_INLINE void ceil_l_d(double *source,long long *dest) +{ + *dest = (long long) ceil(*source); +} +M64P_FPU_INLINE void ceil_w_d(double *source,int *dest) +{ + *dest = (int) ceil(*source); +} +M64P_FPU_INLINE void floor_l_d(double *source,long long *dest) +{ + *dest = (long long) floor(*source); +} +M64P_FPU_INLINE void floor_w_d(double *source,int *dest) +{ + *dest = (int) floor(*source); +} + +M64P_FPU_INLINE void cvt_w_s(usf_state_t * state, float *source,int *dest) +{ + switch(state->FCR31&3) + { + case 0: round_w_s(source,dest);return; + case 1: trunc_w_s(source,dest);return; + case 2: ceil_w_s(source,dest);return; + case 3: floor_w_s(source,dest);return; + } +} +M64P_FPU_INLINE void cvt_w_d(usf_state_t * state, double *source,int *dest) +{ + switch(state->FCR31&3) + { + case 0: round_w_d(source,dest);return; + case 1: trunc_w_d(source,dest);return; + case 2: ceil_w_d(source,dest);return; + case 3: floor_w_d(source,dest);return; + } +} +M64P_FPU_INLINE void cvt_l_s(usf_state_t * state, float *source,long long *dest) +{ + switch(state->FCR31&3) + { + case 0: round_l_s(source,dest);return; + case 1: trunc_l_s(source,dest);return; + case 2: ceil_l_s(source,dest);return; + case 3: floor_l_s(source,dest);return; + } +} +M64P_FPU_INLINE void cvt_l_d(usf_state_t * state, double *source,long long *dest) +{ + switch(state->FCR31&3) + { + case 0: round_l_d(source,dest);return; + case 1: trunc_l_d(source,dest);return; + case 2: ceil_l_d(source,dest);return; + case 3: floor_l_d(source,dest);return; + } +} + +M64P_FPU_INLINE void c_f_s(usf_state_t * state) +{ + state->FCR31 &= ~0x800000; +} +M64P_FPU_INLINE void c_un_s(usf_state_t * state, float *source,float *target) +{ + state->FCR31=(isnan(*source) || isnan(*target)) ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_eq_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ueq_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_olt_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ult_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_ole_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ule_s(usf_state_t * state, float *source,float *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_sf_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31&=~0x800000; +} +M64P_FPU_INLINE void c_ngle_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31&=~0x800000; +} + +M64P_FPU_INLINE void c_seq_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ngl_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_lt_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_nge_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_le_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ngt_s(usf_state_t * state, float *source,float *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_f_d(usf_state_t * state) +{ + state->FCR31 &= ~0x800000; +} +M64P_FPU_INLINE void c_un_d(usf_state_t * state, double *source,double *target) +{ + state->FCR31=(isnan(*source) || isnan(*target)) ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_eq_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ueq_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_olt_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ult_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_ole_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;} + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ule_d(usf_state_t * state, double *source,double *target) +{ + if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;} + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_sf_d(usf_state_t * state, double *source,double *target) +{ + (void)source; (void)target; + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31&=~0x800000; +} +M64P_FPU_INLINE void c_ngle_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31&=~0x800000; +} + +M64P_FPU_INLINE void c_seq_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ngl_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_lt_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_nge_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + +M64P_FPU_INLINE void c_le_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} +M64P_FPU_INLINE void c_ngt_d(usf_state_t * state, double *source,double *target) +{ + //if (isnan(*source) || isnan(*target)) // FIXME - exception + state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000; +} + + +M64P_FPU_INLINE void add_s(usf_state_t * state, float *source1,float *source2,float *target) +{ + set_rounding(state); + *target=(*source1)+(*source2); +} +M64P_FPU_INLINE void sub_s(usf_state_t * state, float *source1,float *source2,float *target) +{ + set_rounding(state); + *target=(*source1)-(*source2); +} +M64P_FPU_INLINE void mul_s(usf_state_t * state, float *source1,float *source2,float *target) +{ + set_rounding(state); + *target=(*source1)*(*source2); +} +M64P_FPU_INLINE void div_s(usf_state_t * state, float *source1,float *source2,float *target) +{ + set_rounding(state); + *target=(*source1)/(*source2); +} +M64P_FPU_INLINE void sqrt_s(usf_state_t * state, float *source,float *target) +{ + set_rounding(state); + *target=sqrtf(*source); +} +M64P_FPU_INLINE void abs_s(usf_state_t * state, float *source,float *target) +{ + (void)state; + *target=fabsf(*source); +} +M64P_FPU_INLINE void mov_s(usf_state_t * state, float *source,float *target) +{ + (void)state; + *target=*source; +} +M64P_FPU_INLINE void neg_s(usf_state_t * state, float *source,float *target) +{ + (void)state; + *target=-(*source); +} +M64P_FPU_INLINE void add_d(usf_state_t * state, double *source1,double *source2,double *target) +{ + set_rounding(state); + *target=(*source1)+(*source2); +} +M64P_FPU_INLINE void sub_d(usf_state_t * state, double *source1,double *source2,double *target) +{ + set_rounding(state); + *target=(*source1)-(*source2); +} +M64P_FPU_INLINE void mul_d(usf_state_t * state, double *source1,double *source2,double *target) +{ + set_rounding(state); + *target=(*source1)*(*source2); +} +M64P_FPU_INLINE void div_d(usf_state_t * state, double *source1,double *source2,double *target) +{ + set_rounding(state); + *target=(*source1)/(*source2); +} +M64P_FPU_INLINE void sqrt_d(usf_state_t * state, double *source,double *target) +{ + set_rounding(state); + *target=sqrt(*source); +} +M64P_FPU_INLINE void abs_d(usf_state_t * state, double *source,double *target) +{ + (void)state; + *target=fabs(*source); +} +M64P_FPU_INLINE void mov_d(usf_state_t * state, double *source,double *target) +{ + (void)state; + *target=*source; +} +M64P_FPU_INLINE void neg_d(usf_state_t * state, double *source,double *target) +{ + (void)state; + *target=-(*source); +} + +#endif /* M64P_R4300_FPU_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/instr_counters.c b/Frameworks/lazyusf/lazyusf/r4300/instr_counters.c new file mode 100644 index 000000000..091b5c680 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/instr_counters.c @@ -0,0 +1,105 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - instr_counters.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if defined(COUNT_INSTR) + +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" + +/* various constants */ +static char instr_name[][10] = +{ + "reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ", + "ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI", + "BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR", + "LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR", + "SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1", + "LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ", + "BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL", + "SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL", + "MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT", + "MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD", + "ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT", + "SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA", + "TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL", + "TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1", + "DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD", + "f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND", + "f.TRUNC", "f.CEIL", "f.FLOOR" +}; + +static unsigned int instr_type[131] = +{ + 9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0, + 7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7, + 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10, + 2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, + 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, + 5, 5, 5 +}; + +static char instr_typename[][20] = +{ + "Load", "Store", "Data move/convert", + "32-bit math", "64-bit math", "Float Math", + "Jump", "Branch", "Exceptions", + "Reserved", "Other" +}; + +/* global function */ +void instr_counters_print(usf_state_t * state) +{ + size_t i; + unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned int iTotal = 0; + char line[128], param[24]; + DebugMessage(state, M64MSG_INFO, "Instruction counters:"); + line[0] = 0; + for (i = 0; i < 131; i++) + { + sprintf(param, "%8s: %08i ", instr_name[i], state->instr_count[i]); + strcat(line, param); + if (i % 5 == 4) + { + DebugMessage(state, M64MSG_INFO, "%s", line); + line[0] = 0; + } + iTypeCount[instr_type[i]] += state->instr_count[i]; + iTotal += state->instr_count[i]; + } + DebugMessage(state, M64MSG_INFO, "Instruction type summary (total instructions = %i)", iTotal); + for (i = 0; i < 11; i++) + { + DebugMessage(state, M64MSG_INFO, "%20s: %04.1f%% (%i)", instr_typename[i], (float) iTypeCount[i] * 100.0 / iTotal, iTypeCount[i]); + } +} + +#endif /* COUNT_INSTR */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/instr_counters.h b/Frameworks/lazyusf/lazyusf/r4300/instr_counters.h new file mode 100644 index 000000000..36d7302d0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/instr_counters.h @@ -0,0 +1,29 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - instr_counters.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_INSTR_COUNTERS_H +#define M64P_R4300_INSTR_COUNTERS_H + +#if defined(COUNT_INSTR) +void instr_counters_print(usf_state_t * state); +#endif /* COUNT_INSTR */ + +#endif /* M64P_R4300_INSTR_COUNTERS_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter.def new file mode 100644 index 000000000..bbb9a3673 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter.def @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Before #including this file, the following macros should be defined: + * + * PCADDR: Program counter (memory address of the current instruction). + * + * ADD_TO_PC(x): Increment the program counter in 'x' instructions. + * This is only used for small changes to PC, so the new program counter + * is guaranteed to fall in the current cached interpreter or dynarec block. + * + * DECLARE_INSTRUCTION(name) + * Declares an instruction function which is not a jump. + * Followed by a block of code. + * + * DECLARE_JUMP(name, destination, condition, link, likely, cop1) + * name is the name of the jump or branch instruction. + * destination is the destination memory address of the jump. + * If condition is nonzero, the jump is taken. + * link is a pointer to a variable where (PC+8) is written unconditionally. + * To avoid linking, pass ®[0] + * If likely is nonzero, the delay slot is only executed if the jump is taken. + * If cop1 is nonzero, a COP1 unusable check will be done. + * + * CHECK_MEMORY(): A snippet to be run after a store instruction, + * to check if the store affected executable blocks. + * The memory address of the store is in the 'address' global. + */ + +DECLARE_INSTRUCTION(NI) +{ + DebugMessage(state, M64MSG_ERROR, "NI() @ 0x%x", PCADDR); + DebugMessage(state, M64MSG_ERROR, "opcode not implemented: %x:%x", PCADDR, *fast_mem_access(state, PCADDR)); + state->stop=1; +} + +DECLARE_INSTRUCTION(RESERVED) +{ + DebugMessage(state, M64MSG_ERROR, "reserved opcode: %x:%x", PCADDR, *fast_mem_access(state, PCADDR)); + state->stop=1; +} + +// R4300 +#include "interpreter_r4300.def" + +// COP0 +#include "interpreter_cop0.def" + +// COP1 +#include "interpreter_cop1.def" + +// regimm +#include "interpreter_regimm.def" + +// special +#include "interpreter_special.def" + +// TLB +#include "interpreter_tlb.def" + + diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop0.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop0.def new file mode 100644 index 000000000..c219aad81 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop0.def @@ -0,0 +1,137 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_cop0.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +DECLARE_INSTRUCTION(MFC0) +{ + switch(rfs) + { + case CP0_RANDOM_REG: + DebugMessage(state, M64MSG_ERROR, "MFC0 instruction reading un-implemented Random register"); + state->stop=1; + case CP0_COUNT_REG: + update_count(state); + default: + rrt32 = state->g_cp0_regs[rfs]; + sign_extended(rrt); + } + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MTC0) +{ + switch(rfs) + { + case CP0_INDEX_REG: + state->g_cp0_regs[CP0_INDEX_REG] = (unsigned int) rrt & 0x8000003F; + if ((state->g_cp0_regs[CP0_INDEX_REG] & 0x3F) > 31) + { + DebugMessage(state, M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31"); + state->stop=1; + } + break; + case CP0_RANDOM_REG: + break; + case CP0_ENTRYLO0_REG: + state->g_cp0_regs[CP0_ENTRYLO0_REG] = (unsigned int) rrt & 0x3FFFFFFF; + break; + case CP0_ENTRYLO1_REG: + state->g_cp0_regs[CP0_ENTRYLO1_REG] = (unsigned int) rrt & 0x3FFFFFFF; + break; + case CP0_CONTEXT_REG: + state->g_cp0_regs[CP0_CONTEXT_REG] = ((unsigned int) rrt & 0xFF800000) + | (state->g_cp0_regs[CP0_CONTEXT_REG] & 0x007FFFF0); + break; + case CP0_PAGEMASK_REG: + state->g_cp0_regs[CP0_PAGEMASK_REG] = (unsigned int) rrt & 0x01FFE000; + break; + case CP0_WIRED_REG: + state->g_cp0_regs[CP0_WIRED_REG] = (unsigned int) rrt; + state->g_cp0_regs[CP0_RANDOM_REG] = 31; + break; + case CP0_BADVADDR_REG: + break; + case CP0_COUNT_REG: + update_count(state); + state->interupt_unsafe_state = 1; + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); + state->interupt_unsafe_state = 0; + translate_event_queue(state, (unsigned int) rrt & 0xFFFFFFFF); + state->g_cp0_regs[CP0_COUNT_REG] = (unsigned int) rrt & 0xFFFFFFFF; + break; + case CP0_ENTRYHI_REG: + state->g_cp0_regs[CP0_ENTRYHI_REG] = (unsigned int) rrt & 0xFFFFE0FF; + break; + case CP0_COMPARE_REG: + update_count(state); + remove_event(state, COMPARE_INT); + add_interupt_event_count(state, COMPARE_INT, (unsigned int)rrt); + state->g_cp0_regs[CP0_COMPARE_REG] = (unsigned int) rrt; + state->g_cp0_regs[CP0_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear + break; + case CP0_STATUS_REG: + if((rrt & 0x04000000) != (state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000)) + { + shuffle_fpr_data(state, state->g_cp0_regs[CP0_STATUS_REG], (unsigned int) rrt); + set_fpr_pointers(state, (unsigned int) rrt); + } + state->g_cp0_regs[CP0_STATUS_REG] = (unsigned int) rrt; + update_count(state); + ADD_TO_PC(1); + check_interupt(state); + state->interupt_unsafe_state = 1; + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); + state->interupt_unsafe_state = 0; + ADD_TO_PC(-1); + break; + case CP0_CAUSE_REG: + if (rrt!=0) + { + DebugMessage(state, M64MSG_ERROR, "MTC0 instruction trying to write Cause register with non-0 value"); + state->stop = 1; + } + else state->g_cp0_regs[CP0_CAUSE_REG] = (unsigned int) rrt; + break; + case CP0_EPC_REG: + state->g_cp0_regs[CP0_EPC_REG] = (unsigned int) rrt; + break; + case CP0_PREVID_REG: + break; + case CP0_CONFIG_REG: + state->g_cp0_regs[CP0_CONFIG_REG] = (unsigned int) rrt; + break; + case CP0_WATCHLO_REG: + state->g_cp0_regs[CP0_WATCHLO_REG] = (unsigned int) rrt & 0xFFFFFFFF; + break; + case CP0_WATCHHI_REG: + state->g_cp0_regs[CP0_WATCHHI_REG] = (unsigned int) rrt & 0xFFFFFFFF; + break; + case CP0_TAGLO_REG: + state->g_cp0_regs[CP0_TAGLO_REG] = (unsigned int) rrt & 0x0FFFFFC0; + break; + case CP0_TAGHI_REG: + state->g_cp0_regs[CP0_TAGHI_REG] =0; + break; + default: + DebugMessage(state, M64MSG_ERROR, "Unknown MTC0 write: %d", rfs); + state->stop=1; + } + ADD_TO_PC(1); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop1.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop1.def new file mode 100644 index 000000000..43da7d43b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_cop1.def @@ -0,0 +1,708 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_cop1.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "fpu.h" + +DECLARE_JUMP(BC1F, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)==0, &state->reg[0], 0, 1) +DECLARE_JUMP(BC1T, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)!=0, &state->reg[0], 0, 1) +DECLARE_JUMP(BC1FL, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)==0, &state->reg[0], 1, 1) +DECLARE_JUMP(BC1TL, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)!=0, &state->reg[0], 1, 1) + +DECLARE_INSTRUCTION(MFC1) +{ + if (check_cop1_unusable(state)) return; + rrt32 = *((int*)state->reg_cop1_simple[rfs]); + sign_extended(rrt); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DMFC1) +{ + if (check_cop1_unusable(state)) return; + rrt = *((long long*)state->reg_cop1_double[rfs]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CFC1) +{ + if (check_cop1_unusable(state)) return; + if (rfs==31) + { + rrt32 = state->FCR31; + sign_extended(rrt); + } + if (rfs==0) + { + rrt32 = state->FCR0; + sign_extended(rrt); + } + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MTC1) +{ + if (check_cop1_unusable(state)) return; + *((int*)state->reg_cop1_simple[rfs]) = rrt32; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DMTC1) +{ + if (check_cop1_unusable(state)) return; + *((long long*)state->reg_cop1_double[rfs]) = rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CTC1) +{ + if (check_cop1_unusable(state)) return; + if (rfs==31) + state->FCR31 = rrt32; + switch((state->FCR31 & 3)) + { + case 0: + state->rounding_mode = 0x33F; // Round to nearest, or to even if equidistant + break; + case 1: + state->rounding_mode = 0xF3F; // Truncate (toward 0) + break; + case 2: + state->rounding_mode = 0xB3F; // Round up (toward +infinity) + break; + case 3: + state->rounding_mode = 0x73F; // Round down (toward -infinity) + break; + } + //if ((state->FCR31 >> 7) & 0x1F) printf("FPU Exception enabled : %x\n", + // (int)((state->FCR31 >> 7) & 0x1F)); + ADD_TO_PC(1); +} + +// COP1_D +DECLARE_INSTRUCTION(ADD_D) +{ + if (check_cop1_unusable(state)) return; + add_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SUB_D) +{ + if (check_cop1_unusable(state)) return; + sub_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MUL_D) +{ + if (check_cop1_unusable(state)) return; + mul_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DIV_D) +{ + if (check_cop1_unusable(state)) return; + if((state->FCR31 & 0x400) && *state->reg_cop1_double[cfft] == 0) + { + //state->FCR31 |= 0x8020; + /*state->FCR31 |= 0x8000; + state->Cause = 15 << 2; + exception_general(state);*/ + DebugMessage(state, M64MSG_ERROR, "DIV_D by 0"); + //return; + } + div_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SQRT_D) +{ + if (check_cop1_unusable(state)) return; + sqrt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ABS_D) +{ + if (check_cop1_unusable(state)) return; + abs_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MOV_D) +{ + if (check_cop1_unusable(state)) return; + mov_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(NEG_D) +{ + if (check_cop1_unusable(state)) return; + neg_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ROUND_L_D) +{ + if (check_cop1_unusable(state)) return; + round_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TRUNC_L_D) +{ + if (check_cop1_unusable(state)) return; + trunc_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CEIL_L_D) +{ + if (check_cop1_unusable(state)) return; + ceil_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(FLOOR_L_D) +{ + if (check_cop1_unusable(state)) return; + floor_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ROUND_W_D) +{ + if (check_cop1_unusable(state)) return; + round_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TRUNC_W_D) +{ + if (check_cop1_unusable(state)) return; + trunc_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CEIL_W_D) +{ + if (check_cop1_unusable(state)) return; + ceil_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(FLOOR_W_D) +{ + if (check_cop1_unusable(state)) return; + floor_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_S_D) +{ + if (check_cop1_unusable(state)) return; + cvt_s_d(state, state->reg_cop1_double[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_W_D) +{ + if (check_cop1_unusable(state)) return; + cvt_w_d(state, state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_L_D) +{ + if (check_cop1_unusable(state)) return; + cvt_l_d(state, state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_F_D) +{ + if (check_cop1_unusable(state)) return; + c_f_d(state); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_UN_D) +{ + if (check_cop1_unusable(state)) return; + c_un_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_EQ_D) +{ + if (check_cop1_unusable(state)) return; + c_eq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_UEQ_D) +{ + if (check_cop1_unusable(state)) return; + c_ueq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_OLT_D) +{ + if (check_cop1_unusable(state)) return; + c_olt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_ULT_D) +{ + if (check_cop1_unusable(state)) return; + c_ult_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_OLE_D) +{ + if (check_cop1_unusable(state)) return; + c_ole_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_ULE_D) +{ + if (check_cop1_unusable(state)) return; + c_ule_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_SF_D) +{ + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_sf_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGLE_D) +{ + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngle_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_SEQ_D) +{ + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_seq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGL_D) +{ + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngl_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_LT_D) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_lt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGE_D) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_nge_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_LE_D) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_le_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGT_D) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]); + ADD_TO_PC(1); +} + +// COP1_L +DECLARE_INSTRUCTION(CVT_S_L) +{ + if (check_cop1_unusable(state)) return; + cvt_s_l(state, (long long*)(state->reg_cop1_double[cffs]), state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_D_L) +{ + if (check_cop1_unusable(state)) return; + cvt_d_l(state, (long long*)(state->reg_cop1_double[cffs]), state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +// COP1_S +DECLARE_INSTRUCTION(ADD_S) +{ + if (check_cop1_unusable(state)) return; + add_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SUB_S) +{ + if (check_cop1_unusable(state)) return; + sub_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MUL_S) +{ + if (check_cop1_unusable(state)) return; + mul_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DIV_S) +{ + if (check_cop1_unusable(state)) return; + if((state->FCR31 & 0x400) && *state->reg_cop1_simple[cfft] == 0) + { + DebugMessage(state, M64MSG_ERROR, "DIV_S by 0"); + } + div_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SQRT_S) +{ + if (check_cop1_unusable(state)) return; + sqrt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ABS_S) +{ + if (check_cop1_unusable(state)) return; + abs_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MOV_S) +{ + if (check_cop1_unusable(state)) return; + mov_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(NEG_S) +{ + if (check_cop1_unusable(state)) return; + neg_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ROUND_L_S) +{ + if (check_cop1_unusable(state)) return; + round_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TRUNC_L_S) +{ + if (check_cop1_unusable(state)) return; + trunc_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CEIL_L_S) +{ + if (check_cop1_unusable(state)) return; + ceil_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(FLOOR_L_S) +{ + if (check_cop1_unusable(state)) return; + floor_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ROUND_W_S) +{ + if (check_cop1_unusable(state)) return; + round_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TRUNC_W_S) +{ + if (check_cop1_unusable(state)) return; + trunc_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CEIL_W_S) +{ + if (check_cop1_unusable(state)) return; + ceil_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(FLOOR_W_S) +{ + if (check_cop1_unusable(state)) return; + floor_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_D_S) +{ + if (check_cop1_unusable(state)) return; + cvt_d_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_W_S) +{ + if (check_cop1_unusable(state)) return; + cvt_w_s(state, state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_L_S) +{ + if (check_cop1_unusable(state)) return; + cvt_l_s(state, state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd])); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_F_S) +{ + if (check_cop1_unusable(state)) return; + c_f_s(state); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_UN_S) +{ + if (check_cop1_unusable(state)) return; + c_un_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_EQ_S) +{ + if (check_cop1_unusable(state)) return; + c_eq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_UEQ_S) +{ + if (check_cop1_unusable(state)) return; + c_ueq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_OLT_S) +{ + if (check_cop1_unusable(state)) return; + c_olt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_ULT_S) +{ + if (check_cop1_unusable(state)) return; + c_ult_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_OLE_S) +{ + if (check_cop1_unusable(state)) return; + c_ole_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_ULE_S) +{ + if (check_cop1_unusable(state)) return; + c_ule_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_SF_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_sf_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGLE_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngle_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_SEQ_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_seq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGL_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngl_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_LT_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_lt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGE_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_nge_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_LE_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_le_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(C_NGT_S) +{ + if (check_cop1_unusable(state)) return; + if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft])) + { + DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode"); + state->stop=1; + } + c_ngt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]); + ADD_TO_PC(1); +} + +// COP1_W +DECLARE_INSTRUCTION(CVT_S_W) +{ + if (check_cop1_unusable(state)) return; + cvt_s_w(state, (int*)state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(CVT_D_W) +{ + if (check_cop1_unusable(state)) return; + cvt_d_w(state, (int*)state->reg_cop1_simple[cffs], state->reg_cop1_double[cffd]); + ADD_TO_PC(1); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_r4300.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_r4300.def new file mode 100644 index 000000000..f46f02868 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_r4300.def @@ -0,0 +1,800 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_r4300.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +DECLARE_JUMP(J, (jinst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, &state->reg[0], 0, 0) +DECLARE_JUMP(JAL, (jinst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, &state->reg[31], 0, 0) +DECLARE_JUMP(BEQ, PCADDR + (iimmediate+1)*4, irs == irt, &state->reg[0], 0, 0) +DECLARE_JUMP(BNE, PCADDR + (iimmediate+1)*4, irs != irt, &state->reg[0], 0, 0) +DECLARE_JUMP(BLEZ, PCADDR + (iimmediate+1)*4, irs <= 0, &state->reg[0], 0, 0) +DECLARE_JUMP(BGTZ, PCADDR + (iimmediate+1)*4, irs > 0, &state->reg[0], 0, 0) + +DECLARE_INSTRUCTION(ADDI) +{ + irt32 = irs32 + iimmediate; + sign_extended(irt); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ADDIU) +{ + irt32 = irs32 + iimmediate; + sign_extended(irt); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLTI) +{ + if (irs < iimmediate) irt = 1; + else irt = 0; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLTIU) +{ + if ((unsigned long long)irs < (unsigned long long)((long long)iimmediate)) + irt = 1; + else irt = 0; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ANDI) +{ + irt = irs & (unsigned short)iimmediate; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ORI) +{ + irt = irs | (unsigned short)iimmediate; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(XORI) +{ + irt = irs ^ (unsigned short)iimmediate; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(LUI) +{ + irt32 = iimmediate << 16; + sign_extended(irt); + ADD_TO_PC(1); +} + +DECLARE_JUMP(BEQL, PCADDR + (iimmediate+1)*4, irs == irt, &state->reg[0], 1, 0) +DECLARE_JUMP(BNEL, PCADDR + (iimmediate+1)*4, irs != irt, &state->reg[0], 1, 0) +DECLARE_JUMP(BLEZL, PCADDR + (iimmediate+1)*4, irs <= 0, &state->reg[0], 1, 0) +DECLARE_JUMP(BGTZL, PCADDR + (iimmediate+1)*4, irs > 0, &state->reg[0], 1, 0) + +DECLARE_INSTRUCTION(DADDI) +{ + irt = irs + iimmediate; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DADDIU) +{ + irt = irs + iimmediate; + ADD_TO_PC(1); +} + +// TODOXXX refactor the following functions to remove the +// lsaddr and lsrpt locals. this may lead to a small speedup too + +DECLARE_INSTRUCTION(LDL) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 7) + { + case 0: + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_dword_in_memory(); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFF) | (word << 8); + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFF) | (word << 16); + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24); + break; + case 4: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFF) | (word << 32); + break; + case 5: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFLL) | (word << 40); + break; + case 6: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFLL) | (word << 48); + break; + case 7: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFFLL) | (word << 56); + break; + } +} + +DECLARE_INSTRUCTION(LDR) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 7) + { + case 0: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | (word >> 56); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | (word >> 48); + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | (word >> 40); + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFF00000000LL) | (word >> 32); + break; + case 4: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFF0000000000LL) | (word >> 24); + break; + case 5: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFF000000000000LL) | (word >> 16); + break; + case 6: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &word; + read_dword_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFF00000000000000LL) | (word >> 8); + break; + case 7: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = (unsigned long long *) lsrtp; + read_dword_in_memory(); + break; + } +} + +DECLARE_INSTRUCTION(LB) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_byte_in_memory(); + if (state->address) + sign_extendedb(*lsrtp); +} + +DECLARE_INSTRUCTION(LH) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_hword_in_memory(); + if (state->address) + sign_extendedh(*lsrtp); +} + +DECLARE_INSTRUCTION(LWL) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 3) + { + case 0: + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_word_in_memory(); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFF) | (word << 8); + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFF) | (word << 16); + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24); + break; + } + if(state->address) + sign_extended(*lsrtp); +} + +DECLARE_INSTRUCTION(LW) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_word_in_memory(); + if (state->address) + sign_extended(*lsrtp); +} + +DECLARE_INSTRUCTION(LBU) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_byte_in_memory(); +} + +DECLARE_INSTRUCTION(LHU) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_hword_in_memory(); +} + +DECLARE_INSTRUCTION(LWR) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 3) + { + case 0: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | ((word >> 24) & 0xFF); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | ((word >> 16) & 0xFFFF); + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &word; + read_word_in_memory(); + if(state->address) + *lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | ((word >> 8) & 0XFFFFFF); + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = (unsigned long long *) lsrtp; + read_word_in_memory(); + if(state->address) + sign_extended(*lsrtp); + } +} + +DECLARE_INSTRUCTION(LWU) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_word_in_memory(); +} + +DECLARE_INSTRUCTION(SB) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->cpu_byte = (unsigned char)(*lsrtp & 0xFF); + write_byte_in_memory(); + CHECK_MEMORY(); +} + +DECLARE_INSTRUCTION(SH) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->cpu_hword = (unsigned short)(*lsrtp & 0xFFFF); + write_hword_in_memory(); + CHECK_MEMORY(); +} + +DECLARE_INSTRUCTION(SWL) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int old_word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 3) + { + case 0: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->cpu_word = (unsigned int)*lsrtp; + write_word_in_memory(); + CHECK_MEMORY(); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &old_word; + read_word_in_memory(); + if(state->address) + { + state->cpu_word = ((unsigned int)*lsrtp >> 8) | ((unsigned int) old_word & 0xFF000000); + write_word_in_memory(); + CHECK_MEMORY(); + } + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &old_word; + read_word_in_memory(); + if(state->address) + { + state->cpu_word = ((unsigned int)*lsrtp >> 16) | ((unsigned int) old_word & 0xFFFF0000); + write_word_in_memory(); + CHECK_MEMORY(); + } + break; + case 3: + state->address = (unsigned int) lsaddr; + state->cpu_byte = (unsigned char)(*lsrtp >> 24); + write_byte_in_memory(); + CHECK_MEMORY(); + break; + } +} + +DECLARE_INSTRUCTION(SW) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->cpu_word = (unsigned int)(*lsrtp & 0xFFFFFFFF); + write_word_in_memory(); + CHECK_MEMORY(); +} + +DECLARE_INSTRUCTION(SDL) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int old_word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 7) + { + case 0: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->cpu_dword = *lsrtp; + write_dword_in_memory(); + CHECK_MEMORY(); + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 8)|(old_word & 0xFF00000000000000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 16)|(old_word & 0xFFFF000000000000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 24)|(old_word & 0xFFFFFF0000000000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 4: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 32)|(old_word & 0xFFFFFFFF00000000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 5: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 40)|(old_word & 0xFFFFFFFFFF000000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 6: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 48)|(old_word & 0xFFFFFFFFFFFF0000LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 7: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = ((unsigned long long)*lsrtp >> 56)|(old_word & 0xFFFFFFFFFFFFFF00LL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + } +} + +DECLARE_INSTRUCTION(SDR) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int old_word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 7) + { + case 0: + state->address = (unsigned int) lsaddr; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 56) | (old_word & 0x00FFFFFFFFFFFFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 48) | (old_word & 0x0000FFFFFFFFFFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 40) | (old_word & 0x000000FFFFFFFFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 32) | (old_word & 0x00000000FFFFFFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 4: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 24) | (old_word & 0x0000000000FFFFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 5: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 16) | (old_word & 0x000000000000FFFFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 6: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->rdword = &old_word; + read_dword_in_memory(); + if(state->address) + { + state->cpu_dword = (*lsrtp << 8) | (old_word & 0x00000000000000FFLL); + write_dword_in_memory(); + CHECK_MEMORY(); + } + break; + case 7: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8; + state->cpu_dword = *lsrtp; + write_dword_in_memory(); + CHECK_MEMORY(); + break; + } +} + +DECLARE_INSTRUCTION(SWR) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + unsigned long long int old_word = 0; + ADD_TO_PC(1); + switch ((lsaddr) & 3) + { + case 0: + state->address = (unsigned int) lsaddr; + state->rdword = &old_word; + read_word_in_memory(); + if(state->address) + { + state->cpu_word = ((unsigned int)*lsrtp << 24) | ((unsigned int) old_word & 0x00FFFFFF); + write_word_in_memory(); + CHECK_MEMORY(); + } + break; + case 1: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &old_word; + read_word_in_memory(); + if(state->address) + { + state->cpu_word = ((unsigned int)*lsrtp << 16) | ((unsigned int) old_word & 0x0000FFFF); + write_word_in_memory(); + CHECK_MEMORY(); + } + break; + case 2: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->rdword = &old_word; + read_word_in_memory(); + if(state->address) + { + state->cpu_word = ((unsigned int)*lsrtp << 8) | ((unsigned int) old_word & 0x000000FF); + write_word_in_memory(); + CHECK_MEMORY(); + } + break; + case 3: + state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC; + state->cpu_word = (unsigned int)*lsrtp; + write_word_in_memory(); + CHECK_MEMORY(); + break; + } +} + +DECLARE_INSTRUCTION(CACHE) +{ + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(LL) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_word_in_memory(); + if (state->address) + { + sign_extended(*lsrtp); + state->llbit = 1; + } +} + +DECLARE_INSTRUCTION(LWC1) +{ + const unsigned char lslfft = lfft; + const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]); + unsigned long long int temp; + if (check_cop1_unusable(state)) return; + ADD_TO_PC(1); + state->address = (unsigned int) lslfaddr; + state->rdword = &temp; + read_word_in_memory(); + if (state->address) + *((int*)state->reg_cop1_simple[lslfft]) = (int) *state->rdword; +} + +DECLARE_INSTRUCTION(LDC1) +{ + const unsigned char lslfft = lfft; + const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]); + if (check_cop1_unusable(state)) return; + ADD_TO_PC(1); + state->address = (unsigned int) lslfaddr; + state->rdword = (unsigned long long *)state->reg_cop1_double[lslfft]; + read_dword_in_memory(); +} + +DECLARE_INSTRUCTION(LD) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->rdword = (unsigned long long *) lsrtp; + read_dword_in_memory(); +} + +DECLARE_INSTRUCTION(SC) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + if(state->llbit) + { + state->address = (unsigned int) lsaddr; + state->cpu_word = (unsigned int)(*lsrtp & 0xFFFFFFFF); + write_word_in_memory(); + CHECK_MEMORY(); + state->llbit = 0; + *lsrtp = 1; + } + else + { + *lsrtp = 0; + } +} + +DECLARE_INSTRUCTION(SWC1) +{ + const unsigned char lslfft = lfft; + const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]); + if (check_cop1_unusable(state)) return; + ADD_TO_PC(1); + state->address = (unsigned int) lslfaddr; + state->cpu_word = *((int*)state->reg_cop1_simple[lslfft]); + write_word_in_memory(); + CHECK_MEMORY(); +} + +DECLARE_INSTRUCTION(SDC1) +{ + const unsigned char lslfft = lfft; + const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]); + if (check_cop1_unusable(state)) return; + ADD_TO_PC(1); + state->address = (unsigned int) lslfaddr; + state->cpu_dword = *((unsigned long long*)state->reg_cop1_double[lslfft]); + write_dword_in_memory(); + CHECK_MEMORY(); +} + +DECLARE_INSTRUCTION(SD) +{ + const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); + long long int *lsrtp = &irt; + ADD_TO_PC(1); + state->address = (unsigned int) lsaddr; + state->cpu_dword = *lsrtp; + write_dword_in_memory(); + CHECK_MEMORY(); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_regimm.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_regimm.def new file mode 100644 index 000000000..368ef0516 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_regimm.def @@ -0,0 +1,29 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_regimm.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +DECLARE_JUMP(BLTZ, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[0], 0, 0) +DECLARE_JUMP(BGEZ, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[0], 0, 0) +DECLARE_JUMP(BLTZL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[0], 1, 0) +DECLARE_JUMP(BGEZL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[0], 1, 0) +DECLARE_JUMP(BLTZAL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[31], 0, 0) +DECLARE_JUMP(BGEZAL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[31], 0, 0) +DECLARE_JUMP(BLTZALL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[31], 1, 0) +DECLARE_JUMP(BGEZALL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[31], 1, 0) diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_special.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_special.def new file mode 100644 index 000000000..29fc1f0a0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_special.def @@ -0,0 +1,408 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_special.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +DECLARE_INSTRUCTION(NOP) +{ + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLL) +{ + rrd32 = (unsigned int)(rrt32) << rsa; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SRL) +{ + rrd32 = (unsigned int)rrt32 >> rsa; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SRA) +{ + rrd32 = (signed int)rrt32 >> rsa; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLLV) +{ + rrd32 = (unsigned int)(rrt32) << (rrs32&0x1F); + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SRLV) +{ + rrd32 = (unsigned int)rrt32 >> (rrs32 & 0x1F); + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SRAV) +{ + rrd32 = (signed int)rrt32 >> (rrs32 & 0x1F); + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_JUMP(JR, irs32, 1, &state->reg[0], 0, 0) +DECLARE_JUMP(JALR, irs32, 1, &rrd, 0, 0) + +DECLARE_INSTRUCTION(SYSCALL) +{ + state->g_cp0_regs[CP0_CAUSE_REG] = 8 << 2; + exception_general(state); +} + +DECLARE_INSTRUCTION(SYNC) +{ + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MFHI) +{ + rrd = state->hi; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MTHI) +{ + state->hi = rrs; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MFLO) +{ + rrd = state->lo; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MTLO) +{ + state->lo = rrs; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSLLV) +{ + rrd = rrt << (rrs32&0x3F); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRLV) +{ + rrd = (unsigned long long)rrt >> (rrs32 & 0x3F); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRAV) +{ + rrd = (long long)rrt >> (rrs32 & 0x3F); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MULT) +{ + long long int temp; + temp = rrs * rrt; + state->hi = temp >> 32; + state->lo = temp; + sign_extended(state->lo); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(MULTU) +{ + unsigned long long int temp; + temp = (unsigned int)rrs * (unsigned long long)((unsigned int)rrt); + state->hi = (long long)temp >> 32; + state->lo = temp; + sign_extended(state->lo); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DIV) +{ + if (rrt32) + { + state->lo = rrs32 / rrt32; + state->hi = rrs32 % rrt32; + sign_extended(state->lo); + sign_extended(state->hi); + } + else DebugMessage(state, M64MSG_ERROR, "DIV: divide by 0"); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DIVU) +{ + if (rrt32) + { + state->lo = (unsigned int)rrs32 / (unsigned int)rrt32; + state->hi = (unsigned int)rrs32 % (unsigned int)rrt32; + sign_extended(state->lo); + sign_extended(state->hi); + } + else DebugMessage(state, M64MSG_ERROR, "DIVU: divide by 0"); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DMULT) +{ + unsigned long long int op1, op2, op3, op4; + unsigned long long int result1, result2, result3, result4; + unsigned long long int temp1, temp2, temp3, temp4; + int sign = 0; + + if (rrs < 0) + { + op2 = -rrs; + sign = 1 - sign; + } + else op2 = rrs; + if (rrt < 0) + { + op4 = -rrt; + sign = 1 - sign; + } + else op4 = rrt; + + op1 = op2 & 0xFFFFFFFF; + op2 = (op2 >> 32) & 0xFFFFFFFF; + op3 = op4 & 0xFFFFFFFF; + op4 = (op4 >> 32) & 0xFFFFFFFF; + + temp1 = op1 * op3; + temp2 = (temp1 >> 32) + op1 * op4; + temp3 = op2 * op3; + temp4 = (temp3 >> 32) + op2 * op4; + + result1 = temp1 & 0xFFFFFFFF; + result2 = temp2 + (temp3 & 0xFFFFFFFF); + result3 = (result2 >> 32) + temp4; + result4 = (result3 >> 32); + + state->lo = result1 | (result2 << 32); + state->hi = (result3 & 0xFFFFFFFF) | (result4 << 32); + if (sign) + { + state->hi = ~state->hi; + if (!state->lo) state->hi++; + else state->lo = ~state->lo + 1; + } + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DMULTU) +{ + unsigned long long int op1, op2, op3, op4; + unsigned long long int result1, result2, result3, result4; + unsigned long long int temp1, temp2, temp3, temp4; + + op1 = rrs & 0xFFFFFFFF; + op2 = (rrs >> 32) & 0xFFFFFFFF; + op3 = rrt & 0xFFFFFFFF; + op4 = (rrt >> 32) & 0xFFFFFFFF; + + temp1 = op1 * op3; + temp2 = (temp1 >> 32) + op1 * op4; + temp3 = op2 * op3; + temp4 = (temp3 >> 32) + op2 * op4; + + result1 = temp1 & 0xFFFFFFFF; + result2 = temp2 + (temp3 & 0xFFFFFFFF); + result3 = (result2 >> 32) + temp4; + result4 = (result3 >> 32); + + state->lo = result1 | (result2 << 32); + state->hi = (result3 & 0xFFFFFFFF) | (result4 << 32); + + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DDIV) +{ + if (rrt) + { + state->lo = (long long int)rrs / (long long int)rrt; + state->hi = (long long int)rrs % (long long int)rrt; + } + else DebugMessage(state, M64MSG_ERROR, "DDIV: divide by 0"); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DDIVU) +{ + if (rrt) + { + state->lo = (unsigned long long int)rrs / (unsigned long long int)rrt; + state->hi = (unsigned long long int)rrs % (unsigned long long int)rrt; + } + else DebugMessage(state, M64MSG_ERROR, "DDIVU: divide by 0"); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ADD) +{ + rrd32 = rrs32 + rrt32; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ADDU) +{ + rrd32 = rrs32 + rrt32; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SUB) +{ + rrd32 = rrs32 - rrt32; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SUBU) +{ + rrd32 = rrs32 - rrt32; + sign_extended(rrd); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(AND) +{ + rrd = rrs & rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(OR) +{ + rrd = rrs | rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(XOR) +{ + rrd = rrs ^ rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(NOR) +{ + rrd = ~(rrs | rrt); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLT) +{ + if (rrs < rrt) rrd = 1; + else rrd = 0; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(SLTU) +{ + if ((unsigned long long)rrs < (unsigned long long)rrt) + rrd = 1; + else rrd = 0; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DADD) +{ + rrd = rrs + rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DADDU) +{ + rrd = rrs + rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSUB) +{ + rrd = rrs - rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSUBU) +{ + rrd = rrs - rrt; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TEQ) +{ + if (rrs == rrt) + { + DebugMessage(state, M64MSG_ERROR, "trap exception in TEQ"); + state->stop=1; + } + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSLL) +{ + rrd = rrt << rsa; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRL) +{ + rrd = (unsigned long long)rrt >> rsa; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRA) +{ + rrd = rrt >> rsa; + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSLL32) +{ + rrd = rrt << (32+rsa); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRL32) +{ + rrd = (unsigned long long int)rrt >> (32+rsa); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(DSRA32) +{ + rrd = (signed long long int)rrt >> (32+rsa); + ADD_TO_PC(1); +} + +/* Idle loop hack from 64th Note */ +DECLARE_INSTRUCTION(BREAK) +{ + state->g_cp0_regs[CP0_COUNT_REG] = state->next_interupt; + ADD_TO_PC(1); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/interpreter_tlb.def b/Frameworks/lazyusf/lazyusf/r4300/interpreter_tlb.def new file mode 100644 index 000000000..b67eb85bc --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interpreter_tlb.def @@ -0,0 +1,250 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpreter_tlb.def * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include // For adler32() + +DECLARE_INSTRUCTION(TLBR) +{ + int index; + index = state->g_cp0_regs[CP0_INDEX_REG] & 0x1F; + state->g_cp0_regs[CP0_PAGEMASK_REG] = state->tlb_e[index].mask << 13; + state->g_cp0_regs[CP0_ENTRYHI_REG] = ((state->tlb_e[index].vpn2 << 13) | state->tlb_e[index].asid); + state->g_cp0_regs[CP0_ENTRYLO0_REG] = (state->tlb_e[index].pfn_even << 6) | (state->tlb_e[index].c_even << 3) + | (state->tlb_e[index].d_even << 2) | (state->tlb_e[index].v_even << 1) + | state->tlb_e[index].g; + state->g_cp0_regs[CP0_ENTRYLO1_REG] = (state->tlb_e[index].pfn_odd << 6) | (state->tlb_e[index].c_odd << 3) + | (state->tlb_e[index].d_odd << 2) | (state->tlb_e[index].v_odd << 1) + | state->tlb_e[index].g; + ADD_TO_PC(1); +} + +static void TLBWrite(usf_state_t * state, unsigned int idx) +{ + if (state->r4300emu != CORE_PURE_INTERPRETER) + { + unsigned int i; + if (state->tlb_e[idx].v_even) + { + for (i=state->tlb_e[idx].start_even>>12; i<=state->tlb_e[idx].end_even>>12; i++) + { + if(!state->invalid_code[i] &&(state->invalid_code[state->tlb_LUT_r[i]>>12] || + state->invalid_code[(state->tlb_LUT_r[i]>>12)+0x20000])) + state->invalid_code[i] = 1; + if (!state->invalid_code[i]) + { + /*int j; + md5_state_t state; + md5_byte_t digest[16]; + md5_init(&state); + md5_append(&state, + (const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], + 0x1000); + md5_finish(&state, digest); + for (j=0; j<16; j++) state->blocks[i]->md5[j] = digest[j];*/ + + state->blocks[i]->adler32 = adler32(0, (const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], 0x1000); + + state->invalid_code[i] = 1; + } + else if (state->blocks[i]) + { + /*int j; + for (j=0; j<16; j++) state->blocks[i]->md5[j] = 0;*/ + state->blocks[i]->adler32 = 0; + } + } + } + if (state->tlb_e[idx].v_odd) + { + for (i=state->tlb_e[idx].start_odd>>12; i<=state->tlb_e[idx].end_odd>>12; i++) + { + if(!state->invalid_code[i] &&(state->invalid_code[state->tlb_LUT_r[i]>>12] || + state->invalid_code[(state->tlb_LUT_r[i]>>12)+0x20000])) + state->invalid_code[i] = 1; + if (!state->invalid_code[i]) + { + /*int j; + md5_state_t state; + md5_byte_t digest[16]; + md5_init(&state); + md5_append(&state, + (const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], + 0x1000); + md5_finish(&state, digest); + for (j=0; j<16; j++) state->blocks[i]->md5[j] = digest[j];*/ + + state->blocks[i]->adler32 = adler32(0, (const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], 0x1000); + + state->invalid_code[i] = 1; + } + else if (state->blocks[i]) + { + /*int j; + for (j=0; j<16; j++) state->blocks[i]->md5[j] = 0;*/ + state->blocks[i]->adler32 = 0; + } + } + } + } + + tlb_unmap(state, &state->tlb_e[idx]); + + state->tlb_e[idx].g = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & state->g_cp0_regs[CP0_ENTRYLO1_REG] & 1); + state->tlb_e[idx].pfn_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x3FFFFFC0) >> 6; + state->tlb_e[idx].pfn_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x3FFFFFC0) >> 6; + state->tlb_e[idx].c_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x38) >> 3; + state->tlb_e[idx].c_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x38) >> 3; + state->tlb_e[idx].d_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x4) >> 2; + state->tlb_e[idx].d_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x4) >> 2; + state->tlb_e[idx].v_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x2) >> 1; + state->tlb_e[idx].v_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x2) >> 1; + state->tlb_e[idx].asid = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFF); + state->tlb_e[idx].vpn2 = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFFFFE000) >> 13; + //state->tlb_e[idx].r = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xC000000000000000LL) >> 62; + state->tlb_e[idx].mask = (state->g_cp0_regs[CP0_PAGEMASK_REG] & 0x1FFE000) >> 13; + + state->tlb_e[idx].start_even = state->tlb_e[idx].vpn2 << 13; + state->tlb_e[idx].end_even = state->tlb_e[idx].start_even+ + (state->tlb_e[idx].mask << 12) + 0xFFF; + state->tlb_e[idx].phys_even = state->tlb_e[idx].pfn_even << 12; + + + state->tlb_e[idx].start_odd = state->tlb_e[idx].end_even+1; + state->tlb_e[idx].end_odd = state->tlb_e[idx].start_odd+ + (state->tlb_e[idx].mask << 12) + 0xFFF; + state->tlb_e[idx].phys_odd = state->tlb_e[idx].pfn_odd << 12; + + tlb_map(state, &state->tlb_e[idx]); + + if (state->r4300emu != CORE_PURE_INTERPRETER) + { + unsigned int i; + if (state->tlb_e[idx].v_even) + { + for (i=state->tlb_e[idx].start_even>>12; i<=state->tlb_e[idx].end_even>>12; i++) + { + /*if (state->blocks[i] && (state->blocks[i]->md5[0] || state->blocks[i]->md5[1] || + state->blocks[i]->md5[2] || state->blocks[i]->md5[3])) + { + int j; + int equal = 1; + md5_state_t state; + md5_byte_t digest[16]; + md5_init(&state); + md5_append(&state, + (const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], + 0x1000); + md5_finish(&state, digest); + for (j=0; j<16; j++) + if (digest[j] != state->blocks[i]->md5[j]) + equal = 0; + if (equal) state->invalid_code[i] = 0; + }*/ + if(state->blocks[i] && state->blocks[i]->adler32) + { + if(state->blocks[i]->adler32 == adler32(0,(const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],0x1000)) + state->invalid_code[i] = 0; + } + } + } + + if (state->tlb_e[idx].v_odd) + { + for (i=state->tlb_e[idx].start_odd>>12; i<=state->tlb_e[idx].end_odd>>12; i++) + { + /*if (state->blocks[i] && (state->blocks[i]->md5[0] || state->blocks[i]->md5[1] || + state->blocks[i]->md5[2] || state->blocks[i]->md5[3])) + { + int j; + int equal = 1; + md5_state_t state; + md5_byte_t digest[16]; + md5_init(&state); + md5_append(&state, + (const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], + 0x1000); + md5_finish(&state, digest); + for (j=0; j<16; j++) + if (digest[j] != state->blocks[i]->md5[j]) + equal = 0; + if (equal) state->invalid_code[i] = 0; + }*/ + if(state->blocks[i] && state->blocks[i]->adler32) + { + if(state->blocks[i]->adler32 == adler32(0,(const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],0x1000)) + state->invalid_code[i] = 0; + } + } + } + } +} + +DECLARE_INSTRUCTION(TLBWI) +{ + TLBWrite(state, state->g_cp0_regs[CP0_INDEX_REG]&0x3F); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TLBWR) +{ + update_count(state); + state->g_cp0_regs[CP0_RANDOM_REG] = (state->g_cp0_regs[CP0_COUNT_REG]/2 % (32 - state->g_cp0_regs[CP0_WIRED_REG])) + + state->g_cp0_regs[CP0_WIRED_REG]; + TLBWrite(state, state->g_cp0_regs[CP0_RANDOM_REG]); + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(TLBP) +{ + int i; + state->g_cp0_regs[CP0_INDEX_REG] |= 0x80000000; + for (i=0; i<32; i++) + { + if (((state->tlb_e[i].vpn2 & (~state->tlb_e[i].mask)) == + (((state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFFFFE000) >> 13) & (~state->tlb_e[i].mask))) && + ((state->tlb_e[i].g) || + (state->tlb_e[i].asid == (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFF)))) + { + state->g_cp0_regs[CP0_INDEX_REG] = i; + break; + } + } + ADD_TO_PC(1); +} + +DECLARE_INSTRUCTION(ERET) +{ + update_count(state); + if (state->g_cp0_regs[CP0_STATUS_REG] & 0x4) + { + DebugMessage(state, M64MSG_ERROR, "error in ERET"); + state->stop=1; + } + else + { + state->g_cp0_regs[CP0_STATUS_REG] &= ~0x2; + generic_jump_to(state, state->g_cp0_regs[CP0_EPC_REG]); + } + state->llbit = 0; + check_interupt(state); + state->last_addr = PCADDR; + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/interupt.c b/Frameworks/lazyusf/lazyusf/r4300/interupt.c new file mode 100644 index 000000000..95609d3e0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interupt.c @@ -0,0 +1,601 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interupt.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define M64P_CORE_PROTOTYPES 1 + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "interupt.h" +#include "cached_interp.h" +#include "cp0.h" +#include "exception.h" +#include "new_dynarec/new_dynarec.h" +#include "r4300.h" +#include "r4300_core.h" +#include "reset.h" + +#include "ai/ai_controller.h" +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "main/main.h" +#include "main/savestates.h" +#include "pi/pi_controller.h" +#include "rdp/rdp_core.h" +#include "rsp/rsp_core.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + + +#include + +/*************************************************************************** + * Pool of Single Linked List Nodes + **************************************************************************/ +#ifndef INTERUPT_STRUCTS +#define INTERUPT_STRUCTS +#define POOL_CAPACITY 16 + +struct interrupt_event +{ + int type; + unsigned int count; +}; + + +struct node +{ + struct interrupt_event data; + struct node *next; +}; + +struct pool +{ + struct node nodes[POOL_CAPACITY]; + struct node* stack[POOL_CAPACITY]; + size_t index; +}; + + +struct interrupt_queue +{ + struct pool pool; + struct node* first; +}; +#endif + +static struct node* alloc_node(struct pool* p); +static void free_node(struct pool* p, struct node* node); +static void clear_pool(struct pool* p); + + +/* node allocation/deallocation on a given pool */ +static struct node* alloc_node(struct pool* p) +{ + /* return NULL if pool is too small */ + if (p->index >= POOL_CAPACITY) + return NULL; + + return p->stack[p->index++]; +} + +static void free_node(struct pool* p, struct node* node) +{ + if (p->index == 0 || node == NULL) + return; + + p->stack[--p->index] = node; +} + +/* release all nodes */ +static void clear_pool(struct pool* p) +{ + size_t i; + + for(i = 0; i < POOL_CAPACITY; ++i) + p->stack[i] = &p->nodes[i]; + + p->index = 0; +} + +/*************************************************************************** + * Interrupt Queue + **************************************************************************/ + + +static void clear_queue(usf_state_t * state) +{ + state->q.first = NULL; + clear_pool(&state->q.pool); +} + + +static int before_event(usf_state_t * state, unsigned int evt1, unsigned int evt2, int type2) +{ + if(evt1 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000) + { + if(evt2 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000) + { + if((evt1 - state->g_cp0_regs[CP0_COUNT_REG]) < (evt2 - state->g_cp0_regs[CP0_COUNT_REG])) return 1; + else return 0; + } + else + { + if((state->g_cp0_regs[CP0_COUNT_REG] - evt2) < 0x10000000) + { + switch(type2) + { + case SPECIAL_INT: + if(state->SPECIAL_done) return 1; + else return 0; + break; + default: + return 0; + } + } + else return 1; + } + } + else return 0; +} + +void add_interupt_event(usf_state_t * state, int type, unsigned int delay) +{ + add_interupt_event_count(state, type, state->g_cp0_regs[CP0_COUNT_REG] + delay); +} + +void add_interupt_event_count(usf_state_t * state, int type, unsigned int count) +{ + struct node* event; + struct node* e; + int special; + + special = (type == SPECIAL_INT); + + if(state->g_cp0_regs[CP0_COUNT_REG] > 0x80000000) state->SPECIAL_done = 0; + + if (get_event(state, type)) { + DebugMessage(state, M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type); + /* FIXME: hack-fix for freezing in Perfect Dark + * http://code.google.com/p/mupen64plus/issues/detail?id=553 + * https://github.com/mupen64plus-ae/mupen64plus-ae/commit/802d8f81d46705d64694d7a34010dc5f35787c7d + */ + return; + } + + event = alloc_node(&state->q.pool); + if (event == NULL) + { + DebugMessage(state, M64MSG_ERROR, "Failed to allocate node for new interrupt event"); + return; + } + + event->data.count = count; + event->data.type = type; + + if (state->q.first == NULL) + { + state->q.first = event; + event->next = NULL; + state->next_interupt = state->q.first->data.count; + } + else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type) && !special) + { + event->next = state->q.first; + state->q.first = event; + state->next_interupt = state->q.first->data.count; + } + else + { + for(e = state->q.first; + e->next != NULL && + (!before_event(state, count, e->next->data.count, e->next->data.type) || special); + e = e->next); + + if (e->next == NULL) + { + e->next = event; + event->next = NULL; + } + else + { + if (!special) + for(; e->next != NULL && e->next->data.count == count; e = e->next); + + event->next = e->next; + e->next = event; + } + } +} + +static void remove_interupt_event(usf_state_t * state) +{ + struct node* e; + + e = state->q.first; + state->q.first = e->next; + free_node(&state->q.pool, e); + + state->next_interupt = (state->q.first != NULL + && (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG] + || (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000)) + ? state->q.first->data.count + : 0; +} + +unsigned int get_event(usf_state_t * state, int type) +{ + struct node* e = state->q.first; + + if (e == NULL) + return 0; + + if (e->data.type == type) + return e->data.count; + + for(; e->next != NULL && e->next->data.type != type; e = e->next); + + return (e->next != NULL) + ? e->next->data.count + : 0; +} + +int get_next_event_type(usf_state_t * state) +{ + return (state->q.first == NULL) + ? 0 + : state->q.first->data.type; +} + +void remove_event(usf_state_t * state, int type) +{ + struct node* to_del; + struct node* e = state->q.first; + + if (e == NULL) + return; + + if (e->data.type == type) + { + state->q.first = e->next; + free_node(&state->q.pool, e); + } + else + { + for(; e->next != NULL && e->next->data.type != type; e = e->next); + + if (e->next != NULL) + { + to_del = e->next; + e->next = to_del->next; + free_node(&state->q.pool, to_del); + } + } +} + +void translate_event_queue(usf_state_t * state, unsigned int base) +{ + struct node* e; + + remove_event(state, COMPARE_INT); + remove_event(state, SPECIAL_INT); + + for(e = state->q.first; e != NULL; e = e->next) + { + e->data.count = (e->data.count - state->g_cp0_regs[CP0_COUNT_REG]) + base; + } + add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]); + add_interupt_event_count(state, SPECIAL_INT, 0); + + r4300_reset_checkpoint(state, base); +} + +int save_eventqueue_infos(usf_state_t * state, char *buf) +{ + int len; + struct node* e; + + len = 0; + + for(e = state->q.first; e != NULL; e = e->next) + { + memcpy(buf + len , &e->data.type , 4); + memcpy(buf + len + 4, &e->data.count, 4); + len += 8; + } + + *((unsigned int*)&buf[len]) = 0xFFFFFFFF; + return len+4; +} + +void load_eventqueue_infos(usf_state_t * state, char *buf) +{ + int len = 0; + clear_queue(state); + while (*((unsigned int*)&buf[len]) != 0xFFFFFFFF) + { + int type = *((unsigned int*)&buf[len]); + unsigned int count = *((unsigned int*)&buf[len+4]); + add_interupt_event_count(state, type, count); + len += 8; + } +} + +void init_interupt(usf_state_t * state) +{ + state->SPECIAL_done = 1; + + state->g_vi.delay = state->g_vi.next_vi = 5000; + + clear_queue(state); + add_interupt_event_count(state, VI_INT, state->g_vi.next_vi); + add_interupt_event_count(state, SPECIAL_INT, 0); +} + +void check_interupt(usf_state_t * state) +{ + struct node* event; + + state->g_r4300.mi.regs[MI_INTR_REG] &= ~MI_INTR_AI; + state->g_r4300.mi.regs[MI_INTR_REG] |= state->g_r4300.mi.AudioIntrReg & MI_INTR_AI; + +#ifdef DEBUG_INFO + if (state->g_r4300.mi.regs[MI_INTR_REG]) + fprintf(state->debug_log, "Interrupt %d - ", state->g_r4300.mi.regs[MI_INTR_REG]); +#endif + if (state->g_r4300.mi.regs[MI_INTR_REG] & state->g_r4300.mi.regs[MI_INTR_MASK_REG]) + { +#ifdef DEBUG_INFO + fprintf(state->debug_log, "triggered\n"); +#endif + state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | 0x400) & 0xFFFFFF83; + } + else + { +#ifdef DEBUG_INFO + if (state->g_r4300.mi.regs[MI_INTR_REG]) + fprintf(state->debug_log, "masked\n"); +#endif + state->g_cp0_regs[CP0_CAUSE_REG] &= ~0x400; + } + if ((state->g_cp0_regs[CP0_STATUS_REG] & 7) != 1) return; + if (state->g_cp0_regs[CP0_STATUS_REG] & state->g_cp0_regs[CP0_CAUSE_REG] & 0xFF00) + { + event = alloc_node(&state->q.pool); + + if (event == NULL) + { + DebugMessage(state, M64MSG_ERROR, "Failed to allocate node for new interrupt event"); + return; + } + + event->data.count = state->next_interupt = state->g_cp0_regs[CP0_COUNT_REG]; + event->data.type = CHECK_INT; + + if (state->q.first == NULL) + { + state->q.first = event; + event->next = NULL; + } + else + { + event->next = state->q.first; + state->q.first = event; + } + } +} + +static void wrapped_exception_general(usf_state_t * state) +{ +#ifdef NEW_DYNAREC + if (r4300emu == CORE_DYNAREC) { + state->g_cp0_regs[CP0_EPC_REG] = pcaddr; + state->pcaddr = 0x80000180; + state->g_cp0_regs[CP0_STATUS_REG] |= 2; + state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF; + state->pending_exception=1; + } else { + exception_general(state); + } +#else + exception_general(state); +#endif +} + +void raise_maskable_interrupt(usf_state_t * state, uint32_t cause) +{ + state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | cause) & 0xffffff83; + + if (!(state->g_cp0_regs[CP0_STATUS_REG] & state->g_cp0_regs[CP0_CAUSE_REG] & 0xff00)) + return; + + if ((state->g_cp0_regs[CP0_STATUS_REG] & 7) != 1) + return; + + wrapped_exception_general(state); +} + +static void special_int_handler(usf_state_t * state) +{ + if (state->g_cp0_regs[CP0_COUNT_REG] > 0x10000000) + return; + + state->SPECIAL_done = 1; + remove_interupt_event(state); + add_interupt_event_count(state, SPECIAL_INT, 0); +} + +static void compare_int_handler(usf_state_t * state) +{ + remove_interupt_event(state); + state->g_cp0_regs[CP0_COUNT_REG]+=state->count_per_op; + add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]); + state->g_cp0_regs[CP0_COUNT_REG]-=state->count_per_op; + + if (state->enablecompare) + raise_maskable_interrupt(state, 0x8000); +} + +static void hw2_int_handler(usf_state_t * state) +{ + // Hardware Interrupt 2 -- remove interrupt event from queue + remove_interupt_event(state); + + state->g_cp0_regs[CP0_STATUS_REG] = (state->g_cp0_regs[CP0_STATUS_REG] & ~0x00380000) | 0x1000; + state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | 0x1000) & 0xffffff83; + + wrapped_exception_general(state); +} + +static void nmi_int_handler(usf_state_t * state) +{ + // Non Maskable Interrupt -- remove interrupt event from queue + remove_interupt_event(state); + // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR + state->g_cp0_regs[CP0_STATUS_REG] = (state->g_cp0_regs[CP0_STATUS_REG] & ~0x00380000) | 0x00500004; + state->g_cp0_regs[CP0_CAUSE_REG] = 0x00000000; + // simulate the soft reset code which would run from the PIF ROM + r4300_reset_soft(state); + // clear all interrupts, reset interrupt counters back to 0 + state->g_cp0_regs[CP0_COUNT_REG] = 0; + state->g_gs_vi_counter = 0; + init_interupt(state); + // clear the audio status register so that subsequent write_ai() calls will work properly + state->g_ai.regs[AI_STATUS_REG] = 0; + // set ErrorEPC with the last instruction address + state->g_cp0_regs[CP0_ERROREPC_REG] = state->PC->addr; + // reset the r4300 internal state + if (state->r4300emu != CORE_PURE_INTERPRETER) + { + // clear all the compiled instruction blocks and re-initialize + free_blocks(state); + init_blocks(state); + } + // adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags + if(state->delay_slot==1 || state->delay_slot==3) + { + state->g_cp0_regs[CP0_ERROREPC_REG]-=4; + } + state->delay_slot = 0; + state->dyna_interp = 0; + // set next instruction address to reset vector + state->last_addr = 0xa4000040; + generic_jump_to(state, 0xa4000040); +} + + +void osal_fastcall gen_interupt(usf_state_t * state) +{ + r4300_checkpoint(state); + + if (state->stop == 1) + { + state->g_gs_vi_counter = 0; // debug + dyna_stop(state); + } + + if (!state->interupt_unsafe_state) + { + if (state->reset_hard_job) + { + reset_hard(state); + state->reset_hard_job = 0; + return; + } + } + + if (state->skip_jump) + { + unsigned int dest = state->skip_jump; + state->skip_jump = 0; + + state->next_interupt = (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG] + || (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000) + ? state->q.first->data.count + : 0; + + state->last_addr = dest; + generic_jump_to(state, dest); + return; + } + + switch(state->q.first->data.type) + { + case SPECIAL_INT: + special_int_handler(state); + break; + + case VI_INT: + remove_interupt_event(state); + vi_vertical_interrupt_event(&state->g_vi); + break; + + case COMPARE_INT: + compare_int_handler(state); + break; + + case CHECK_INT: + remove_interupt_event(state); + wrapped_exception_general(state); + break; + + case SI_INT: + remove_interupt_event(state); + si_end_of_dma_event(&state->g_si); + break; + + case PI_INT: + remove_interupt_event(state); + pi_end_of_dma_event(&state->g_pi); + break; + + case AI_INT: + remove_interupt_event(state); + ai_end_of_dma_event(&state->g_ai); + break; + + case SP_INT: + remove_interupt_event(state); + rsp_interrupt_event(&state->g_sp); + break; + + case DP_INT: + remove_interupt_event(state); + rdp_interrupt_event(&state->g_dp); + break; + + case HW2_INT: + hw2_int_handler(state); + break; + + case NMI_INT: + nmi_int_handler(state); + break; + + default: + DebugMessage(state, M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", state->q.first->data.type); + remove_interupt_event(state); + wrapped_exception_general(state); + break; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/interupt.h b/Frameworks/lazyusf/lazyusf/r4300/interupt.h new file mode 100644 index 000000000..0b67d825a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/interupt.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interupt.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_INTERUPT_H +#define M64P_R4300_INTERUPT_H + +#include + +#include "usf/usf.h" + +void init_interupt(usf_state_t *); + +// set to avoid savestates/reset if state may be inconsistent +// (e.g. in the middle of an instruction) +void raise_maskable_interrupt(usf_state_t *, uint32_t cause); + +void osal_fastcall gen_interupt(usf_state_t *); +void check_interupt(usf_state_t *); + +void translate_event_queue(usf_state_t *, unsigned int base); +void remove_event(usf_state_t *, int type); +void add_interupt_event_count(usf_state_t *, int type, unsigned int count); +void add_interupt_event(usf_state_t *, int type, unsigned int delay); +unsigned int get_event(usf_state_t *, int type); +int get_next_event_type(usf_state_t *); + +int save_eventqueue_infos(usf_state_t *, char *buf); +void load_eventqueue_infos(usf_state_t *, char *buf); + +#define VI_INT 0x001 +#define COMPARE_INT 0x002 +#define CHECK_INT 0x004 +#define SI_INT 0x008 +#define PI_INT 0x010 +#define SPECIAL_INT 0x020 +#define AI_INT 0x040 +#define SP_INT 0x080 +#define DP_INT 0x100 +#define HW2_INT 0x200 +#define NMI_INT 0x400 + +#endif /* M64P_R4300_INTERUPT_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/macros.h b/Frameworks/lazyusf/lazyusf/r4300/macros.h new file mode 100644 index 000000000..85ae806ca --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/macros.h @@ -0,0 +1,63 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - macros.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_MACROS_H +#define M64P_R4300_MACROS_H + +#define sign_extended(a) a = (long long)((int)a) +#define sign_extendedb(a) a = (long long)((signed char)a) +#define sign_extendedh(a) a = (long long)((short)a) + +#define rrt *state->PC->f.r.rt +#define rrd *state->PC->f.r.rd +#define rfs state->PC->f.r.nrd +#define rrs *state->PC->f.r.rs +#define rsa state->PC->f.r.sa +#define irt *state->PC->f.i.rt +#define ioffset state->PC->f.i.immediate +#define iimmediate state->PC->f.i.immediate +#define irs *state->PC->f.i.rs +#define ibase *state->PC->f.i.rs +#define jinst_index state->PC->f.j.inst_index +#define lfbase state->PC->f.lf.base +#define lfft state->PC->f.lf.ft +#define lfoffset state->PC->f.lf.offset +#define cfft state->PC->f.cf.ft +#define cffs state->PC->f.cf.fs +#define cffd state->PC->f.cf.fd + +// 32 bits macros +#ifndef M64P_BIG_ENDIAN +#define rrt32 *((int*)state->PC->f.r.rt) +#define rrd32 *((int*)state->PC->f.r.rd) +#define rrs32 *((int*)state->PC->f.r.rs) +#define irs32 *((int*)state->PC->f.i.rs) +#define irt32 *((int*)state->PC->f.i.rt) +#else +#define rrt32 *((int*)state->PC->f.r.rt+1) +#define rrd32 *((int*)state->PC->f.r.rd+1) +#define rrs32 *((int*)state->PC->f.r.rs+1) +#define irs32 *((int*)state->PC->f.i.rs+1) +#define irt32 *((int*)state->PC->f.i.rt+1) +#endif + +#endif /* M64P_R4300_MACROS_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/mi_controller.c b/Frameworks/lazyusf/lazyusf/r4300/mi_controller.c new file mode 100644 index 000000000..bc8f54855 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/mi_controller.c @@ -0,0 +1,136 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - mi_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "mi_controller.h" +#include "r4300.h" +#include "r4300_core.h" +#include "cp0.h" +#include "interupt.h" + +#include + +static int update_mi_init_mode(uint32_t* mi_init_mode, uint32_t w) +{ + int clear_dp = 0; + + /* set init_length */ + *mi_init_mode &= ~0x7f; + *mi_init_mode |= w & 0x7f; + /* clear / set init_mode */ + if (w & 0x80) *mi_init_mode &= ~0x80; + if (w & 0x100) *mi_init_mode |= 0x80; + /* clear / set ebus test_mode */ + if (w & 0x200) *mi_init_mode &= ~0x100; + if (w & 0x400) *mi_init_mode |= 0x100; + /* clear DP interrupt */ + if (w & 0x800) clear_dp = 1; + /* clear / set RDRAM reg_mode */ + if (w & 0x1000) *mi_init_mode &= ~0x200; + if (w & 0x2000) *mi_init_mode |= 0x200; + + return clear_dp; +} + +static void update_mi_intr_mask(uint32_t* mi_intr_mask, uint32_t w) +{ + if (w & 0x1) *mi_intr_mask &= ~0x1; // clear SP mask + if (w & 0x2) *mi_intr_mask |= 0x1; // set SP mask + if (w & 0x4) *mi_intr_mask &= ~0x2; // clear SI mask + if (w & 0x8) *mi_intr_mask |= 0x2; // set SI mask + if (w & 0x10) *mi_intr_mask &= ~0x4; // clear AI mask + if (w & 0x20) *mi_intr_mask |= 0x4; // set AI mask + if (w & 0x40) *mi_intr_mask &= ~0x8; // clear VI mask + if (w & 0x80) *mi_intr_mask |= 0x8; // set VI mask + if (w & 0x100) *mi_intr_mask &= ~0x10; // clear PI mask + if (w & 0x200) *mi_intr_mask |= 0x10; // set PI mask + if (w & 0x400) *mi_intr_mask &= ~0x20; // clear DP mask + if (w & 0x800) *mi_intr_mask |= 0x20; // set DP mask +} + +void init_mi(struct mi_controller* mi) +{ + memset(mi->regs, 0, MI_REGS_COUNT*sizeof(uint32_t)); + mi->regs[MI_VERSION_REG] = 0x02020102; + mi->AudioIntrReg = 0; +} + + +int read_mi_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct r4300_core* r4300 = (struct r4300_core*)opaque; + uint32_t reg = mi_reg(address); + + *value = r4300->mi.regs[reg]; + + return 0; +} + +int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct r4300_core* r4300 = (struct r4300_core*)opaque; + uint32_t reg = mi_reg(address); + + switch(reg) + { + case MI_INIT_MODE_REG: + if (update_mi_init_mode(&r4300->mi.regs[MI_INIT_MODE_REG], value & mask) != 0) + { + clear_rcp_interrupt(r4300, MI_INTR_DP); + } + break; + case MI_INTR_MASK_REG: + update_mi_intr_mask(&r4300->mi.regs[MI_INTR_MASK_REG], value & mask); + + check_interupt(r4300->state); + update_count(r4300->state); + if (r4300->state->next_interupt <= r4300->state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(r4300->state); + break; + } + + return 0; +} + +/* interrupt execution is immediate (if not masked) */ +void raise_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr) +{ + r4300->mi.regs[MI_INTR_REG] |= mi_intr; + + if (r4300->mi.regs[MI_INTR_REG] & r4300->mi.regs[MI_INTR_MASK_REG]) + raise_maskable_interrupt(r4300->state, 0x400); +} + +/* interrupt execution is scheduled (if not masked) */ +void signal_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr) +{ + r4300->mi.regs[MI_INTR_REG] |= mi_intr; + check_interupt(r4300->state); +} + +void clear_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr) +{ + r4300->mi.regs[MI_INTR_REG] &= ~mi_intr; + check_interupt(r4300->state); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/mi_controller.h b/Frameworks/lazyusf/lazyusf/r4300/mi_controller.h new file mode 100644 index 000000000..19337dd73 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/mi_controller.h @@ -0,0 +1,71 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - mi_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_MI_CONTROLLER_H +#define M64P_R4300_MI_CONTROLLER_H + +#include + +struct r4300_core; + +enum mi_registers +{ + MI_INIT_MODE_REG, + MI_VERSION_REG, + MI_INTR_REG, + MI_INTR_MASK_REG, + MI_REGS_COUNT +}; + + +enum mi_intr +{ + MI_INTR_SP = 0x01, + MI_INTR_SI = 0x02, + MI_INTR_AI = 0x04, + MI_INTR_VI = 0x08, + MI_INTR_PI = 0x10, + MI_INTR_DP = 0x20 +}; + +struct mi_controller +{ + uint32_t regs[MI_REGS_COUNT]; + uint32_t AudioIntrReg; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t mi_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +void init_mi(struct mi_controller* mi); + +int read_mi_regs(void* opaque, uint32_t address, uint32_t* value); +int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void raise_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr); +void signal_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr); +void clear_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.c b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.c new file mode 100644 index 000000000..8a78e45e3 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.c @@ -0,0 +1,4575 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assem_arm.c * + * Copyright (C) 2009-2011 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "main/main.h" +#include "../cp0.h" + +extern int cycle_count; +extern int last_count; +extern int pcaddr; +extern int pending_exception; +extern int branch_target; +extern int ram_offset; +extern uint64_t readmem_dword; +extern precomp_instr fake_pc; +extern void *dynarec_local; +extern u_int memory_map[1048576]; +extern u_int mini_ht[32][2]; +extern u_int rounding_modes[4]; + +static u_int literals[1024][2]; + +void indirect_jump_indexed(); +void indirect_jump(); +void do_interrupt(); +void jump_vaddr(); +void jump_vaddr_r0(); +void jump_vaddr_r1(); +void jump_vaddr_r2(); +void jump_vaddr_r3(); +void jump_vaddr_r4(); +void jump_vaddr_r5(); +void jump_vaddr_r6(); +void jump_vaddr_r7(); +void jump_vaddr_r8(); +void jump_vaddr_r9(); +void jump_vaddr_r10(); +void jump_vaddr_r12(); + +const u_int jump_vaddr_reg[16] = { + (int)jump_vaddr_r0, + (int)jump_vaddr_r1, + (int)jump_vaddr_r2, + (int)jump_vaddr_r3, + (int)jump_vaddr_r4, + (int)jump_vaddr_r5, + (int)jump_vaddr_r6, + (int)jump_vaddr_r7, + (int)jump_vaddr_r8, + (int)jump_vaddr_r9, + (int)jump_vaddr_r10, + 0, + (int)jump_vaddr_r12, + 0, + 0, + 0}; + +void invalidate_addr_r0(); +void invalidate_addr_r1(); +void invalidate_addr_r2(); +void invalidate_addr_r3(); +void invalidate_addr_r4(); +void invalidate_addr_r5(); +void invalidate_addr_r6(); +void invalidate_addr_r7(); +void invalidate_addr_r8(); +void invalidate_addr_r9(); +void invalidate_addr_r10(); +void invalidate_addr_r12(); + +const u_int invalidate_addr_reg[16] = { + (int)invalidate_addr_r0, + (int)invalidate_addr_r1, + (int)invalidate_addr_r2, + (int)invalidate_addr_r3, + (int)invalidate_addr_r4, + (int)invalidate_addr_r5, + (int)invalidate_addr_r6, + (int)invalidate_addr_r7, + (int)invalidate_addr_r8, + (int)invalidate_addr_r9, + (int)invalidate_addr_r10, + 0, + (int)invalidate_addr_r12, + 0, + 0, + 0}; + +#include "../fpu.h" + +static u_int jump_table_symbols[] = { + (int)invalidate_addr, + (int)jump_vaddr, + (int)dyna_linker, + (int)dyna_linker_ds, + (int)verify_code, + (int)verify_code_vm, + (int)verify_code_ds, + (int)cc_interrupt, + (int)fp_exception, + (int)fp_exception_ds, + (int)jump_syscall, + (int)jump_eret, + (int)indirect_jump_indexed, + (int)indirect_jump, + (int)do_interrupt, + (int)NULL /*MFC0*/, + (int)NULL /*MTC0*/, + (int)NULL /*TLBR*/, + (int)NULL /*TLBP*/, + (int)TLBWI_new, + (int)TLBWR_new, + (int)jump_vaddr_r0, + (int)jump_vaddr_r1, + (int)jump_vaddr_r2, + (int)jump_vaddr_r3, + (int)jump_vaddr_r4, + (int)jump_vaddr_r5, + (int)jump_vaddr_r6, + (int)jump_vaddr_r7, + (int)jump_vaddr_r8, + (int)jump_vaddr_r9, + (int)jump_vaddr_r10, + (int)jump_vaddr_r12, + (int)invalidate_addr_r0, + (int)invalidate_addr_r1, + (int)invalidate_addr_r2, + (int)invalidate_addr_r3, + (int)invalidate_addr_r4, + (int)invalidate_addr_r5, + (int)invalidate_addr_r6, + (int)invalidate_addr_r7, + (int)invalidate_addr_r8, + (int)invalidate_addr_r9, + (int)invalidate_addr_r10, + (int)invalidate_addr_r12, + (int)mult64, + (int)multu64, + (int)div64, + (int)divu64, + (int)cvt_s_w, + (int)cvt_d_w, + (int)cvt_s_l, + (int)cvt_d_l, + (int)cvt_w_s, + (int)cvt_w_d, + (int)cvt_l_s, + (int)cvt_l_d, + (int)cvt_d_s, + (int)cvt_s_d, + (int)round_l_s, + (int)round_w_s, + (int)trunc_l_s, + (int)trunc_w_s, + (int)ceil_l_s, + (int)ceil_w_s, + (int)floor_l_s, + (int)floor_w_s, + (int)round_l_d, + (int)round_w_d, + (int)trunc_l_d, + (int)trunc_w_d, + (int)ceil_l_d, + (int)ceil_w_d, + (int)floor_l_d, + (int)floor_w_d, + (int)c_f_s, + (int)c_un_s, + (int)c_eq_s, + (int)c_ueq_s, + (int)c_olt_s, + (int)c_ult_s, + (int)c_ole_s, + (int)c_ule_s, + (int)c_sf_s, + (int)c_ngle_s, + (int)c_seq_s, + (int)c_ngl_s, + (int)c_lt_s, + (int)c_nge_s, + (int)c_le_s, + (int)c_ngt_s, + (int)c_f_d, + (int)c_un_d, + (int)c_eq_d, + (int)c_ueq_d, + (int)c_olt_d, + (int)c_ult_d, + (int)c_ole_d, + (int)c_ule_d, + (int)c_sf_d, + (int)c_ngle_d, + (int)c_seq_d, + (int)c_ngl_d, + (int)c_lt_d, + (int)c_nge_d, + (int)c_le_d, + (int)c_ngt_d, + (int)add_s, + (int)sub_s, + (int)mul_s, + (int)div_s, + (int)sqrt_s, + (int)abs_s, + (int)mov_s, + (int)neg_s, + (int)add_d, + (int)sub_d, + (int)mul_d, + (int)div_d, + (int)sqrt_d, + (int)abs_d, + (int)mov_d, + (int)neg_d +}; + +static unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; + +#define JUMP_TABLE_SIZE (sizeof(jump_table_symbols)*2) + +/* Linker */ + +static void set_jump_target(int addr,u_int target) +{ + u_char *ptr=(u_char *)addr; + u_int *ptr2=(u_int *)ptr; + if(ptr[3]==0xe2) { + assert((target-(u_int)ptr2-8)<1024); + assert((addr&3)==0); + assert((target&3)==0); + *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00; + //DebugMessage(M64MSG_VERBOSE, "target=%x addr=%x insn=%x",target,addr,*ptr2); + } + else if(ptr[3]==0x72) { + // generated by emit_jno_unlikely + if((target-(u_int)ptr2-8)<1024) { + assert((addr&3)==0); + assert((target&3)==0); + *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00; + } + else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) { + assert((addr&3)==0); + assert((target&3)==0); + *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00; + } + else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8); + } + else { + assert((ptr[3]&0x0e)==0xa); + *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8); + } +} + +// This optionally copies the instruction from the target of the branch into +// the space before the branch. Works, but the difference in speed is +// usually insignificant. +/* +static void set_jump_target_fillslot(int addr,u_int target,int copy) +{ + u_char *ptr=(u_char *)addr; + u_int *ptr2=(u_int *)ptr; + assert(!copy||ptr2[-1]==0xe28dd000); + if(ptr[3]==0xe2) { + assert(!copy); + assert((target-(u_int)ptr2-8)<4096); + *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8); + } + else { + assert((ptr[3]&0x0e)==0xa); + u_int target_insn=*(u_int *)target; + if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags + copy=0; + } + if((target_insn&0x0c100000)==0x04100000) { // Load + copy=0; + } + if(target_insn&0x08000000) { + copy=0; + } + if(copy) { + ptr2[-1]=target_insn; + target+=4; + } + *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8); + } +} +*/ + +/* Literal pool */ +static void add_literal(int addr,int val) +{ + literals[literalcount][0]=addr; + literals[literalcount][1]=val; + literalcount++; +} + +static void *kill_pointer(void *stub) +{ + int *ptr=(int *)(stub+4); + assert((*ptr&0x0ff00000)==0x05900000); + u_int offset=*ptr&0xfff; + int **l_ptr=(void *)ptr+offset+8; + int *i_ptr=*l_ptr; + set_jump_target((int)i_ptr,(int)stub); + return i_ptr; +} + +static int get_pointer(void *stub) +{ + //DebugMessage(M64MSG_VERBOSE, "get_pointer(%x)",(int)stub); + int *ptr=(int *)(stub+4); + assert((*ptr&0x0ff00000)==0x05900000); + u_int offset=*ptr&0xfff; + int **l_ptr=(void *)ptr+offset+8; + int *i_ptr=*l_ptr; + assert((*i_ptr&0x0f000000)==0x0a000000); + return (int)i_ptr+((*i_ptr<<8)>>6)+8; +} + +// Find the "clean" entry point from a "dirty" entry point +// by skipping past the call to verify_code +static u_int get_clean_addr(int addr) +{ + int *ptr=(int *)addr; + #ifdef ARMv5_ONLY + ptr+=4; + #else + ptr+=6; + #endif + if((*ptr&0xFF000000)!=0xeb000000) ptr++; + assert((*ptr&0xFF000000)==0xeb000000); // bl instruction + ptr++; + if((*ptr&0xFF000000)==0xea000000) { + return (int)ptr+((*ptr<<8)>>6)+8; // follow jump + } + return (u_int)ptr; +} + +static int verify_dirty(void *addr) +{ + u_int *ptr=(u_int *)addr; + #ifdef ARMv5_ONLY + // get from literal pool + assert((*ptr&0xFFF00000)==0xe5900000); + u_int offset=*ptr&0xfff; + u_int *l_ptr=(void *)ptr+offset+8; + u_int source=l_ptr[0]; + u_int copy=l_ptr[1]; + u_int len=l_ptr[2]; + ptr+=4; + #else + // ARMv7 movw/movt + assert((*ptr&0xFFF00000)==0xe3000000); + u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); + u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); + u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); + ptr+=6; + #endif + if((*ptr&0xFF000000)!=0xeb000000) ptr++; + assert((*ptr&0xFF000000)==0xeb000000); // bl instruction + u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl + if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { + unsigned int page=source>>12; + unsigned int map_value=memory_map[page]; + if(map_value>=0x80000000) return 0; + while(page<((source+len-1)>>12)) { + if((memory_map[++page]<<2)!=(map_value<<2)) return 0; + } + source = source+(map_value<<2); + } + //DebugMessage(M64MSG_VERBOSE, "verify_dirty: %x %x %x",source,copy,len); + return !memcmp((void *)source,(void *)copy,len); +} + +// This doesn't necessarily find all clean entry points, just +// guarantees that it's not dirty +static int isclean(int addr) +{ + #ifdef ARMv5_ONLY + int *ptr=((u_int *)addr)+4; + #else + int *ptr=((u_int *)addr)+6; + #endif + if((*ptr&0xFF000000)!=0xeb000000) ptr++; + if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction + if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0; + if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_vm) return 0; + if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0; + return 1; +} + +static void get_bounds(int addr,u_int *start,u_int *end) +{ + u_int *ptr=(u_int *)addr; + #ifdef ARMv5_ONLY + // get from literal pool + assert((*ptr&0xFFF00000)==0xe5900000); + u_int offset=*ptr&0xfff; + u_int *l_ptr=(void *)ptr+offset+8; + u_int source=l_ptr[0]; + //u_int copy=l_ptr[1]; + u_int len=l_ptr[2]; + ptr+=4; + #else + // ARMv7 movw/movt + assert((*ptr&0xFFF00000)==0xe3000000); + u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); + //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); + u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); + ptr+=6; + #endif + if((*ptr&0xFF000000)!=0xeb000000) ptr++; + assert((*ptr&0xFF000000)==0xeb000000); // bl instruction + u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl + if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { + if(memory_map[source>>12]>=0x80000000) source = 0; + else source = source+(memory_map[source>>12]<<2); + } + *start=source; + *end=source+len; +} + +/* Register allocation */ + +// Note: registers are allocated clean (unmodified state) +// if you intend to modify the register, you must call dirty_reg(). +static void alloc_reg(struct regstat *cur,int i,signed char reg) +{ + int r,hr; + int preferred_reg = (reg&7); + if(reg==CCREG) preferred_reg=HOST_CCREG; + if(reg==PTEMP||reg==FTEMP) preferred_reg=12; + + // Don't allocate unused registers + if((cur->u>>reg)&1) return; + + // see if it's already allocated + for(hr=0;hrregmap[hr]==reg) return; + } + + // Keep the same mapping if the register was already allocated in a loop + preferred_reg = loop_reg(i,reg,preferred_reg); + + // Try to allocate the preferred register + if(cur->regmap[preferred_reg]==-1) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; + if(r<64&&((cur->u>>r)&1)) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} + } + else + { + if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} + } + } + } + // Try to allocate any available register, but prefer + // registers that have not been used recently. + if(i>0) { + for(hr=0;hrregmap[hr]==-1) { + if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]); + //DebugMessage(M64MSG_VERBOSE, "hsn(%x): %d %d %d %d %d %d %d",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + // Alloc preferred register if available + if(hsn[r=cur->regmap[preferred_reg]&63]==j) { + for(hr=0;hrregmap[hr]&63)==r) { + cur->regmap[hr]=-1; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; + return; + } + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<uu>>reg)&1) return; + + // see if the upper half is already allocated + for(hr=0;hrregmap[hr]==reg+64) return; + } + + // Keep the same mapping if the register was already allocated in a loop + preferred_reg = loop_reg(i,reg,preferred_reg); + + // Try to allocate the preferred register + if(cur->regmap[preferred_reg]==-1) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; + if(r<64&&((cur->u>>r)&1)) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=0;hr--) + { + r=cur->regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} + } + else + { + if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} + } + } + } + // Try to allocate any available register, but prefer + // registers that have not been used recently. + if(i>0) { + for(hr=0;hrregmap[hr]==-1) { + if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]); + //DebugMessage(M64MSG_VERBOSE, "hsn(%x): %d %d %d %d %d %d %d",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + // Alloc preferred register if available + if(hsn[r=cur->regmap[preferred_reg]&63]==j) { + for(hr=0;hrregmap[hr]&63)==r) { + cur->regmap[hr]=-1; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg|64; + return; + } + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; + } + + // Try to allocate any available register + for(hr=HOST_REGS-1;hr>=0;hr--) { + if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;hr--) + { + r=cur->regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) { + if(i==0||((unneeded_reg[i-1]>>r)&1)) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { + if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hr2) { + if(cur->regmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<2) { + if(cur->regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[n]==reg) { + dirty=(cur->dirty>>n)&1; + cur->regmap[n]=-1; + } + } + + cur->regmap[hr]=reg; + cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<0) + { + if(imm<256) { + *encoded=((i&30)<<7)|imm; + return 1; + } + imm=(imm>>2)|(imm<<30);i-=2; + } + return 0; +} +static u_int genjmp(u_int addr) +{ + if(addr<4) return 0; + int offset=addr-(int)out-8; + if(offset<-33554432||offset>=33554432) { + int n; + for (n=0;n=-33554432&&offset<33554432); + return ((u_int)offset>>2)&0xffffff; +} + +static void emit_mov(int rs,int rt) +{ + assem_debug("mov %s,%s",regname[rt],regname[rs]); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)); +} + +static void emit_movs(int rs,int rt) +{ + assem_debug("movs %s,%s",regname[rt],regname[rs]); + output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)); +} + +static void emit_add(int rs1,int rs2,int rt) +{ + assem_debug("add %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_addne(int rs1,int rs2,int rt) +{ + assem_debug("addne %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x12800000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_addsarimm(int rs1,int rs2,int rt,int imm) +{ + assert(imm>0); + assert(imm<32); + assem_debug("add %s,%s,%s,ASR#%d",regname[rt],regname[rs1],regname[rs2],imm); + output_w32(0xe0a00000|rd_rn_rm(rt,rs1,rs2)|0x40|(imm<<7)); +} + +static void emit_adds(int rs1,int rs2,int rt) +{ + assem_debug("adds %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_adc(int rs1,int rs2,int rt) +{ + assem_debug("adc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0a00000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_adcs(int rs1,int rs2,int rt) +{ + assem_debug("adcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_sbc(int rs1,int rs2,int rt) +{ + assem_debug("sbc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0c00000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_sbcs(int rs1,int rs2,int rt) +{ + assem_debug("sbcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0d00000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_neg(int rs, int rt) +{ + assem_debug("rsb %s,%s,#0",regname[rt],regname[rs]); + output_w32(0xe2600000|rd_rn_rm(rt,rs,0)); +} + +static void emit_negs(int rs, int rt) +{ + assem_debug("rsbs %s,%s,#0",regname[rt],regname[rs]); + output_w32(0xe2700000|rd_rn_rm(rt,rs,0)); +} + +static void emit_sub(int rs1,int rs2,int rt) +{ + assem_debug("sub %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_subs(int rs1,int rs2,int rt) +{ + assem_debug("subs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_zeroreg(int rt) +{ + assem_debug("mov %s,#0",regname[rt]); + output_w32(0xe3a00000|rd_rn_rm(rt,0,0)); +} + +static void emit_loadlp(u_int imm,u_int rt) +{ + add_literal((int)out,imm); + assem_debug("ldr %s,pc+? [=%x]",regname[rt],imm); + output_w32(0xe5900000|rd_rn_rm(rt,15,0)); +} +static void emit_movw(u_int imm,u_int rt) +{ + assert(imm<65536); + assem_debug("movw %s,#%d (0x%x)",regname[rt],imm,imm); + output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000)); +} +static void emit_movt(u_int imm,u_int rt) +{ + assem_debug("movt %s,#%d (0x%x)",regname[rt],imm&0xffff0000,imm&0xffff0000); + output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000)); +} +static void emit_movimm(u_int imm,u_int rt) +{ + u_int armval; + if(genimm(imm,&armval)) { + assem_debug("mov %s,#%d",regname[rt],imm); + output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval); + }else if(genimm(~imm,&armval)) { + assem_debug("mvn %s,#%d",regname[rt],imm); + output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval); + }else if(imm<65536) { + #ifdef ARMv5_ONLY + assem_debug("mov %s,#%d",regname[rt],imm&0xFF00); + output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8)); + assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); + output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); + #else + emit_movw(imm,rt); + #endif + }else{ + #ifdef ARMv5_ONLY + emit_loadlp(imm,rt); + #else + emit_movw(imm&0x0000FFFF,rt); + emit_movt(imm&0xFFFF0000,rt); + #endif + } +} +static void emit_pcreladdr(u_int rt) +{ + assem_debug("add %s,pc,#?",regname[rt]); + output_w32(0xe2800000|rd_rn_rm(rt,15,0)); +} + +static void emit_loadreg(int r, int hr) +{ + if((r&63)==0) + emit_zeroreg(hr); + else if(r==MMREG) + emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,hr); + else { + int addr=((int)reg)+((r&63)<<3)+((r&64)>>4); + if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4); + if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4); + if(r==CCREG) addr=(int)&cycle_count; + if(r==CSREG) addr=(int)&g_cp0_regs[CP0_STATUS_REG]; + if(r==FSREG) addr=(int)&FCR31; + if(r==INVCP) addr=(int)&invc_ptr; + if(r==ROREG) addr=(int)&ram_offset; + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("ldr %s,fp+%d",regname[hr],offset); + output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset); + } +} +static void emit_storereg(int r, int hr) +{ + int addr=((int)reg)+((r&63)<<3)+((r&64)>>4); + if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4); + if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4); + if(r==CCREG) addr=(int)&cycle_count; + if(r==FSREG) addr=(int)&FCR31; + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("str %s,fp+%d",regname[hr],offset); + output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset); +} + +static void emit_test(int rs, int rt) +{ + assem_debug("tst %s,%s",regname[rs],regname[rt]); + output_w32(0xe1100000|rd_rn_rm(0,rs,rt)); +} + +static void emit_testimm(int rs,int imm) +{ + u_int armval, ret; + assem_debug("tst %s,#%d",regname[rs],imm); + ret = genimm(imm,&armval); + assert(ret); + output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval); +} + +static void emit_not(int rs,int rt) +{ + assem_debug("mvn %s,%s",regname[rt],regname[rs]); + output_w32(0xe1e00000|rd_rn_rm(rt,0,rs)); +} + +static void emit_and(u_int rs1,u_int rs2,u_int rt) +{ + assem_debug("and %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_or(u_int rs1,u_int rs2,u_int rt) +{ + assem_debug("orr %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2)); +} +static void emit_or_and_set_flags(int rs1,int rs2,int rt) +{ + assem_debug("orrs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_xor(u_int rs1,u_int rs2,u_int rt) +{ + assem_debug("eor %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_addimm(u_int rs,int imm,u_int rt) +{ + assert(rs<16); + assert(rt<16); + if(imm!=0) { + assert(imm>-65536&&imm<65536); + u_int armval; + if(genimm(imm,&armval)) { + assem_debug("add %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval); + }else if(genimm(-imm,&armval)) { + assem_debug("sub %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval); + }else if(imm<0) { + assem_debug("sub %s,%s,#%d",regname[rt],regname[rs],(-imm)&0xFF00); + assem_debug("sub %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF); + output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8)); + output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); + }else{ + assem_debug("add %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); + assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); + output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); + output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); + } + } + else if(rs!=rt) emit_mov(rs,rt); +} + +static void emit_addimm_and_set_flags(int imm,int rt) +{ + assert(imm>-65536&&imm<65536); + u_int armval; + if(genimm(imm,&armval)) { + assem_debug("adds %s,%s,#%d",regname[rt],regname[rt],imm); + output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval); + }else if(genimm(-imm,&armval)) { + assem_debug("subs %s,%s,#%d",regname[rt],regname[rt],imm); + output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval); + }else if(imm<0) { + assem_debug("sub %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF00); + assem_debug("subs %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF); + output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8)); + output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); + }else{ + assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF00); + assem_debug("adds %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); + output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8)); + output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); + } +} + +#ifndef RAM_OFFSET +static void emit_addimm_no_flags(u_int imm,u_int rt) +{ + emit_addimm(rt,imm,rt); +} +#endif + +static void emit_addnop(u_int r) +{ + assert(r<16); + assem_debug("add %s,%s,#0 (nop)",regname[r],regname[r]); + output_w32(0xe2800000|rd_rn_rm(r,r,0)); +} + +static void emit_adcimm(u_int rs,int imm,u_int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("adc %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval); +} +/*static void emit_sbcimm(int imm,u_int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("sbc %s,%s,#%d",regname[rt],regname[rt],imm); + output_w32(0xe2c00000|rd_rn_rm(rt,rt,0)|armval); +}*/ + +static void emit_rscimm(int rs,int imm,u_int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("rsc %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) +{ + // TODO: if(genimm(imm,&armval)) ... + // else + emit_movimm(imm,HOST_TEMPREG); + emit_adds(HOST_TEMPREG,rsl,rtl); + emit_adcimm(rsh,0,rth); +} +#ifdef INVERTED_CARRY +static void emit_sbb(int rs1,int rs2) +{ + assem_debug("sbb %%%s,%%%s",regname[rs2],regname[rs1]); + output_byte(0x19); + output_modrm(3,rs1,rs2); +} +#endif + +static void emit_andimm(int rs,int imm,int rt) +{ + u_int armval; + if(imm==0) { + emit_zeroreg(rt); + }else if(genimm(imm,&armval)) { + assem_debug("and %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval); + }else if(genimm(~imm,&armval)) { + assem_debug("bic %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval); + }else if(imm==65535) { + #ifdef ARMv5_ONLY + assem_debug("bic %s,%s,#FF000000",regname[rt],regname[rs]); + output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF); + assem_debug("bic %s,%s,#00FF0000",regname[rt],regname[rt]); + output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF); + #else + assem_debug("uxth %s,%s",regname[rt],regname[rs]); + output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs)); + #endif + }else{ + assert(imm>0&&imm<65535); + #ifdef ARMv5_ONLY + assem_debug("mov r14,#%d",imm&0xFF00); + output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8)); + assem_debug("add r14,r14,#%d",imm&0xFF); + output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0)); + #else + emit_movw(imm,HOST_TEMPREG); + #endif + assem_debug("and %s,%s,r14",regname[rt],regname[rs]); + output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG)); + } +} + +static void emit_orimm(int rs,int imm,int rt) +{ + u_int armval; + if(imm==0) { + if(rs!=rt) emit_mov(rs,rt); + }else if(genimm(imm,&armval)) { + assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval); + }else{ + assert(imm>0&&imm<65536); + assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); + assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm&0xFF); + output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); + output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); + } +} + +static void emit_xorimm(int rs,int imm,int rt) +{ + u_int armval; + if(imm==0) { + if(rs!=rt) emit_mov(rs,rt); + }else if(genimm(imm,&armval)) { + assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval); + }else{ + assert(imm>0&&imm<65536); + assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); + assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm&0xFF); + output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8)); + output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); + } +} + +static void emit_shlimm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + //if(imm==1) ... + assem_debug("lsl %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); +} + +static void emit_shrimm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("lsr %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); +} + +static void emit_sarimm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("asr %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7)); +} + +static void emit_rorimm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("ror %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7)); +} + +static void emit_shldimm(int rs,int rs2,u_int imm,int rt) +{ + assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); + assert(imm>0); + assert(imm<32); + //if(imm==1) ... + assem_debug("lsl %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); + assem_debug("orr %s,%s,%s,lsr #%d",regname[rt],regname[rt],regname[rs2],32-imm); + output_w32(0xe1800020|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); +} + +static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) +{ + assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); + assert(imm>0); + assert(imm<32); + //if(imm==1) ... + assem_debug("lsr %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe1a00020|rd_rn_rm(rt,0,rs)|(imm<<7)); + assem_debug("orr %s,%s,%s,lsl #%d",regname[rt],regname[rt],regname[rs2],32-imm); + output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); +} + +static void emit_shl(u_int rs,u_int shift,u_int rt) +{ + assert(rs<16); + assert(rt<16); + assert(shift<16); + //if(imm==1) ... + assem_debug("lsl %s,%s,%s",regname[rt],regname[rs],regname[shift]); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8)); +} +static void emit_shr(u_int rs,u_int shift,u_int rt) +{ + assert(rs<16); + assert(rt<16); + assert(shift<16); + assem_debug("lsr %s,%s,%s",regname[rt],regname[rs],regname[shift]); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8)); +} +static void emit_sar(u_int rs,u_int shift,u_int rt) +{ + assert(rs<16); + assert(rt<16); + assert(shift<16); + assem_debug("asr %s,%s,%s",regname[rt],regname[rs],regname[shift]); + output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8)); +} + +static void emit_orrshl(u_int rs,u_int shift,u_int rt) +{ + assert(rs<16); + assert(rt<16); + assert(shift<16); + assem_debug("orr %s,%s,%s,lsl %s",regname[rt],regname[rt],regname[rs],regname[shift]); + output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8)); +} +static void emit_orrshr(u_int rs,u_int shift,u_int rt) +{ + assert(rs<16); + assert(rt<16); + assert(shift<16); + assem_debug("orr %s,%s,%s,lsr %s",regname[rt],regname[rt],regname[rs],regname[shift]); + output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8)); +} + +static void emit_cmpimm(int rs,int imm) +{ + u_int armval; + if(genimm(imm,&armval)) { + assem_debug("cmp %s,#%d",regname[rs],imm); + output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval); + }else if(genimm(-imm,&armval)) { + assem_debug("cmn %s,#%d",regname[rs],imm); + output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval); + }else if(imm>0) { + assert(imm<65536); + #ifdef ARMv5_ONLY + emit_movimm(imm,HOST_TEMPREG); + #else + emit_movw(imm,HOST_TEMPREG); + #endif + assem_debug("cmp %s,r14",regname[rs]); + output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG)); + }else{ + assert(imm>-65536); + #ifdef ARMv5_ONLY + emit_movimm(-imm,HOST_TEMPREG); + #else + emit_movw(-imm,HOST_TEMPREG); + #endif + assem_debug("cmn %s,r14",regname[rs]); + output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG)); + } +} + +static void emit_cmovne_imm(int imm,int rt) +{ + assem_debug("movne %s,#%d",regname[rt],imm); + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval); +} +static void emit_cmovl_imm(int imm,int rt) +{ + assem_debug("movlt %s,#%d",regname[rt],imm); + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval); +} +static void emit_cmovb_imm(int imm,int rt) +{ + assem_debug("movcc %s,#%d",regname[rt],imm); + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval); +} +static void emit_cmovs_imm(int imm,int rt) +{ + assem_debug("movmi %s,#%d",regname[rt],imm); + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval); +} +static void emit_cmove_reg(int rs,int rt) +{ + assem_debug("moveq %s,%s",regname[rt],regname[rs]); + output_w32(0x01a00000|rd_rn_rm(rt,0,rs)); +} +static void emit_cmovne_reg(int rs,int rt) +{ + assem_debug("movne %s,%s",regname[rt],regname[rs]); + output_w32(0x11a00000|rd_rn_rm(rt,0,rs)); +} +static void emit_cmovl_reg(int rs,int rt) +{ + assem_debug("movlt %s,%s",regname[rt],regname[rs]); + output_w32(0xb1a00000|rd_rn_rm(rt,0,rs)); +} +static void emit_cmovs_reg(int rs,int rt) +{ + assem_debug("movmi %s,%s",regname[rt],regname[rs]); + output_w32(0x41a00000|rd_rn_rm(rt,0,rs)); +} + +static void emit_slti32(int rs,int imm,int rt) +{ + if(rs!=rt) emit_zeroreg(rt); + emit_cmpimm(rs,imm); + if(rs==rt) emit_movimm(0,rt); + emit_cmovl_imm(1,rt); +} +static void emit_sltiu32(int rs,int imm,int rt) +{ + if(rs!=rt) emit_zeroreg(rt); + emit_cmpimm(rs,imm); + if(rs==rt) emit_movimm(0,rt); + emit_cmovb_imm(1,rt); +} +static void emit_slti64_32(int rsh,int rsl,int imm,int rt) +{ + assert(rsh!=rt); + emit_slti32(rsl,imm,rt); + if(imm>=0) + { + emit_test(rsh,rsh); + emit_cmovne_imm(0,rt); + emit_cmovs_imm(1,rt); + } + else + { + emit_cmpimm(rsh,-1); + emit_cmovne_imm(0,rt); + emit_cmovl_imm(1,rt); + } +} +static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) +{ + assert(rsh!=rt); + emit_sltiu32(rsl,imm,rt); + if(imm>=0) + { + emit_test(rsh,rsh); + emit_cmovne_imm(0,rt); + } + else + { + emit_cmpimm(rsh,-1); + emit_cmovne_imm(1,rt); + } +} + +static void emit_cmp(int rs,int rt) +{ + assem_debug("cmp %s,%s",regname[rs],regname[rt]); + output_w32(0xe1500000|rd_rn_rm(0,rs,rt)); +} +static void emit_set_gz32(int rs, int rt) +{ + //assem_debug("set_gz32"); + emit_cmpimm(rs,1); + emit_movimm(1,rt); + emit_cmovl_imm(0,rt); +} +static void emit_set_nz32(int rs, int rt) +{ + //assem_debug("set_nz32"); + if(rs!=rt) emit_movs(rs,rt); + else emit_test(rs,rs); + emit_cmovne_imm(1,rt); +} +static void emit_set_gz64_32(int rsh, int rsl, int rt) +{ + //assem_debug("set_gz64"); + emit_set_gz32(rsl,rt); + emit_test(rsh,rsh); + emit_cmovne_imm(1,rt); + emit_cmovs_imm(0,rt); +} +static void emit_set_nz64_32(int rsh, int rsl, int rt) +{ + //assem_debug("set_nz64"); + emit_or_and_set_flags(rsh,rsl,rt); + emit_cmovne_imm(1,rt); +} +static void emit_set_if_less32(int rs1, int rs2, int rt) +{ + //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); + if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); + emit_cmp(rs1,rs2); + if(rs1==rt||rs2==rt) emit_movimm(0,rt); + emit_cmovl_imm(1,rt); +} +static void emit_set_if_carry32(int rs1, int rs2, int rt) +{ + //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); + if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); + emit_cmp(rs1,rs2); + if(rs1==rt||rs2==rt) emit_movimm(0,rt); + emit_cmovb_imm(1,rt); +} +static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) +{ + //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); + assert(u1!=rt); + assert(u2!=rt); + emit_cmp(l1,l2); + emit_movimm(0,rt); + emit_sbcs(u1,u2,HOST_TEMPREG); + emit_cmovl_imm(1,rt); +} +static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) +{ + //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); + assert(u1!=rt); + assert(u2!=rt); + emit_cmp(l1,l2); + emit_movimm(0,rt); + emit_sbcs(u1,u2,HOST_TEMPREG); + emit_cmovb_imm(1,rt); +} + +static void emit_call(int a) +{ + assem_debug("bl %x (%x+%x)",a,(int)out,a-(int)out-8); + u_int offset=genjmp(a); + output_w32(0xeb000000|offset); +} +static void emit_jmp(int a) +{ + assem_debug("b %x (%x+%x)",a,(int)out,a-(int)out-8); + u_int offset=genjmp(a); + output_w32(0xea000000|offset); +} +static void emit_jne(int a) +{ + assem_debug("bne %x",a); + u_int offset=genjmp(a); + output_w32(0x1a000000|offset); +} +static void emit_jeq(int a) +{ + assem_debug("beq %x",a); + u_int offset=genjmp(a); + output_w32(0x0a000000|offset); +} +static void emit_js(int a) +{ + assem_debug("bmi %x",a); + u_int offset=genjmp(a); + output_w32(0x4a000000|offset); +} +static void emit_jns(int a) +{ + assem_debug("bpl %x",a); + u_int offset=genjmp(a); + output_w32(0x5a000000|offset); +} +static void emit_jl(int a) +{ + assem_debug("blt %x",a); + u_int offset=genjmp(a); + output_w32(0xba000000|offset); +} +static void emit_jge(int a) +{ + assem_debug("bge %x",a); + u_int offset=genjmp(a); + output_w32(0xaa000000|offset); +} +static void emit_jno(int a) +{ + assem_debug("bvc %x",a); + u_int offset=genjmp(a); + output_w32(0x7a000000|offset); +} + +static void emit_jcc(int a) +{ + assem_debug("bcc %x",a); + u_int offset=genjmp(a); + output_w32(0x3a000000|offset); +} +static void emit_jae(int a) +{ + assem_debug("bcs %x",a); + u_int offset=genjmp(a); + output_w32(0x2a000000|offset); +} +static void emit_jb(int a) +{ + assem_debug("bcc %x",a); + u_int offset=genjmp(a); + output_w32(0x3a000000|offset); +} + +static void emit_pushreg(u_int r) +{ + assem_debug("push %%%s",regname[r]); + assert(0); +} +static void emit_popreg(u_int r) +{ + assem_debug("pop %%%s",regname[r]); + assert(0); +} +/* +static void emit_callreg(u_int r) +{ + assem_debug("call *%%%s",regname[r]); + assert(0); +} +static void emit_jmpreg(u_int r) +{ + assem_debug("mov pc,%s",regname[r]); + output_w32(0xe1a00000|rd_rn_rm(15,0,r)); +} +*/ +static void emit_readword_indexed(int offset, int rs, int rt) +{ + assert(offset>-4096&&offset<4096); + assem_debug("ldr %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset); + }else{ + output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset)); + } +} +static void emit_readword_dualindexedx4(int rs1, int rs2, int rt) +{ + assem_debug("ldr %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100); +} +static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_readword_indexed(addr, rs, rt); + else { + assert(addr==0); + emit_readword_dualindexedx4(rs, map, rt); + } +} +static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) +{ + if(map<0) { + if(rh>=0) emit_readword_indexed(addr, rs, rh); + emit_readword_indexed(addr+4, rs, rl); + }else{ + assert(rh!=rs); + if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); + emit_addimm(map,1,HOST_TEMPREG); + emit_readword_indexed_tlb(addr, rs, HOST_TEMPREG, rl); + } +} +static void emit_movsbl_indexed(int offset, int rs, int rt) +{ + assert(offset>-256&&offset<256); + assem_debug("ldrsb %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} +static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_movsbl_indexed(addr, rs, rt); + else { + if(addr==0) { + emit_shlimm(map,2,HOST_TEMPREG); + assem_debug("ldrsb %s,%s+%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); + output_w32(0xe19000d0|rd_rn_rm(rt,rs,HOST_TEMPREG)); + }else{ + assert(addr>-256&&addr<256); + assem_debug("add %s,%s,%s,lsl #2",regname[rt],regname[rs],regname[map]); + output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); + emit_movsbl_indexed(addr, rt, rt); + } + } +} +static void emit_movswl_indexed(int offset, int rs, int rt) +{ + assert(offset>-256&&offset<256); + assem_debug("ldrsh %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} +static void emit_movzbl_indexed(int offset, int rs, int rt) +{ + assert(offset>-4096&&offset<4096); + assem_debug("ldrb %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset); + }else{ + output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset)); + } +} +static void emit_movzbl_dualindexedx4(int rs1, int rs2, int rt) +{ + assem_debug("ldrb %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe7d00000|rd_rn_rm(rt,rs1,rs2)|0x100); +} +static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_movzbl_indexed(addr, rs, rt); + else { + if(addr==0) { + emit_movzbl_dualindexedx4(rs, map, rt); + }else{ + emit_addimm(rs,addr,rt); + emit_movzbl_dualindexedx4(rt, map, rt); + } + } +} +static void emit_movzwl_indexed(int offset, int rs, int rt) +{ + assert(offset>-256&&offset<256); + assem_debug("ldrh %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} +static void emit_readword(int addr, int rt) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("ldr %s,fp+%d",regname[rt],offset); + output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset); +} +static void emit_movsbl(int addr, int rt) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<256); + assem_debug("ldrsb %s,fp+%d",regname[rt],offset); + output_w32(0xe1d000d0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); +} +static void emit_movswl(int addr, int rt) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<256); + assem_debug("ldrsh %s,fp+%d",regname[rt],offset); + output_w32(0xe1d000f0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); +} +static void emit_movzbl(int addr, int rt) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("ldrb %s,fp+%d",regname[rt],offset); + output_w32(0xe5d00000|rd_rn_rm(rt,FP,0)|offset); +} +static void emit_movzwl(int addr, int rt) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<256); + assem_debug("ldrh %s,fp+%d",regname[rt],offset); + output_w32(0xe1d000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); +} + +/* +static void emit_movzwl_reg(int rs, int rt) +{ + assem_debug("movzwl %%%s,%%%s",regname[rs]+1,regname[rt]); + assert(0); +} +*/ + +static void emit_writeword_indexed(int rt, int offset, int rs) +{ + assert(offset>-4096&&offset<4096); + assem_debug("str %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset); + }else{ + output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset)); + } +} +static void emit_writeword_dualindexedx4(int rt, int rs1, int rs2) +{ + assem_debug("str %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe7800000|rd_rn_rm(rt,rs1,rs2)|0x100); +} +static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map, int temp) +{ + if(map<0) emit_writeword_indexed(rt, addr, rs); + else { + assert(addr==0); + emit_writeword_dualindexedx4(rt, rs, map); + } +} +static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map, int temp) +{ + if(map<0) { + if(rh>=0) emit_writeword_indexed(rh, addr, rs); + emit_writeword_indexed(rl, addr+4, rs); + }else{ + assert(rh>=0); + if(temp!=rs) emit_addimm(map,1,temp); + emit_writeword_indexed_tlb(rh, addr, rs, map, temp); + if(temp!=rs) emit_writeword_indexed_tlb(rl, addr, rs, temp, temp); + else { + emit_addimm(rs,4,rs); + emit_writeword_indexed_tlb(rl, addr, rs, map, temp); + } + } +} +static void emit_writehword_indexed(int rt, int offset, int rs) +{ + assert(offset>-256&&offset<256); + assem_debug("strh %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} +static void emit_writebyte_indexed(int rt, int offset, int rs) +{ + assert(offset>-4096&&offset<4096); + assem_debug("strb %s,%s+%d",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset); + }else{ + output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset)); + } +} +static void emit_writebyte_dualindexedx4(int rt, int rs1, int rs2) +{ + assem_debug("strb %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe7c00000|rd_rn_rm(rt,rs1,rs2)|0x100); +} +static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map, int temp) +{ + if(map<0) emit_writebyte_indexed(rt, addr, rs); + else { + if(addr==0) { + emit_writebyte_dualindexedx4(rt, rs, map); + }else{ + emit_addimm(rs,addr,temp); + emit_writebyte_dualindexedx4(rt, temp, map); + } + } +} +static void emit_writeword(int rt, int addr) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("str %s,fp+%d",regname[rt],offset); + output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset); +} +static void emit_writehword(int rt, int addr) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<256); + assem_debug("strh %s,fp+%d",regname[rt],offset); + output_w32(0xe1c000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); +} +static void emit_writebyte(int rt, int addr) +{ + u_int offset = addr-(u_int)&dynarec_local; + assert(offset<4096); + assem_debug("strb %s,fp+%d",regname[rt],offset); + output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset); +} + +/* +static void emit_mul(int rs) +{ + assem_debug("mul %%%s",regname[rs]); + assert(0); +} +*/ + +static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo) +{ + assem_debug("umull %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); + assert(rs1<16); + assert(rs2<16); + assert(hi<16); + assert(lo<16); + output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); +} +static void emit_umlal(u_int rs1, u_int rs2, u_int hi, u_int lo) +{ + assem_debug("umlal %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); + assert(rs1<16); + assert(rs2<16); + assert(hi<16); + assert(lo<16); + output_w32(0xe0a00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); +} +static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo) +{ + assem_debug("smull %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); + assert(rs1<16); + assert(rs2<16); + assert(hi<16); + assert(lo<16); + output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); +} +static void emit_smlal(u_int rs1, u_int rs2, u_int hi, u_int lo) +{ + assem_debug("smlal %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); + assert(rs1<16); + assert(rs2<16); + assert(hi<16); + assert(lo<16); + output_w32(0xe0e00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); +} + +static void emit_clz(int rs,int rt) +{ + assem_debug("clz %s,%s",regname[rt],regname[rs]); + output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs)); +} + +static void emit_subcs(int rs1,int rs2,int rt) +{ + assem_debug("subcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_shrcc_imm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("lsrcc %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); +} + +static void emit_negmi(int rs, int rt) +{ + assem_debug("rsbmi %s,%s,#0",regname[rt],regname[rs]); + output_w32(0x42600000|rd_rn_rm(rt,rs,0)); +} + +static void emit_orreq(u_int rs1,u_int rs2,u_int rt) +{ + assem_debug("orreq %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x01800000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_orrne(u_int rs1,u_int rs2,u_int rt) +{ + assem_debug("orrne %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x11800000|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("bic %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); +} + +static void emit_biceq_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("biceq %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); +} + +static void emit_bicne_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("bicne %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); +} + +static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("bic %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); +} + +static void emit_biceq_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("biceq %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); +} + +static void emit_bicne_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) +{ + assem_debug("bicne %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); + output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); +} + +static void emit_teq(int rs, int rt) +{ + assem_debug("teq %s,%s",regname[rs],regname[rt]); + output_w32(0xe1300000|rd_rn_rm(0,rs,rt)); +} + +static void emit_rsbimm(int rs, int imm, int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("rsb %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval); +} + +// Load 2 immediates optimizing for small code size +static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) +{ + emit_movimm(imm1,rt1); + u_int armval; + if(genimm(imm2-imm1,&armval)) { + assem_debug("add %s,%s,#%d",regname[rt2],regname[rt1],imm2-imm1); + output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval); + }else if(genimm(imm1-imm2,&armval)) { + assem_debug("sub %s,%s,#%d",regname[rt2],regname[rt1],imm1-imm2); + output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval); + } + else emit_movimm(imm2,rt2); +} + +// Conditionally select one of two immediates, optimizing for small code size +// This will only be called if HAVE_CMOV_IMM is defined +static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt) +{ + u_int armval; + if(genimm(imm2-imm1,&armval)) { + emit_movimm(imm1,rt); + assem_debug("addne %s,%s,#%d",regname[rt],regname[rt],imm2-imm1); + output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval); + }else if(genimm(imm1-imm2,&armval)) { + emit_movimm(imm1,rt); + assem_debug("subne %s,%s,#%d",regname[rt],regname[rt],imm1-imm2); + output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval); + } + else { + #ifdef ARMv5_ONLY + emit_movimm(imm1,rt); + add_literal((int)out,imm2); + assem_debug("ldrne %s,pc+? [=%x]",regname[rt],imm2); + output_w32(0x15900000|rd_rn_rm(rt,15,0)); + #else + emit_movw(imm1&0x0000FFFF,rt); + if((imm1&0xFFFF)!=(imm2&0xFFFF)) { + assem_debug("movwne %s,#%d (0x%x)",regname[rt],imm2&0xFFFF,imm2&0xFFFF); + output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000)); + } + emit_movt(imm1&0xFFFF0000,rt); + if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) { + assem_debug("movtne %s,#%d (0x%x)",regname[rt],imm2&0xffff0000,imm2&0xffff0000); + output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000)); + } + #endif + } +} + +#if !defined(HOST_IMM8) +// special case for checking invalid_code +static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) +{ + assert(0); +} +#endif + +// special case for checking invalid_code +static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) +{ + assert(imm<128&&imm>=0); + assert(r>=0&&r<16); + assem_debug("ldrb lr,%s,%s lsr #12",regname[base],regname[r]); + output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620); + emit_cmpimm(HOST_TEMPREG,imm); +} + +// special case for tlb mapping +static void emit_addsr12(int rs1,int rs2,int rt) +{ + assem_debug("add %s,%s,%s lsr #12",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2)); +} + +static void emit_callne(int a) +{ + assem_debug("blne %x",a); + u_int offset=genjmp(a); + output_w32(0x1b000000|offset); +} + +#ifdef IMM_PREFETCH +// Used to preload hash table entries +static void emit_prefetch(void *addr) +{ + assem_debug("prefetch %x",(int)addr); + output_byte(0x0F); + output_byte(0x18); + output_modrm(0,5,1); + output_w32((int)addr); +} +#endif + +#ifdef REG_PREFETCH +static void emit_prefetchreg(int r) +{ + assem_debug("pld %s",regname[r]); + output_w32(0xf5d0f000|rd_rn_rm(0,r,0)); +} +#endif + +// Special case for mini_ht +static void emit_ldreq_indexed(int rs, u_int offset, int rt) +{ + assert(offset<4096); + assem_debug("ldreq %s,[%s, #%d]",regname[rt],regname[rs],offset); + output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset); +} + +static void emit_flds(int r,int sr) +{ + assem_debug("flds s%d,[%s]",sr,regname[r]); + output_w32(0xed900a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); +} + +static void emit_vldr(int r,int vr) +{ + assem_debug("vldr d%d,[%s]",vr,regname[r]); + output_w32(0xed900b00|(vr<<12)|(r<<16)); +} + +static void emit_fsts(int sr,int r) +{ + assem_debug("fsts s%d,[%s]",sr,regname[r]); + output_w32(0xed800a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); +} + +static void emit_vstr(int vr,int r) +{ + assem_debug("vstr d%d,[%s]",vr,regname[r]); + output_w32(0xed800b00|(vr<<12)|(r<<16)); +} + +static void emit_ftosizs(int s,int d) +{ + assem_debug("ftosizs s%d,s%d",d,s); + output_w32(0xeebd0ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_ftosizd(int s,int d) +{ + assem_debug("ftosizd s%d,d%d",d,s); + output_w32(0xeebd0bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); +} + +static void emit_fsitos(int s,int d) +{ + assem_debug("fsitos s%d,s%d",d,s); + output_w32(0xeeb80ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fsitod(int s,int d) +{ + assem_debug("fsitod d%d,s%d",d,s); + output_w32(0xeeb80bc0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fcvtds(int s,int d) +{ + assem_debug("fcvtds d%d,s%d",d,s); + output_w32(0xeeb70ac0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fcvtsd(int s,int d) +{ + assem_debug("fcvtsd s%d,d%d",d,s); + output_w32(0xeeb70bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); +} + +static void emit_fsqrts(int s,int d) +{ + assem_debug("fsqrts d%d,s%d",d,s); + output_w32(0xeeb10ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fsqrtd(int s,int d) +{ + assem_debug("fsqrtd s%d,d%d",d,s); + output_w32(0xeeb10bc0|((d&7)<<12)|(s&7)); +} + +static void emit_fabss(int s,int d) +{ + assem_debug("fabss d%d,s%d",d,s); + output_w32(0xeeb00ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fabsd(int s,int d) +{ + assem_debug("fabsd s%d,d%d",d,s); + output_w32(0xeeb00bc0|((d&7)<<12)|(s&7)); +} + +static void emit_fnegs(int s,int d) +{ + assem_debug("fnegs d%d,s%d",d,s); + output_w32(0xeeb10a40|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); +} + +static void emit_fnegd(int s,int d) +{ + assem_debug("fnegd s%d,d%d",d,s); + output_w32(0xeeb10b40|((d&7)<<12)|(s&7)); +} + +static void emit_fadds(int s1,int s2,int d) +{ + assem_debug("fadds s%d,s%d,s%d",d,s1,s2); + output_w32(0xee300a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); +} + +static void emit_faddd(int s1,int s2,int d) +{ + assem_debug("faddd d%d,d%d,d%d",d,s1,s2); + output_w32(0xee300b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); +} + +static void emit_fsubs(int s1,int s2,int d) +{ + assem_debug("fsubs s%d,s%d,s%d",d,s1,s2); + output_w32(0xee300a40|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); +} + +static void emit_fsubd(int s1,int s2,int d) +{ + assem_debug("fsubd d%d,d%d,d%d",d,s1,s2); + output_w32(0xee300b40|((d&7)<<12)|((s1&7)<<16)|(s2&7)); +} + +static void emit_fmuls(int s1,int s2,int d) +{ + assem_debug("fmuls s%d,s%d,s%d",d,s1,s2); + output_w32(0xee200a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); +} + +static void emit_fmuld(int s1,int s2,int d) +{ + assem_debug("fmuld d%d,d%d,d%d",d,s1,s2); + output_w32(0xee200b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); +} + +static void emit_fdivs(int s1,int s2,int d) +{ + assem_debug("fdivs s%d,s%d,s%d",d,s1,s2); + output_w32(0xee800a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); +} + +static void emit_fdivd(int s1,int s2,int d) +{ + assem_debug("fdivd d%d,d%d,d%d",d,s1,s2); + output_w32(0xee800b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); +} + +static void emit_fcmps(int x,int y) +{ + assem_debug("fcmps s14, s15"); + output_w32(0xeeb47a67); +} + +static void emit_fcmpd(int x,int y) +{ + assem_debug("fcmpd d6, d7"); + output_w32(0xeeb46b47); +} + +static void emit_fmstat() +{ + assem_debug("fmstat"); + output_w32(0xeef1fa10); +} + +static void emit_bicne_imm(int rs,int imm,int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("bicne %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_biccs_imm(int rs,int imm,int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("biccs %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_bicvc_imm(int rs,int imm,int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("bicvc %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_bichi_imm(int rs,int imm,int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("bichi %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_orrvs_imm(int rs,int imm,int rt) +{ + u_int armval, ret; + ret = genimm(imm,&armval); + assert(ret); + assem_debug("orrvs %s,%s,#%d",regname[rt],regname[rs],imm); + output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval); +} + +static void emit_jno_unlikely(int a) +{ + //emit_jno(a); + assem_debug("addvc pc,pc,#? (%x)",/*a-(int)out-8,*/a); + output_w32(0x72800000|rd_rn_rm(15,15,0)); +} + +// Save registers before function call +static void save_regs(u_int reglist) +{ + reglist&=0x100f; // only save the caller-save registers, r0-r3, r12 + if(!reglist) return; + assem_debug("stmia fp,{"); + if(reglist&1) assem_debug("r0, "); + if(reglist&2) assem_debug("r1, "); + if(reglist&4) assem_debug("r2, "); + if(reglist&8) assem_debug("r3, "); + if(reglist&0x1000) assem_debug("r12"); + assem_debug("}"); + output_w32(0xe88b0000|reglist); +} +// Restore registers after function call +static void restore_regs(u_int reglist) +{ + reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12 + if(!reglist) return; + assem_debug("ldmia fp,{"); + if(reglist&1) assem_debug("r0, "); + if(reglist&2) assem_debug("r1, "); + if(reglist&4) assem_debug("r2, "); + if(reglist&8) assem_debug("r3, "); + if(reglist&0x1000) assem_debug("r12"); + assem_debug("}"); + output_w32(0xe89b0000|reglist); +} + +// Write back consts using r14 so we don't disturb the other registers +static void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i) +{ + int hr; + for(hr=0;hr=0&&((i_dirty>>hr)&1)) { + if(((regs[i].isconst>>hr)&1)&&i_regmap[hr]>0) { + if(i_regmap[hr]<64 || !((i_is32>>(i_regmap[hr]&63))&1) ) { + int value=constmap[i][hr]; + if(value==0) { + emit_zeroreg(HOST_TEMPREG); + } + else { + emit_movimm(value,HOST_TEMPREG); + } + emit_storereg(i_regmap[hr],HOST_TEMPREG); + if((i_is32>>i_regmap[hr])&1) { + if(value!=-1&&value!=0) emit_sarimm(HOST_TEMPREG,31,HOST_TEMPREG); + emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); + } + } + } + } + } +} + +/* Stubs/epilogue */ + +static void literal_pool(int n) +{ + if(!literalcount) return; + if(n) { + if((int)out-literals[0][0]<4096-n) return; + } + u_int *ptr; + int i; + for(i=0;i=0x7000000&&addr<0x7FFFFFF); + //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000)); +//DEBUG > +#ifdef DEBUG_CYCLE_COUNT + emit_readword((int)&last_count,ECX); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); +#endif +//DEBUG < + emit_jmp(linker); +} + +static void emit_extjump(int addr, int target) +{ + emit_extjump2(addr, target, (int)dyna_linker); +} +static void emit_extjump_ds(int addr, int target) +{ + emit_extjump2(addr, target, (int)dyna_linker_ds); +} + +static void do_readstub(int n) +{ + assem_debug("do_readstub %x",start+stubs[n][3]*4); + literal_pool(256); + set_jump_target(stubs[n][1],(int)out); + int type=stubs[n][0]; + int i=stubs[n][3]; + int rs=stubs[n][4]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + u_int reglist=stubs[n][7]; + signed char *i_regmap=i_regs->regmap; + int addr=get_reg(i_regmap,AGEN1+(i&1)); + int rth,rt; + int ds; + if(itype[i]==C1LS||itype[i]==LOADLR) { + rth=get_reg(i_regmap,FTEMP|64); + rt=get_reg(i_regmap,FTEMP); + }else{ + rth=get_reg(i_regmap,rt1[i]|64); + rt=get_reg(i_regmap,rt1[i]); + } + assert(rs>=0); + if(addr<0) addr=rt; + if(addr<0&&itype[i]!=C1LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1); + assert(addr>=0); + int ftable=0; + if(type==LOADB_STUB||type==LOADBU_STUB) + ftable=(int)readmemb; + if(type==LOADH_STUB||type==LOADHU_STUB) + ftable=(int)readmemh; + if(type==LOADW_STUB) + ftable=(int)readmem; + if(type==LOADD_STUB) + ftable=(int)readmemd; + emit_writeword(rs,(int)&address); + //emit_pusha(); + save_regs(reglist); + ds=i_regs!=®s[i]; + int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]); + u_int cmask=ds?-1:(0x100f|~i_regs->wasconst); + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<>rs1[i])&1)<<1)+ds,3); + //emit_readword((int)&last_count,temp); + //emit_add(cc,temp,cc); + //emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + //emit_mov(15,14); + emit_call((int)&indirect_jump_indexed); + //emit_callreg(rs); + //emit_readword_dualindexedx4(rs,HOST_TEMPREG,15); + // We really shouldn't need to update the count here, + // but not doing so causes random crashes... + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_TEMPREG); + emit_readword((int)&next_interupt,2); + emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG); + emit_writeword(2,(int)&last_count); + emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); + if(cc<0) { + emit_storereg(CCREG,HOST_TEMPREG); + } + //emit_popa(); + restore_regs(reglist); + //if((cc=get_reg(regmap,CCREG))>=0) { + // emit_loadreg(CCREG,cc); + //} + if(rt>=0) { + if(type==LOADB_STUB) + emit_movsbl((int)&readmem_dword,rt); + if(type==LOADBU_STUB) + emit_movzbl((int)&readmem_dword,rt); + if(type==LOADH_STUB) + emit_movswl((int)&readmem_dword,rt); + if(type==LOADHU_STUB) + emit_movzwl((int)&readmem_dword,rt); + if(type==LOADW_STUB) + emit_readword((int)&readmem_dword,rt); + if(type==LOADD_STUB) { + emit_readword((int)&readmem_dword,rt); + if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth); + } + } + emit_jmp(stubs[n][2]); // return address +} + +static void inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) +{ + int rs=get_reg(regmap,target); + int rth=get_reg(regmap,target|64); + int rt=get_reg(regmap,target); + if(rs<0) rs=get_reg(regmap,-1); + assert(rs>=0); + int ftable=0; + if(type==LOADB_STUB||type==LOADBU_STUB) + ftable=(int)readmemb; + if(type==LOADH_STUB||type==LOADHU_STUB) + ftable=(int)readmemh; + if(type==LOADW_STUB) + ftable=(int)readmem; + if(type==LOADD_STUB) + ftable=(int)readmemd; + emit_writeword(rs,(int)&address); + //emit_pusha(); + save_regs(reglist); + if((signed int)addr>=(signed int)0xC0000000) { + // Theoretically we can have a pagefault here, if the TLB has never + // been enabled and the address is outside the range 80000000..BFFFFFFF + // Write out the registers so the pagefault can be handled. This is + // a very rare case and likely represents a bug. + int ds=regmap!=regs[i].regmap; + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty); + else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty); + } + //emit_shrimm(rs,16,1); + int cc=get_reg(regmap,CCREG); + if(cc<0) { + emit_loadreg(CCREG,2); + } + //emit_movimm(ftable,0); + emit_movimm(((u_int *)ftable)[addr>>16],0); + //emit_readword((int)&last_count,12); + emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + if((signed int)addr>=(signed int)0xC0000000) { + // Pagefault address + int ds=regmap!=regs[i].regmap; + emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3); + } + //emit_add(12,2,2); + //emit_writeword(2,(int)&g_cp0_regs[CP0_COUNT_REG]); + //emit_call(((u_int *)ftable)[addr>>16]); + emit_call((int)&indirect_jump); + // We really shouldn't need to update the count here, + // but not doing so causes random crashes... + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_TEMPREG); + emit_readword((int)&next_interupt,2); + emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_writeword(2,(int)&last_count); + emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); + if(cc<0) { + emit_storereg(CCREG,HOST_TEMPREG); + } + //emit_popa(); + restore_regs(reglist); + if(rt>=0) { + if(type==LOADB_STUB) + emit_movsbl((int)&readmem_dword,rt); + if(type==LOADBU_STUB) + emit_movzbl((int)&readmem_dword,rt); + if(type==LOADH_STUB) + emit_movswl((int)&readmem_dword,rt); + if(type==LOADHU_STUB) + emit_movzwl((int)&readmem_dword,rt); + if(type==LOADW_STUB) + emit_readword((int)&readmem_dword,rt); + if(type==LOADD_STUB) { + emit_readword((int)&readmem_dword,rt); + if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth); + } + } +} + +static void do_writestub(int n) +{ + assem_debug("do_writestub %x",start+stubs[n][3]*4); + literal_pool(256); + set_jump_target(stubs[n][1],(int)out); + int type=stubs[n][0]; + int i=stubs[n][3]; + int rs=stubs[n][4]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + u_int reglist=stubs[n][7]; + signed char *i_regmap=i_regs->regmap; + int addr=get_reg(i_regmap,AGEN1+(i&1)); + int rth,rt,r; + int ds; + if(itype[i]==C1LS) { + rth=get_reg(i_regmap,FTEMP|64); + rt=get_reg(i_regmap,r=FTEMP); + }else{ + rth=get_reg(i_regmap,rs2[i]|64); + rt=get_reg(i_regmap,r=rs2[i]); + } + assert(rs>=0); + assert(rt>=0); + if(addr<0) addr=get_reg(i_regmap,-1); + assert(addr>=0); + int ftable=0; + if(type==STOREB_STUB) + ftable=(int)writememb; + if(type==STOREH_STUB) + ftable=(int)writememh; + if(type==STOREW_STUB) + ftable=(int)writemem; + if(type==STORED_STUB) + ftable=(int)writememd; + emit_writeword(rs,(int)&address); + //emit_shrimm(rs,16,rs); + //emit_movmem_indexedx4(ftable,rs,rs); + if(type==STOREB_STUB) + emit_writebyte(rt,(int)&cpu_byte); + if(type==STOREH_STUB) + emit_writehword(rt,(int)&cpu_hword); + if(type==STOREW_STUB) + emit_writeword(rt,(int)&cpu_word); + if(type==STORED_STUB) { + emit_writeword(rt,(int)&cpu_dword); + emit_writeword(r?rth:rt,(int)&cpu_dword+4); + } + //emit_pusha(); + save_regs(reglist); + ds=i_regs!=®s[i]; + int real_rs=get_reg(i_regmap,rs1[i]); + u_int cmask=ds?-1:(0x100f|~i_regs->wasconst); + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<>rs1[i])&1)<<1)+ds,3); + //emit_readword((int)&last_count,temp); + //emit_addimm(cc,2*stubs[n][5]+2,cc); + //emit_add(cc,temp,cc); + //emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)&indirect_jump_indexed); + //emit_callreg(rs); + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_TEMPREG); + emit_readword((int)&next_interupt,2); + emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG); + emit_writeword(2,(int)&last_count); + emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); + if(cc<0) { + emit_storereg(CCREG,HOST_TEMPREG); + } + //emit_popa(); + restore_regs(reglist); + //if((cc=get_reg(regmap,CCREG))>=0) { + // emit_loadreg(CCREG,cc); + //} + emit_jmp(stubs[n][2]); // return address +} + +static void inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) +{ + int rs=get_reg(regmap,-1); + int rth=get_reg(regmap,target|64); + int rt=get_reg(regmap,target); + assert(rs>=0); + assert(rt>=0); + int ftable=0; + if(type==STOREB_STUB) + ftable=(int)writememb; + if(type==STOREH_STUB) + ftable=(int)writememh; + if(type==STOREW_STUB) + ftable=(int)writemem; + if(type==STORED_STUB) + ftable=(int)writememd; + emit_writeword(rs,(int)&address); + //emit_shrimm(rs,16,rs); + //emit_movmem_indexedx4(ftable,rs,rs); + if(type==STOREB_STUB) + emit_writebyte(rt,(int)&cpu_byte); + if(type==STOREH_STUB) + emit_writehword(rt,(int)&cpu_hword); + if(type==STOREW_STUB) + emit_writeword(rt,(int)&cpu_word); + if(type==STORED_STUB) { + emit_writeword(rt,(int)&cpu_dword); + emit_writeword(target?rth:rt,(int)&cpu_dword+4); + } + //emit_pusha(); + save_regs(reglist); + if((signed int)addr>=(signed int)0xC0000000) { + // Theoretically we can have a pagefault here, if the TLB has never + // been enabled and the address is outside the range 80000000..BFFFFFFF + // Write out the registers so the pagefault can be handled. This is + // a very rare case and likely represents a bug. + int ds=regmap!=regs[i].regmap; + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty); + else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty); + } + //emit_shrimm(rs,16,1); + int cc=get_reg(regmap,CCREG); + if(cc<0) { + emit_loadreg(CCREG,2); + } + //emit_movimm(ftable,0); + emit_movimm(((u_int *)ftable)[addr>>16],0); + //emit_readword((int)&last_count,12); + emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + if((signed int)addr>=(signed int)0xC0000000) { + // Pagefault address + int ds=regmap!=regs[i].regmap; + emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3); + } + //emit_add(12,2,2); + //emit_writeword(2,(int)&g_cp0_regs[CP0_COUNT_REG]); + //emit_call(((u_int *)ftable)[addr>>16]); + emit_call((int)&indirect_jump); + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_TEMPREG); + emit_readword((int)&next_interupt,2); + emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_writeword(2,(int)&last_count); + emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); + if(cc<0) { + emit_storereg(CCREG,HOST_TEMPREG); + } + //emit_popa(); + restore_regs(reglist); +} + +static void do_unalignedwritestub(int n) +{ + set_jump_target(stubs[n][1],(int)out); + output_w32(0xef000000); + emit_jmp(stubs[n][2]); // return address +} + +void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a) +{ + DebugMessage(M64MSG_VERBOSE, "regs: %x %x %x %x %x %x %x (%x)",a,b,c,d,ebp,esi,edi,(&edi)[-1]); +} + +static void do_invstub(int n) +{ + literal_pool(20); + u_int reglist=stubs[n][3]; + set_jump_target(stubs[n][1],(int)out); + save_regs(reglist); + if(stubs[n][4]!=0) emit_mov(stubs[n][4],0); + emit_call((int)&invalidate_addr); + restore_regs(reglist); + emit_jmp(stubs[n][2]); // return address +} + +static int do_dirty_stub(int i) +{ + assem_debug("do_dirty_stub %x",start+i*4); + // Careful about the code output here, verify_dirty needs to parse it. + #ifdef ARMv5_ONLY + emit_loadlp((int)start<(int)0xC0000000?(int)source:(int)start,1); + emit_loadlp((int)copy,2); + emit_loadlp(slen*4,3); + #else + emit_movw(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0x0000FFFF,1); + emit_movw(((u_int)copy)&0x0000FFFF,2); + emit_movt(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0xFFFF0000,1); + emit_movt(((u_int)copy)&0xFFFF0000,2); + emit_movw(slen*4,3); + #endif + emit_movimm(start+i*4,0); + emit_call((int)start<(int)0xC0000000?(int)&verify_code:(int)&verify_code_vm); + int entry=(int)out; + load_regs_entry(i); + if(entry==(int)out) entry=instr_addr[i]; + emit_jmp(instr_addr[i]); + return entry; +} + +static void do_dirty_stub_ds() +{ + // Careful about the code output here, verify_dirty needs to parse it. + #ifdef ARMv5_ONLY + emit_loadlp((int)start<(int)0xC0000000?(int)source:(int)start,1); + emit_loadlp((int)copy,2); + emit_loadlp(slen*4,3); + #else + emit_movw(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0x0000FFFF,1); + emit_movw(((u_int)copy)&0x0000FFFF,2); + emit_movt(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0xFFFF0000,1); + emit_movt(((u_int)copy)&0xFFFF0000,2); + emit_movw(slen*4,3); + #endif + emit_movimm(start+1,0); + emit_call((int)&verify_code_ds); +} + +static void do_cop1stub(int n) +{ + literal_pool(256); + assem_debug("do_cop1stub %x",start+stubs[n][3]*4); + set_jump_target(stubs[n][1],(int)out); + int i=stubs[n][3]; + int rs=stubs[n][4]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + int ds=stubs[n][6]; + if(!ds) { + load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + //if(i_regs!=®s[i]) DebugMessage(M64MSG_VERBOSE, "oops: regs[i]=%x i_regs=%x",(int)®s[i],(int)i_regs); + } + //else {DebugMessage(M64MSG_ERROR, "fp exception in delay slot");} + wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); + if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_movimm(start+(i-ds)*4,EAX); // Get PC + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... + emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception); +} + +/* TLB */ + +static int do_tlb_r(int s,int ar,int map,int cache,int x,int a,int shift,int c,u_int addr) +{ + if(c) { + if((signed int)addr>=(signed int)0xC0000000) { + // address_generation already loaded the const + emit_readword_dualindexedx4(FP,map,map); + } + else + return -1; // No mapping + } + else { + assert(s!=map); + if(cache>=0) { + // Use cached offset to memory map + emit_addsr12(cache,s,map); + }else{ + emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map); + emit_addsr12(map,s,map); + } + // Schedule this while we wait on the load + //if(x) emit_xorimm(s,x,ar); + if(shift>=0) emit_shlimm(s,3,shift); + if(~a) emit_andimm(s,a,ar); + emit_readword_dualindexedx4(FP,map,map); + } + return map; +} +static int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr) +{ + if(!c||(signed int)addr>=(signed int)0xC0000000) { + emit_test(map,map); + *jaddr=(int)out; + emit_js(0); + } + return map; +} + +static void gen_tlb_addr_r(int ar, int map) { + if(map>=0) { + assem_debug("add %s,%s,%s lsl #2",regname[ar],regname[ar],regname[map]); + output_w32(0xe0800100|rd_rn_rm(ar,ar,map)); + } +} + +static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) +{ + if(c) { + if(addr<0x80800000||addr>=0xC0000000) { + // address_generation already loaded the const + emit_readword_dualindexedx4(FP,map,map); + } + else + return -1; // No mapping + } + else { + assert(s!=map); + if(cache>=0) { + // Use cached offset to memory map + emit_addsr12(cache,s,map); + }else{ + emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map); + emit_addsr12(map,s,map); + } + // Schedule this while we wait on the load + //if(x) emit_xorimm(s,x,ar); + emit_readword_dualindexedx4(FP,map,map); + } + return map; +} +static void do_tlb_w_branch(int map, int c, u_int addr, int *jaddr) +{ + if(!c||addr<0x80800000||addr>=0xC0000000) { + emit_testimm(map,0x40000000); + *jaddr=(int)out; + emit_jne(0); + } +} + +static void gen_tlb_addr_w(int ar, int map) { + if(map>=0) { + assem_debug("add %s,%s,%s lsl #2",regname[ar],regname[ar],regname[map]); + output_w32(0xe0800100|rd_rn_rm(ar,ar,map)); + } +} + +// This reverses the above operation +static void gen_orig_addr_w(int ar, int map) { + if(map>=0) { + assem_debug("sub %s,%s,%s lsl #2",regname[ar],regname[ar],regname[map]); + output_w32(0xe0400100|rd_rn_rm(ar,ar,map)); + } +} + +// Generate the address of the memory_map entry, relative to dynarec_local +static void generate_map_const(u_int addr,int reg) { + //DebugMessage(M64MSG_VERBOSE, "generate_map_const(%x,%s)",addr,regname[reg]); + emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg); +} + +/* Special assem */ + +static void shift_assemble_arm(int i,struct regstat *i_regs) +{ + if(rt1[i]) { + if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV + { + signed char s,t,shift; + t=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + shift=get_reg(i_regs->regmap,rs2[i]); + if(t>=0){ + if(rs1[i]==0) + { + emit_zeroreg(t); + } + else if(rs2[i]==0) + { + assert(s>=0); + if(s!=t) emit_mov(s,t); + } + else + { + emit_andimm(shift,31,HOST_TEMPREG); + if(opcode2[i]==4) // SLLV + { + emit_shl(s,HOST_TEMPREG,t); + } + if(opcode2[i]==6) // SRLV + { + emit_shr(s,HOST_TEMPREG,t); + } + if(opcode2[i]==7) // SRAV + { + emit_sar(s,HOST_TEMPREG,t); + } + } + } + } else { // DSLLV/DSRLV/DSRAV + signed char sh,sl,th,tl,shift; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + shift=get_reg(i_regs->regmap,rs2[i]); + if(tl>=0){ + if(rs1[i]==0) + { + emit_zeroreg(tl); + if(th>=0) emit_zeroreg(th); + } + else if(rs2[i]==0) + { + assert(sl>=0); + if(sl!=tl) emit_mov(sl,tl); + if(th>=0&&sh!=th) emit_mov(sh,th); + } + else + { + // FIXME: What if shift==tl ? + assert(shift!=tl); + int temp=get_reg(i_regs->regmap,-1); + int real_th=th; + if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register + assert(sl>=0); + assert(sh>=0); + emit_andimm(shift,31,HOST_TEMPREG); + if(opcode2[i]==0x14) // DSLLV + { + if(th>=0) emit_shl(sh,HOST_TEMPREG,th); + emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); + emit_orrshr(sl,HOST_TEMPREG,th); + emit_andimm(shift,31,HOST_TEMPREG); + emit_testimm(shift,32); + emit_shl(sl,HOST_TEMPREG,tl); + if(th>=0) emit_cmovne_reg(tl,th); + emit_cmovne_imm(0,tl); + } + if(opcode2[i]==0x16) // DSRLV + { + assert(th>=0); + emit_shr(sl,HOST_TEMPREG,tl); + emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); + emit_orrshl(sh,HOST_TEMPREG,tl); + emit_andimm(shift,31,HOST_TEMPREG); + emit_testimm(shift,32); + emit_shr(sh,HOST_TEMPREG,th); + emit_cmovne_reg(th,tl); + if(real_th>=0) emit_cmovne_imm(0,th); + } + if(opcode2[i]==0x17) // DSRAV + { + assert(th>=0); + emit_shr(sl,HOST_TEMPREG,tl); + emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); + if(real_th>=0) { + assert(temp>=0); + emit_sarimm(th,31,temp); + } + emit_orrshl(sh,HOST_TEMPREG,tl); + emit_andimm(shift,31,HOST_TEMPREG); + emit_testimm(shift,32); + emit_sar(sh,HOST_TEMPREG,th); + emit_cmovne_reg(th,tl); + if(real_th>=0) emit_cmovne_reg(temp,th); + } + } + } + } + } +} +#define shift_assemble shift_assemble_arm + +static void loadlr_assemble_arm(int i,struct regstat *i_regs) +{ + int s,th,tl,temp,temp2,addr,map=-1,cache=-1; + int offset; + int jaddr=0; + int memtarget,c=0; + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + temp=get_reg(i_regs->regmap,-1); + temp2=get_reg(i_regs->regmap,FTEMP); + addr=get_reg(i_regs->regmap,AGEN1+(i&1)); + assert(addr<0); + offset=imm[i]; + for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { + c=(i_regs->wasconst>>s)&1; + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } + if(!using_tlb) { + if(!c) { + #ifdef RAM_OFFSET + map=get_reg(i_regs->regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + #endif + emit_shlimm(addr,3,temp); + if (opcode[i]==0x22||opcode[i]==0x26) { + emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR + }else{ + emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR + } + emit_cmpimm(addr,0x800000); + jaddr=(int)out; + emit_jno(0); + } + else { + if (opcode[i]==0x22||opcode[i]==0x26) { + emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR + }else{ + emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR + } + } + }else{ // using tlb + int a; + if(c) { + a=-1; + }else if (opcode[i]==0x22||opcode[i]==0x26) { + a=0xFFFFFFFC; // LWL/LWR + }else{ + a=0xFFFFFFF8; // LDL/LDR + } + map=get_reg(i_regs->regmap,TLREG); + cache=get_reg(i_regs->regmap,MMREG); // Get cached offset to memory_map + assert(map>=0); + reglist&=~(1<regmap,FTEMP,ccadj[i],reglist); + if(rt1[i]) { + assert(tl>=0); + emit_andimm(temp,24,temp); + if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR + emit_movimm(-1,HOST_TEMPREG); + if (opcode[i]==0x26) { + emit_shr(temp2,temp,temp2); + emit_bic_lsr(tl,HOST_TEMPREG,temp,tl); + }else{ + emit_shl(temp2,temp,temp2); + emit_bic_lsl(tl,HOST_TEMPREG,temp,tl); + } + emit_or(temp2,tl,tl); + } + //emit_storereg(rt1[i],tl); // DEBUG + } + if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR + int temp2h=get_reg(i_regs->regmap,FTEMP|64); + if(!c||memtarget) { + //if(th>=0) emit_readword_indexed((int)g_rdram-0x80000000,temp2,temp2h); + //emit_readword_indexed((int)g_rdram-0x7FFFFFFC,temp2,temp2); + emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); + if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist); + if(rt1[i]) { + assert(th>=0); + assert(tl>=0); + emit_testimm(temp,32); + emit_andimm(temp,24,temp); + if (opcode[i]==0x1A) { // LDL + emit_rsbimm(temp,32,HOST_TEMPREG); + emit_shl(temp2h,temp,temp2h); + emit_orrshr(temp2,HOST_TEMPREG,temp2h); + emit_movimm(-1,HOST_TEMPREG); + emit_shl(temp2,temp,temp2); + emit_cmove_reg(temp2h,th); + emit_biceq_lsl(tl,HOST_TEMPREG,temp,tl); + emit_bicne_lsl(th,HOST_TEMPREG,temp,th); + emit_orreq(temp2,tl,tl); + emit_orrne(temp2,th,th); + } + if (opcode[i]==0x1B) { // LDR + emit_xorimm(temp,24,temp); + emit_rsbimm(temp,32,HOST_TEMPREG); + emit_shr(temp2,temp,temp2); + emit_orrshl(temp2h,HOST_TEMPREG,temp2); + emit_movimm(-1,HOST_TEMPREG); + emit_shr(temp2h,temp,temp2h); + emit_cmovne_reg(temp2,tl); + emit_bicne_lsr(th,HOST_TEMPREG,temp,th); + emit_biceq_lsr(tl,HOST_TEMPREG,temp,tl); + emit_orrne(temp2h,th,th); + emit_orreq(temp2h,tl,tl); + } + } + } +} +#define loadlr_assemble loadlr_assemble_arm + +static void cop0_assemble(int i,struct regstat *i_regs) +{ + if(opcode2[i]==0) // MFC0 + { + if(rt1[i]) { + signed char t=get_reg(i_regs->regmap,rt1[i]); + char copr=(source[i]>>11)&0x1f; + if(t>=0) { + emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0); + emit_movimm((source[i]>>11)&0x1f,1); + emit_writeword(0,(int)&PC); + emit_writebyte(1,(int)&(fake_pc.f.r.nrd)); + if(copr==9) { + emit_readword((int)&last_count,ECX); + emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + } + emit_call((int)cached_interpreter_table.MFC0); + emit_readword((int)&readmem_dword,t); + } + } + } + else if(opcode2[i]==4) // MTC0 + { + signed char s=get_reg(i_regs->regmap,rs1[i]); + char copr=(source[i]>>11)&0x1f; + assert(s>=0); + emit_writeword(s,(int)&readmem_dword); + wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); + emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0); + emit_movimm((source[i]>>11)&0x1f,1); + emit_writeword(0,(int)&PC); + emit_writebyte(1,(int)&(fake_pc.f.r.nrd)); + if(copr==9||copr==11||copr==12) { + emit_readword((int)&last_count,ECX); + emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + } + // What a mess. The status register (12) can enable interrupts, + // so needs a special case to handle a pending interrupt. + // The interrupt must be taken immediately, because a subsequent + // instruction might disable interrupts again. + if(copr==12&&!is_delayslot) { + emit_movimm(start+i*4+4,0); + emit_movimm(0,1); + emit_writeword(0,(int)&pcaddr); + emit_writeword(1,(int)&pending_exception); + } + //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12); + //else + emit_call((int)cached_interpreter_table.MTC0); + if(copr==9||copr==11||copr==12) { + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + } + if(copr==12) { + assert(!is_delayslot); + emit_readword((int)&pending_exception,14); + } + emit_loadreg(rs1[i],s); + if(get_reg(i_regs->regmap,rs1[i]|64)>=0) + emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64)); + if(copr==12) { + emit_test(14,14); + emit_jne((int)&do_interrupt); + } + cop1_usable=0; + } + else + { + assert(opcode2[i]==0x10); + if((source[i]&0x3f)==0x01) // TLBR + emit_call((int)cached_interpreter_table.TLBR); + if((source[i]&0x3f)==0x02) // TLBWI + emit_call((int)TLBWI_new); + if((source[i]&0x3f)==0x06) { // TLBWR + // The TLB entry written by TLBWR is dependent on the count, + // so update the cycle count + emit_readword((int)&last_count,ECX); + if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)TLBWR_new); + } + if((source[i]&0x3f)==0x08) // TLBP + emit_call((int)cached_interpreter_table.TLBP); + if((source[i]&0x3f)==0x18) // ERET + { + int count=ccadj[i]; + if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here? + emit_jmp((int)jump_eret); + } + } +} + +static void cop1_assemble(int i,struct regstat *i_regs) +{ + // Check cop1 unusable + if(!cop1_usable) { + signed char rs=get_reg(i_regs->regmap,CSREG); + assert(rs>=0); + emit_testimm(rs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + if (opcode2[i]==0) { // MFC1 + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],tl); + emit_readword_indexed(0,tl,tl); + } + } + else if (opcode2[i]==1) { // DMFC1 + signed char tl=get_reg(i_regs->regmap,rt1[i]); + signed char th=get_reg(i_regs->regmap,rt1[i]|64); + if(tl>=0) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],tl); + if(th>=0) emit_readword_indexed(4,tl,th); + emit_readword_indexed(0,tl,tl); + } + } + else if (opcode2[i]==4) { // MTC1 + signed char sl=get_reg(i_regs->regmap,rs1[i]); + signed char temp=get_reg(i_regs->regmap,-1); + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_writeword_indexed(sl,0,temp); + } + else if (opcode2[i]==5) { // DMTC1 + signed char sl=get_reg(i_regs->regmap,rs1[i]); + signed char sh=rs1[i]>0?get_reg(i_regs->regmap,rs1[i]|64):sl; + signed char temp=get_reg(i_regs->regmap,-1); + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_writeword_indexed(sh,4,temp); + emit_writeword_indexed(sl,0,temp); + } + else if (opcode2[i]==2) // CFC1 + { + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) { + u_int copr=(source[i]>>11)&0x1f; + if(copr==0) emit_readword((int)&FCR0,tl); + if(copr==31) emit_readword((int)&FCR31,tl); + } + } + else if (opcode2[i]==6) // CTC1 + { + signed char sl=get_reg(i_regs->regmap,rs1[i]); + u_int copr=(source[i]>>11)&0x1f; + assert(sl>=0); + if(copr==31) + { + emit_writeword(sl,(int)&FCR31); + // Set the rounding mode + //FIXME + //char temp=get_reg(i_regs->regmap,-1); + //emit_andimm(sl,3,temp); + //emit_fldcw_indexed((int)&rounding_modes,temp); + } + } +} + +static void fconv_assemble_arm(int i,struct regstat *i_regs) +{ + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char rs=get_reg(i_regs->regmap,CSREG); + assert(rs>=0); + emit_testimm(rs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + + #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp,15); + emit_ftosizs(15,15); // float->int, truncate + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fsts(15,temp); + return; + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_vldr(temp,7); + emit_ftosizd(7,13); // double->int, truncate + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fsts(13,temp); + return; + } + + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp,13); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fsitos(13,15); + emit_fsts(15,temp); + return; + } + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp,13); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fsitod(13,7); + emit_vstr(7,temp); + return; + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp,13); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fcvtds(13,7); + emit_vstr(7,temp); + return; + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_vldr(temp,7); + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fcvtsd(7,13); + emit_fsts(13,temp); + return; + } + #endif + + // C emulation code + + u_int hr,reglist=0; + for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_s_w); + } + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_d_w); + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_s_l); + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_d_l); + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_d_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_l_s); + } + + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_s_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)cvt_l_d); + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)round_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)trunc_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)ceil_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)floor_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)round_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)trunc_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)ceil_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)floor_w_s); + } + + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)round_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)trunc_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)ceil_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)floor_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)round_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)trunc_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)ceil_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + emit_call((int)floor_w_d); + } + + restore_regs(reglist); +} +#define fconv_assemble fconv_assemble_arm + +static void fcomp_assemble(int i,struct regstat *i_regs) +{ + signed char fs=get_reg(i_regs->regmap,FSREG); + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char cs=get_reg(i_regs->regmap,CSREG); + assert(cs>=0); + emit_testimm(cs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + + if((source[i]&0x3f)==0x30) { + emit_andimm(fs,~0x800000,fs); + return; + } + + if((source[i]&0x3e)==0x38) { + // sf/ngle - these should throw exceptions for NaNs + emit_andimm(fs,~0x800000,fs); + return; + } + + #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); + emit_orimm(fs,0x800000,fs); + emit_flds(temp,14); + emit_flds(HOST_TEMPREG,15); + emit_fcmps(14,15); + emit_fmstat(); + if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_s + if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_s + if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_s + if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_s + if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_s + if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_s + if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_s + if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_s + if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_s + if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_s + if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_s + if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_s + if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_s + return; + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],HOST_TEMPREG); + emit_orimm(fs,0x800000,fs); + emit_vldr(temp,6); + emit_vldr(HOST_TEMPREG,7); + emit_fcmpd(6,7); + emit_fmstat(); + if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_d + if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_d + if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_d + if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_d + if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_d + if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_d + if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_d + if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_d + if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_d + if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_d + if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_d + if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_d + if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_d + return; + } + #endif + + // C only + + u_int hr,reglist=0; + for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],ARG2_REG); + if((source[i]&0x3f)==0x30) emit_call((int)c_f_s); + if((source[i]&0x3f)==0x31) emit_call((int)c_un_s); + if((source[i]&0x3f)==0x32) emit_call((int)c_eq_s); + if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_s); + if((source[i]&0x3f)==0x34) emit_call((int)c_olt_s); + if((source[i]&0x3f)==0x35) emit_call((int)c_ult_s); + if((source[i]&0x3f)==0x36) emit_call((int)c_ole_s); + if((source[i]&0x3f)==0x37) emit_call((int)c_ule_s); + if((source[i]&0x3f)==0x38) emit_call((int)c_sf_s); + if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_s); + if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_s); + if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_s); + if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_s); + if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_s); + if((source[i]&0x3f)==0x3e) emit_call((int)c_le_s); + if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_s); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],ARG2_REG); + if((source[i]&0x3f)==0x30) emit_call((int)c_f_d); + if((source[i]&0x3f)==0x31) emit_call((int)c_un_d); + if((source[i]&0x3f)==0x32) emit_call((int)c_eq_d); + if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_d); + if((source[i]&0x3f)==0x34) emit_call((int)c_olt_d); + if((source[i]&0x3f)==0x35) emit_call((int)c_ult_d); + if((source[i]&0x3f)==0x36) emit_call((int)c_ole_d); + if((source[i]&0x3f)==0x37) emit_call((int)c_ule_d); + if((source[i]&0x3f)==0x38) emit_call((int)c_sf_d); + if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_d); + if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_d); + if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_d); + if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_d); + if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_d); + if((source[i]&0x3f)==0x3e) emit_call((int)c_le_d); + if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_d); + } + restore_regs(reglist); + emit_loadreg(FSREG,fs); +} + +static void float_assemble(int i,struct regstat *i_regs) +{ + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char cs=get_reg(i_regs->regmap,CSREG); + assert(cs>=0); + emit_testimm(cs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + + #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + if((source[i]&0x3f)==6) // mov + { + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],HOST_TEMPREG); + emit_readword_indexed(0,temp,temp); + emit_writeword_indexed(temp,0,HOST_TEMPREG); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],HOST_TEMPREG); + emit_vldr(temp,7); + emit_vstr(7,HOST_TEMPREG); + } + } + return; + } + + if((source[i]&0x3f)>3) + { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp,15); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + } + if((source[i]&0x3f)==4) // sqrt + emit_fsqrts(15,15); + if((source[i]&0x3f)==5) // abs + emit_fabss(15,15); + if((source[i]&0x3f)==7) // neg + emit_fnegs(15,15); + emit_fsts(15,temp); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_vldr(temp,7); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + } + if((source[i]&0x3f)==4) // sqrt + emit_fsqrtd(7,7); + if((source[i]&0x3f)==5) // abs + emit_fabsd(7,7); + if((source[i]&0x3f)==7) // neg + emit_fnegd(7,7); + emit_vstr(7,temp); + } + return; + } + if((source[i]&0x3f)<4) + { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + } + if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); + emit_flds(temp,15); + emit_flds(HOST_TEMPREG,13); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + } + } + if((source[i]&0x3f)==0) emit_fadds(15,13,15); + if((source[i]&0x3f)==1) emit_fsubs(15,13,15); + if((source[i]&0x3f)==2) emit_fmuls(15,13,15); + if((source[i]&0x3f)==3) emit_fdivs(15,13,15); + if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { + emit_fsts(15,HOST_TEMPREG); + }else{ + emit_fsts(15,temp); + } + } + else if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],HOST_TEMPREG); + emit_vldr(temp,7); + emit_vldr(HOST_TEMPREG,6); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + } + } + if((source[i]&0x3f)==0) emit_faddd(7,6,7); + if((source[i]&0x3f)==1) emit_fsubd(7,6,7); + if((source[i]&0x3f)==2) emit_fmuld(7,6,7); + if((source[i]&0x3f)==3) emit_fdivd(7,6,7); + if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { + emit_vstr(7,HOST_TEMPREG); + }else{ + emit_vstr(7,temp); + } + } + } + else { + if(opcode2[i]==0x10) { + emit_flds(temp,15); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + } + if((source[i]&0x3f)==0) emit_fadds(15,15,15); + if((source[i]&0x3f)==1) emit_fsubs(15,15,15); + if((source[i]&0x3f)==2) emit_fmuls(15,15,15); + if((source[i]&0x3f)==3) emit_fdivs(15,15,15); + emit_fsts(15,temp); + } + else if(opcode2[i]==0x11) { + emit_vldr(temp,7); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + } + if((source[i]&0x3f)==0) emit_faddd(7,7,7); + if((source[i]&0x3f)==1) emit_fsubd(7,7,7); + if((source[i]&0x3f)==2) emit_fmuld(7,7,7); + if((source[i]&0x3f)==3) emit_fdivd(7,7,7); + emit_vstr(7,temp); + } + } + return; + } + #endif + + u_int hr,reglist=0; + for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG1_REG); + if((source[i]&0x3f)<4) { + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],ARG2_REG); + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG3_REG); + }else{ + emit_readword((int)®_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG); + } + switch(source[i]&0x3f) + { + case 0x00: emit_call((int)add_s);break; + case 0x01: emit_call((int)sub_s);break; + case 0x02: emit_call((int)mul_s);break; + case 0x03: emit_call((int)div_s);break; + case 0x04: emit_call((int)sqrt_s);break; + case 0x05: emit_call((int)abs_s);break; + case 0x06: emit_call((int)mov_s);break; + case 0x07: emit_call((int)neg_s);break; + } + restore_regs(reglist); + } + if(opcode2[i]==0x11) { // Double precision + save_regs(reglist); + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],ARG1_REG); + if((source[i]&0x3f)<4) { + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],ARG2_REG); + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG3_REG); + }else{ + emit_readword((int)®_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG); + } + switch(source[i]&0x3f) + { + case 0x00: emit_call((int)add_d);break; + case 0x01: emit_call((int)sub_d);break; + case 0x02: emit_call((int)mul_d);break; + case 0x03: emit_call((int)div_d);break; + case 0x04: emit_call((int)sqrt_d);break; + case 0x05: emit_call((int)abs_d);break; + case 0x06: emit_call((int)mov_d);break; + case 0x07: emit_call((int)neg_d);break; + } + restore_regs(reglist); + } +} + +static void multdiv_assemble_arm(int i,struct regstat *i_regs) +{ + // case 0x18: MULT + // case 0x19: MULTU + // case 0x1A: DIV + // case 0x1B: DIVU + // case 0x1C: DMULT + // case 0x1D: DMULTU + // case 0x1E: DDIV + // case 0x1F: DDIVU + if(rs1[i]&&rs2[i]) + { + if((opcode2[i]&4)==0) // 32-bit + { + if(opcode2[i]==0x18) // MULT + { + signed char m1=get_reg(i_regs->regmap,rs1[i]); + signed char m2=get_reg(i_regs->regmap,rs2[i]); + signed char hi=get_reg(i_regs->regmap,HIREG); + signed char lo=get_reg(i_regs->regmap,LOREG); + assert(m1>=0); + assert(m2>=0); + assert(hi>=0); + assert(lo>=0); + emit_smull(m1,m2,hi,lo); + } + if(opcode2[i]==0x19) // MULTU + { + signed char m1=get_reg(i_regs->regmap,rs1[i]); + signed char m2=get_reg(i_regs->regmap,rs2[i]); + signed char hi=get_reg(i_regs->regmap,HIREG); + signed char lo=get_reg(i_regs->regmap,LOREG); + assert(m1>=0); + assert(m2>=0); + assert(hi>=0); + assert(lo>=0); + emit_umull(m1,m2,hi,lo); + } + if(opcode2[i]==0x1A) // DIV + { + signed char d1=get_reg(i_regs->regmap,rs1[i]); + signed char d2=get_reg(i_regs->regmap,rs2[i]); + assert(d1>=0); + assert(d2>=0); + signed char quotient=get_reg(i_regs->regmap,LOREG); + signed char remainder=get_reg(i_regs->regmap,HIREG); + assert(quotient>=0); + assert(remainder>=0); + emit_movs(d1,remainder); + emit_negmi(remainder,remainder); + emit_movs(d2,HOST_TEMPREG); + emit_jeq((int)out+52); // Division by zero + emit_negmi(HOST_TEMPREG,HOST_TEMPREG); + emit_clz(HOST_TEMPREG,quotient); + emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG); + emit_orimm(quotient,1<<31,quotient); + emit_shr(quotient,quotient,quotient); + emit_cmp(remainder,HOST_TEMPREG); + emit_subcs(remainder,HOST_TEMPREG,remainder); + emit_adcs(quotient,quotient,quotient); + emit_shrimm(HOST_TEMPREG,1,HOST_TEMPREG); + emit_jcc((int)out-16); // -4 + emit_teq(d1,d2); + emit_negmi(quotient,quotient); + emit_test(d1,d1); + emit_negmi(remainder,remainder); + } + if(opcode2[i]==0x1B) // DIVU + { + signed char d1=get_reg(i_regs->regmap,rs1[i]); // dividend + signed char d2=get_reg(i_regs->regmap,rs2[i]); // divisor + assert(d1>=0); + assert(d2>=0); + signed char quotient=get_reg(i_regs->regmap,LOREG); + signed char remainder=get_reg(i_regs->regmap,HIREG); + assert(quotient>=0); + assert(remainder>=0); + emit_test(d2,d2); + emit_jeq((int)out+44); // Division by zero + emit_clz(d2,HOST_TEMPREG); + emit_movimm(1<<31,quotient); + emit_shl(d2,HOST_TEMPREG,d2); + emit_mov(d1,remainder); + emit_shr(quotient,HOST_TEMPREG,quotient); + emit_cmp(remainder,d2); + emit_subcs(remainder,d2,remainder); + emit_adcs(quotient,quotient,quotient); + emit_shrcc_imm(d2,1,d2); + emit_jcc((int)out-16); // -4 + } + } + else // 64-bit + { + if(opcode2[i]==0x1C) // DMULT + { + signed char m1h=get_reg(i_regs->regmap,rs1[i]|64); + signed char m1l=get_reg(i_regs->regmap,rs1[i]); + signed char m2h=get_reg(i_regs->regmap,rs2[i]|64); + signed char m2l=get_reg(i_regs->regmap,rs2[i]); + assert(m1h>=0); + assert(m2h>=0); + assert(m1l>=0); + assert(m2l>=0); + signed char rh=get_reg(i_regs->regmap,HIREG|64); + signed char rl=get_reg(i_regs->regmap,HIREG); + assert(rh>=0); + assert(rl>=0); + + emit_umull(m1l,m2l,rh,rl); + emit_storereg(LOREG,rl); + emit_mov(rh,rl); + emit_zeroreg(rh); + emit_smlal(m1l,m2h,rh,rl); + emit_mov(rh,HOST_TEMPREG); + emit_testimm(m1l,0x80000000); + emit_addne(HOST_TEMPREG,m2h,HOST_TEMPREG); + emit_zeroreg(rh); + emit_smlal(m1h,m2l,rh,rl); + emit_testimm(m2l,0x80000000); + emit_addne(rh,m1h,rh); + emit_storereg(LOREG|64,rl); + emit_sarimm(HOST_TEMPREG,31,rl); + emit_adds(HOST_TEMPREG,rh,HOST_TEMPREG); + emit_addsarimm(rl,rh,rh,31); + emit_mov(HOST_TEMPREG,rl); + emit_smlal(m1h,m2h,rh,rl); + } + if(opcode2[i]==0x1D) // DMULTU + { + signed char m1h=get_reg(i_regs->regmap,rs1[i]|64); + signed char m1l=get_reg(i_regs->regmap,rs1[i]); + signed char m2h=get_reg(i_regs->regmap,rs2[i]|64); + signed char m2l=get_reg(i_regs->regmap,rs2[i]); + assert(m1h>=0); + assert(m2h>=0); + assert(m1l>=0); + assert(m2l>=0); + signed char rh=get_reg(i_regs->regmap,HIREG|64); + signed char rl=get_reg(i_regs->regmap,HIREG); + assert(rh>=0); + assert(rl>=0); + + emit_umull(m1l,m2l,rh,rl); + emit_storereg(LOREG,rl); + emit_mov(rh,rl); + emit_zeroreg(rh); + emit_umlal(m1l,m2h,rh,rl); + emit_mov(rh,HOST_TEMPREG); + emit_zeroreg(rh); + emit_umlal(m1h,m2l,rh,rl); + emit_storereg(LOREG|64,rl); + emit_zeroreg(rl); + emit_adds(HOST_TEMPREG,rh,HOST_TEMPREG); + emit_adcimm(rl,0,rh); + emit_mov(HOST_TEMPREG,rl); + emit_umlal(m1h,m2h,rh,rl); + } + if(opcode2[i]==0x1E) // DDIV + { + signed char d1h=get_reg(i_regs->regmap,rs1[i]|64); + signed char d1l=get_reg(i_regs->regmap,rs1[i]); + signed char d2h=get_reg(i_regs->regmap,rs2[i]|64); + signed char d2l=get_reg(i_regs->regmap,rs2[i]); + assert(d1h>=0); + assert(d2h>=0); + assert(d1l>=0); + assert(d2l>=0); + save_regs(0x100f); + if(d1l!=0) emit_mov(d1l,0); + if(d1h==0) emit_readword((int)&dynarec_local,1); + else if(d1h>1) emit_mov(d1h,1); + if(d2l<2) emit_readword((int)&dynarec_local+d2l*4,2); + else if(d2l>2) emit_mov(d2l,2); + if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3); + else if(d2h>3) emit_mov(d2h,3); + emit_call((int)&div64); + restore_regs(0x100f); + signed char hih=get_reg(i_regs->regmap,HIREG|64); + signed char hil=get_reg(i_regs->regmap,HIREG); + signed char loh=get_reg(i_regs->regmap,LOREG|64); + signed char lol=get_reg(i_regs->regmap,LOREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); + if(hil>=0) emit_loadreg(HIREG,hil); + if(loh>=0) emit_loadreg(LOREG|64,loh); + if(lol>=0) emit_loadreg(LOREG,lol); + } + if(opcode2[i]==0x1F) // DDIVU + { + //u_int hr,reglist=0; + //for(hr=0;hrregmap[hr]>=0 && (i_regs->regmap[hr]&62)!=HIREG) reglist|=1<regmap,rs1[i]|64); + signed char d1l=get_reg(i_regs->regmap,rs1[i]); + signed char d2h=get_reg(i_regs->regmap,rs2[i]|64); + signed char d2l=get_reg(i_regs->regmap,rs2[i]); + assert(d1h>=0); + assert(d2h>=0); + assert(d1l>=0); + assert(d2l>=0); + save_regs(0x100f); + if(d1l!=0) emit_mov(d1l,0); + if(d1h==0) emit_readword((int)&dynarec_local,1); + else if(d1h>1) emit_mov(d1h,1); + if(d2l<2) emit_readword((int)&dynarec_local+d2l*4,2); + else if(d2l>2) emit_mov(d2l,2); + if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3); + else if(d2h>3) emit_mov(d2h,3); + emit_call((int)&divu64); + restore_regs(0x100f); + signed char hih=get_reg(i_regs->regmap,HIREG|64); + signed char hil=get_reg(i_regs->regmap,HIREG); + signed char loh=get_reg(i_regs->regmap,LOREG|64); + signed char lol=get_reg(i_regs->regmap,LOREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); + if(hil>=0) emit_loadreg(HIREG,hil); + if(loh>=0) emit_loadreg(LOREG|64,loh); + if(lol>=0) emit_loadreg(LOREG,lol); + } + } + } + else + { + // Multiply by zero is zero. + // MIPS does not have a divide by zero exception. + // The result is undefined, we return zero. + signed char hr=get_reg(i_regs->regmap,HIREG); + signed char lr=get_reg(i_regs->regmap,LOREG); + if(hr>=0) emit_zeroreg(hr); + if(lr>=0) emit_zeroreg(lr); + } +} +#define multdiv_assemble multdiv_assemble_arm + +static void do_preload_rhash(int r) { + // Don't need this for ARM. On x86, this puts the value 0xf8 into the + // register. On ARM the hash can be done with a single instruction (below) +} + +static void do_preload_rhtbl(int ht) { + emit_addimm(FP,(int)&mini_ht-(int)&dynarec_local,ht); +} + +static void do_rhash(int rs,int rh) { + emit_andimm(rs,0xf8,rh); +} + +static void do_miniht_load(int ht,int rh) { + assem_debug("ldr %s,[%s,%s]!",regname[rh],regname[ht],regname[rh]); + output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh)); +} + +static void do_miniht_jump(int rs,int rh,int ht) { + emit_cmp(rh,rs); + emit_ldreq_indexed(ht,4,15); + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + emit_mov(rs,7); + emit_jmp(jump_vaddr_reg[7]); + #else + emit_jmp(jump_vaddr_reg[rs]); + #endif +} + +static void do_miniht_insert(u_int return_address,int rt,int temp) { + #ifdef ARMv5_ONLY + emit_movimm(return_address,rt); // PC into link register + add_to_linker((int)out,return_address,1); + emit_pcreladdr(temp); + emit_writeword(rt,(int)&mini_ht[(return_address&0xFF)>>3][0]); + emit_writeword(temp,(int)&mini_ht[(return_address&0xFF)>>3][1]); + #else + emit_movw(return_address&0x0000FFFF,rt); + add_to_linker((int)out,return_address,1); + emit_pcreladdr(temp); + emit_writeword(temp,(int)&mini_ht[(return_address&0xFF)>>3][1]); + emit_movt(return_address&0xFFFF0000,rt); + emit_writeword(rt,(int)&mini_ht[(return_address&0xFF)>>3][0]); + #endif +} + +// Sign-extend to 64 bits and write out upper half of a register +// This is useful where we have a 32-bit value in a register, and want to +// keep it in a 32-bit register, but can't guarantee that it won't be read +// as a 64-bit value later. +static void wb_sx(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32_pre,uint64_t is32,uint64_t u,uint64_t uu) +{ + if(is32_pre==is32) return; + int hr,reg; + for(hr=0;hr=0) { + if((dirty>>hr)&1) { + if( ((is32_pre&~is32&~uu)>>reg)&1 ) { + emit_sarimm(hr,31,HOST_TEMPREG); + emit_storereg(reg|64,HOST_TEMPREG); + } + } + } + //} + } + } +} + +static void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int dirty,uint64_t is32_pre,uint64_t u,uint64_t uu) +{ + //if(dirty_pre==dirty) return; + int hr,reg,new_hr; + for(hr=0;hr>(reg&63))&1) { + if(reg>0) { + if(((dirty_pre&~dirty)>>hr)&1) { + if(reg>0&®<36) { + emit_storereg(reg,hr); + if( ((is32_pre&~uu)>>reg)&1 ) { + emit_sarimm(hr,31,HOST_TEMPREG); + emit_storereg(reg|64,HOST_TEMPREG); + } + } + else if(reg>=64) { + emit_storereg(reg,hr); + } + } + } + } + } + } +} + + +/* using strd could possibly help but you'd have to allocate registers in pairs +static void wb_invalidate_arm(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32,uint64_t u,uint64_t uu) +{ + int hr; + int wrote=-1; + for(hr=HOST_REGS-1;hr>=0;hr--) { + if(hr!=EXCLUDE_REG) { + if(pre[hr]!=entry[hr]) { + if(pre[hr]>=0) { + if((dirty>>hr)&1) { + if(get_reg(entry,pre[hr])<0) { + if(pre[hr]<64) { + if(!((u>>pre[hr])&1)) { + if(hr<10&&(~hr&1)&&(pre[hr+1]<0||wrote==hr+1)) { + if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { + emit_sarimm(hr,31,hr+1); + emit_strdreg(pre[hr],hr); + } + else + emit_storereg(pre[hr],hr); + }else{ + emit_storereg(pre[hr],hr); + if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { + emit_sarimm(hr,31,hr); + emit_storereg(pre[hr]|64,hr); + } + } + } + }else{ + if(!((uu>>(pre[hr]&63))&1) && !((is32>>(pre[hr]&63))&1)) { + emit_storereg(pre[hr],hr); + } + } + wrote=hr; + } + } + } + } + } + } + for(hr=0;hr=0) { + int nr; + if((nr=get_reg(entry,pre[hr]))>=0) { + emit_mov(hr,nr); + } + } + } + } + } +} +#define wb_invalidate wb_invalidate_arm +*/ + +// Clearing the cache is rather slow on ARM Linux, so mark the areas +// that need to be cleared, and then only clear these areas once. +static void do_clear_cache() +{ + int i,j; + for (i=0;i<(1<<(TARGET_SIZE_2-17));i++) + { + u_int bitmap=needs_clear_cache[i]; + if(bitmap) { + u_int start,end; + for(j=0;j<32;j++) + { + if(bitmap&(1<>2; + #endif + + // Trampolines for jumps >32M + int *ptr,*ptr2; + ptr=(int *)jump_table_symbols; + ptr2=(int *)((void *)BASE_ADDR+(1<=-33554432&&offset<33554432) { + *ptr2=0xea000000|((offset>>2)&0xffffff); // direct branch + }else{ + *ptr2=0xe51ff004; // ldr pc,[pc,#-4] + } + ptr2++; + *ptr2=*ptr; + ptr++; + ptr2++; + } + + // Jumping thru the trampolines created above slows things down by about 1%. + // If part of the cache is beyond the 32M limit, avoid using this area + // initially. It will be used later if the cache gets full. + if((u_int)dyna_linker-33554432>(u_int)BASE_ADDR) { + if((u_int)dyna_linker-33554432<(u_int)BASE_ADDR+(1<<(TARGET_SIZE_2-1))) { + out=(u_char *)(((u_int)dyna_linker-33554432)&~4095); + expirep=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535; + } + } +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.h b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.h new file mode 100644 index 000000000..5dfb3add7 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_arm.h @@ -0,0 +1,48 @@ +#ifndef M64P_R4300_ASSEM_ARM_H +#define M64P_R4300_ASSEM_ARM_H + +#define HOST_REGS 13 +#define HOST_CCREG 10 +#define HOST_BTREG 8 +#define EXCLUDE_REG 11 + +#define HOST_IMM8 1 +#define HAVE_CMOV_IMM 1 +#define CORTEX_A8_BRANCH_PREDICTION_HACK 1 +#define USE_MINI_HT 1 +//#define REG_PREFETCH 1 +#define HAVE_CONDITIONAL_CALL 1 +#define RAM_OFFSET 1 + +/* ARM calling convention: + r0-r3, r12: caller-save + r4-r11: callee-save */ + +#define ARG1_REG 0 +#define ARG2_REG 1 +#define ARG3_REG 2 +#define ARG4_REG 3 + +/* GCC register naming convention: + r10 = sl (base) + r11 = fp (frame pointer) + r12 = ip (scratch) + r13 = sp (stack pointer) + r14 = lr (link register) + r15 = pc (program counter) */ + +#define FP 11 +#define LR 14 +#define HOST_TEMPREG 14 + +// Note: FP is set to &dynarec_local when executing generated code. +// Thus the local variables are actually global and not on the stack. + +extern char *invc_ptr; +extern char extra_memory[33554432]; + +#define BASE_ADDR ((int)(&extra_memory)) +//#define TARGET_SIZE_2 24 // 2^24 = 16 megabytes +#define TARGET_SIZE_2 25 // 2^25 = 32 megabytes + +#endif /* M64P_R4300_ASSEM_ARM_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.c b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.c new file mode 100644 index 000000000..ed1d4649c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.c @@ -0,0 +1,4436 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assem_x86.c * + * Copyright (C) 2009-2011 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "main/main.h" + +int cycle_count; +int last_count; +int pcaddr; +int pending_exception; +int branch_target; +uint64_t readmem_dword; +static precomp_instr fake_pc; +u_int memory_map[1048576]; +ALIGN(8, static u_int mini_ht[32][2]); +ALIGN(4, u_char restore_candidate[512]); + +#ifdef __cplusplus +extern "C" { +#endif +void do_interrupt(); +void jump_vaddr_eax(); +void jump_vaddr_ecx(); +void jump_vaddr_edx(); +void jump_vaddr_ebx(); +void jump_vaddr_ebp(); +void jump_vaddr_edi(); +#ifdef __cplusplus +} +#endif + +static const u_int jump_vaddr_reg[8] = { + (int)jump_vaddr_eax, + (int)jump_vaddr_ecx, + (int)jump_vaddr_edx, + (int)jump_vaddr_ebx, + 0, + (int)jump_vaddr_ebp, + 0, + (int)jump_vaddr_edi }; + +#ifdef __cplusplus +extern "C" { +#endif +void invalidate_block_eax(); +void invalidate_block_ecx(); +void invalidate_block_edx(); +void invalidate_block_ebx(); +void invalidate_block_ebp(); +void invalidate_block_esi(); +void invalidate_block_edi(); +#ifdef __cplusplus +} +#endif + +static const u_int invalidate_block_reg[8] = { + (int)invalidate_block_eax, + (int)invalidate_block_ecx, + (int)invalidate_block_edx, + (int)invalidate_block_ebx, + 0, + (int)invalidate_block_ebp, + (int)invalidate_block_esi, + (int)invalidate_block_edi }; + +static const u_short rounding_modes[4] = { + 0x33F, // round + 0xF3F, // trunc + 0xB3F, // ceil + 0x73F};// floor + +#include "../fpu.h" + +// We need these for cmovcc instructions on x86 +static const u_int const_zero=0; +static const u_int const_one=1; + +/* Linker */ + +static void set_jump_target(int addr,int target) +{ + u_char *ptr=(u_char *)addr; + if(*ptr==0x0f) + { + assert(ptr[1]>=0x80&&ptr[1]<=0x8f); + u_int *ptr2=(u_int *)(ptr+2); + *ptr2=target-(int)ptr2-4; + } + else if(*ptr==0xe8||*ptr==0xe9) { + u_int *ptr2=(u_int *)(ptr+1); + *ptr2=target-(int)ptr2-4; + } + else + { + assert(*ptr==0xc7); /* mov immediate (store address) */ + u_int *ptr2=(u_int *)(ptr+6); + *ptr2=target; + } +} + +static void *kill_pointer(void *stub) +{ + int *i_ptr=*((int **)((int)stub+6)); + *i_ptr=(int)stub-(int)i_ptr-4; + return i_ptr; +} +static int get_pointer(void *stub) +{ + int *i_ptr=*((int **)((int)stub+6)); + return *i_ptr+(int)i_ptr+4; +} + +// Find the "clean" entry point from a "dirty" entry point +// by skipping past the call to verify_code +static u_int get_clean_addr(int addr) +{ + u_char *ptr=(u_char *)addr; + assert(ptr[20]==0xE8); // call instruction + assert(ptr[25]==0x83); // pop (add esp,4) instruction + if(ptr[28]==0xE9) return *(u_int *)(ptr+29)+addr+33; // follow jmp + else return(addr+28); +} + +static int verify_dirty(void *addr) +{ + u_char *ptr=(u_char *)addr; + assert(ptr[5]==0xB8); + u_int source=*(u_int *)(ptr+6); + u_int copy=*(u_int *)(ptr+11); + u_int len=*(u_int *)(ptr+16); + assert(ptr[20]==0xE8); // call instruction + u_int verifier=*(u_int *)(ptr+21)+(u_int)ptr+25; + if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { + unsigned int page=source>>12; + unsigned int map_value=memory_map[page]; + if(map_value>=0x80000000) return 0; + while(page<((source+len-1)>>12)) { + if((memory_map[++page]<<2)!=(map_value<<2)) return 0; + } + source = source+(map_value<<2); + } + //DebugMessage(M64MSG_VERBOSE, "verify_dirty: %x %x %x",source,copy,len); + return !memcmp((void *)source,(void *)copy,len); +} + +// This doesn't necessarily find all clean entry points, just +// guarantees that it's not dirty +static int isclean(int addr) +{ + u_char *ptr=(u_char *)addr; + if(ptr[5]!=0xB8) return 1; // mov imm,%eax + if(ptr[10]!=0xBB) return 1; // mov imm,%ebx + if(ptr[15]!=0xB9) return 1; // mov imm,%ecx + if(ptr[20]!=0xE8) return 1; // call instruction + if(ptr[25]!=0x83) return 1; // pop (add esp,4) instruction + return 0; +} + +static void get_bounds(int addr,u_int *start,u_int *end) +{ + u_char *ptr=(u_char *)addr; + assert(ptr[5]==0xB8); + u_int source=*(u_int *)(ptr+6); + //u_int copy=*(u_int *)(ptr+11); + u_int len=*(u_int *)(ptr+16); + assert(ptr[20]==0xE8); // call instruction + u_int verifier=*(u_int *)(ptr+21)+(u_int)ptr+25; + if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { + if(memory_map[source>>12]>=0x80000000) source = 0; + else source = source+(memory_map[source>>12]<<2); + } + if(start) *start=source; + if(end) *end=source+len; +} + +/* Register allocation */ + +// Note: registers are allocated clean (unmodified state) +// if you intend to modify the register, you must call dirty_reg(). +static void alloc_reg(struct regstat *cur,int i,signed char reg) +{ + int r,hr; + int preferred_reg = (reg&3)+(reg>28)*4-(reg==32)+2*(reg==36)-(reg==40); + + // Don't allocate unused registers + if((cur->u>>reg)&1) return; + + // see if it's already allocated + for(hr=0;hrregmap[hr]==reg) return; + } + + // Keep the same mapping if the register was already allocated in a loop + preferred_reg = loop_reg(i,reg,preferred_reg); + + // Try to allocate the preferred register + if(cur->regmap[preferred_reg]==-1) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; + if(r<64&&((cur->u>>r)&1)) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { + cur->regmap[preferred_reg]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) + if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} + } + else + { + if((cur->uu>>(r&63))&1) + if(i==0||(unneeded_reg_upper[i-1]>>(r&63))&1) {cur->regmap[hr]=-1;break;} + } + } + } + // Try to allocate any available register, but prefer + // registers that have not been used recently. + if(i>0) { + for(hr=0;hrregmap[hr]==-1) { + if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + // Alloc preferred register if available + if(hsn[r=cur->regmap[preferred_reg]&63]==j) { + for(hr=0;hrregmap[hr]&63)==r) { + cur->regmap[hr]=-1; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; + return; + } + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<uu>>reg)&1) return; + + // see if the upper half is already allocated + for(hr=0;hrregmap[hr]==reg+64) return; + } + + // Keep the same mapping if the register was already allocated in a loop + preferred_reg = loop_reg(i,reg,preferred_reg); + + // Try to allocate the preferred register + if(cur->regmap[preferred_reg]==-1) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; + if(r<64&&((cur->u>>r)&1)) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { + cur->regmap[preferred_reg]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=0;hr--) + { + r=cur->regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} + } + else + { + if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} + } + } + } + // Try to allocate any available register, but prefer + // registers that have not been used recently. + if(i>0) { + for(hr=0;hrregmap[hr]==-1) { + if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]); + //DebugMessage(M64MSG_VERBOSE, "hsn(%x): %d %d %d %d %d %d %d",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + // Alloc preferred register if available + if(hsn[r=cur->regmap[preferred_reg]&63]==j) { + for(hr=0;hrregmap[hr]&63)==r) { + cur->regmap[hr]=-1; + cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg|64; + return; + } + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg|64; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; + } + + // Try to allocate any available register, starting with EDI, ESI, EBP... + // We prefer EDI, ESI, EBP since the others are used for byte/halfword stores + for(hr=HOST_REGS-1;hr>=0;hr--) { + if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;hr--) + { + r=cur->regmap[hr]; + if(r>=0) { + if(r<64) { + if((cur->u>>r)&1) { + if(i==0||((unneeded_reg[i-1]>>r)&1)) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { + if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; + if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { + for(hr=0;hr2) { + if(cur->regmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<2) { + if(cur->regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrregmap[hr]==r+64) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { + cur->regmap[hr]=reg; + cur->dirty&=~(1<isconst&=~(1<regmap[n]==reg) { + dirty=(cur->dirty>>n)&1; + cur->regmap[n]=-1; + } + } + + cur->regmap[hr]=reg; + cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<u&=~(1LL<u&=~(1LL<is32|=1LL<is32|=1LL<is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<>4); + if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4); + if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4); + if(r==CCREG) addr=(int)&cycle_count; + if(r==CSREG) addr=(int)&g_cp0_regs[CP0_STATUS_REG]; + if(r==FSREG) addr=(int)&FCR31; + assem_debug("mov %x+%d,%%%s",addr,r,regname[hr]); + output_byte(0x8B); + output_modrm(0,5,hr); + output_w32(addr); + } +} +static void emit_storereg(int r, int hr) +{ + int addr=((int)reg)+((r&63)<<3)+((r&64)>>4); + if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4); + if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4); + if(r==CCREG) addr=(int)&cycle_count; + if(r==FSREG) addr=(int)&FCR31; + assem_debug("mov %%%s,%x+%d",regname[hr],addr,r); + output_byte(0x89); + output_modrm(0,5,hr); + output_w32(addr); +} + +static void emit_test(int rs, int rt) +{ + assem_debug("test %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x85); + output_modrm(3,rs,rt); +} + +static void emit_testimm(int rs,int imm) +{ + assem_debug("test $0x%x,%%%s",imm,regname[rs]); + if(imm<128&&imm>=-128&&rs<4) { + output_byte(0xF6); + output_modrm(3,rs,0); + output_byte(imm); + } + else + { + output_byte(0xF7); + output_modrm(3,rs,0); + output_w32(imm); + } +} + +static void emit_not(int rs,int rt) +{ + if(rs!=rt) emit_mov(rs,rt); + assem_debug("not %%%s",regname[rt]); + output_byte(0xF7); + output_modrm(3,rt,2); +} + +static void emit_and(u_int rs1,u_int rs2,u_int rt) +{ + assert(rs1<8); + assert(rs2<8); + assert(rt<8); + if(rs1==rt) { + assem_debug("and %%%s,%%%s",regname[rs2],regname[rt]); + output_byte(0x21); + output_modrm(3,rs1,rs2); + } + else + if(rs2==rt) { + assem_debug("and %%%s,%%%s",regname[rs1],regname[rt]); + output_byte(0x21); + output_modrm(3,rs2,rs1); + } + else { + emit_mov(rs1,rt); + emit_and(rt,rs2,rt); + } +} + +static void emit_or(u_int rs1,u_int rs2,u_int rt) +{ + assert(rs1<8); + assert(rs2<8); + assert(rt<8); + if(rs1==rt) { + assem_debug("or %%%s,%%%s",regname[rs2],regname[rt]); + output_byte(0x09); + output_modrm(3,rs1,rs2); + } + else + if(rs2==rt) { + assem_debug("or %%%s,%%%s",regname[rs1],regname[rt]); + output_byte(0x09); + output_modrm(3,rs2,rs1); + } + else { + emit_mov(rs1,rt); + emit_or(rt,rs2,rt); + } +} +static void emit_or_and_set_flags(int rs1,int rs2,int rt) +{ + emit_or(rs1,rs2,rt); +} + +static void emit_xor(u_int rs1,u_int rs2,u_int rt) +{ + assert(rs1<8); + assert(rs2<8); + assert(rt<8); + if(rs1==rt) { + assem_debug("xor %%%s,%%%s",regname[rs2],regname[rt]); + output_byte(0x31); + output_modrm(3,rs1,rs2); + } + else + if(rs2==rt) { + assem_debug("xor %%%s,%%%s",regname[rs1],regname[rt]); + output_byte(0x31); + output_modrm(3,rs2,rs1); + } + else { + emit_mov(rs1,rt); + emit_xor(rt,rs2,rt); + } +} + +static void emit_movimm(int imm,u_int rt) +{ + assem_debug("mov $%d,%%%s",imm,regname[rt]); + assert(rt<8); + output_byte(0xB8+rt); + output_w32(imm); +} + +static void emit_addimm(int rs,int imm,int rt) +{ + if(rs==rt) { + if(imm!=0) { + assem_debug("add $%d,%%%s",imm,regname[rt]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,0); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,0); + output_w32(imm); + } + } + } + else { + if(imm!=0) { + assem_debug("lea %d(%%%s),%%%s",imm,regname[rs],regname[rt]); + output_byte(0x8D); + if(imm<128&&imm>=-128) { + output_modrm(1,rs,rt); + output_byte(imm); + }else{ + output_modrm(2,rs,rt); + output_w32(imm); + } + }else{ + emit_mov(rs,rt); + } + } +} + +static void emit_addimm_and_set_flags(int imm,int rt) +{ + assem_debug("add $%d,%%%s",imm,regname[rt]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,0); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,0); + output_w32(imm); + } +} +static void emit_addimm_no_flags(int imm,int rt) +{ + if(imm!=0) { + assem_debug("lea %d(%%%s),%%%s",imm,regname[rt],regname[rt]); + output_byte(0x8D); + if(imm<128&&imm>=-128) { + output_modrm(1,rt,rt); + output_byte(imm); + }else{ + output_modrm(2,rt,rt); + output_w32(imm); + } + } +} + +static void emit_adcimm(int imm,u_int rt) +{ + assem_debug("adc $%d,%%%s",imm,regname[rt]); + assert(rt<8); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,2); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,2); + output_w32(imm); + } +} +static void emit_sbbimm(int imm,u_int rt) +{ + assem_debug("sbb $%d,%%%s",imm,regname[rt]); + assert(rt<8); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,3); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,3); + output_w32(imm); + } +} + +static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) +{ + if(rsh==rth&&rsl==rtl) { + assem_debug("add $%d,%%%s",imm,regname[rtl]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rtl,0); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rtl,0); + output_w32(imm); + } + assem_debug("adc $%d,%%%s",imm>>31,regname[rth]); + output_byte(0x83); + output_modrm(3,rth,2); + output_byte(imm>>31); + } + else { + emit_mov(rsh,rth); + emit_mov(rsl,rtl); + emit_addimm64_32(rth,rtl,imm,rth,rtl); + } +} + +static void emit_sub64_32(int rs1l,int rs1h,int rs2l,int rs2h,int rtl,int rth) +{ + if((rs1l==rtl)&&(rs1h==rth)) { + assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rs1l]); + output_byte(0x29); + output_modrm(3,rs1l,rs2l); + assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rs1h]); + output_byte(0x19); + output_modrm(3,rs1h,rs2h); + } else if((rs2l==rtl)&&(rs2h==rth)) { + emit_neg(rs2l,rs2l); + emit_adcimm(-1,rs2h); + assem_debug("add %%%s,%%%s",regname[rs1l],regname[rs2l]); + output_byte(0x01); + output_modrm(3,rs2l,rs1l); + emit_not(rs2h,rs2h); + assem_debug("adc %%%s,%%%s",regname[rs1h],regname[rs2h]); + output_byte(0x11); + output_modrm(3,rs2h,rs1h); + } else { + emit_mov(rs1l,rtl); + assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rtl]); + output_byte(0x29); + output_modrm(3,rtl,rs2l); + emit_mov(rs1h,rth); + assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rth]); + output_byte(0x19); + output_modrm(3,rth,rs2h); + } +} + +static void emit_sbb(int rs1,int rs2) +{ + assem_debug("sbb %%%s,%%%s",regname[rs1],regname[rs2]); + output_byte(0x19); + output_modrm(3,rs2,rs1); +} + +static void emit_andimm(int rs,int imm,int rt) +{ + if(imm==0) { + emit_zeroreg(rt); + } + else if(rs==rt) { + assem_debug("and $%d,%%%s",imm,regname[rt]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,4); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,4); + output_w32(imm); + } + } + else { + emit_mov(rs,rt); + emit_andimm(rt,imm,rt); + } +} + +static void emit_orimm(int rs,int imm,int rt) +{ + if(rs==rt) { + if(imm!=0) { + assem_debug("or $%d,%%%s",imm,regname[rt]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,1); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,1); + output_w32(imm); + } + } + } + else { + emit_mov(rs,rt); + emit_orimm(rt,imm,rt); + } +} + +static void emit_xorimm(int rs,int imm,int rt) +{ + if(rs==rt) { + if(imm!=0) { + assem_debug("xor $%d,%%%s",imm,regname[rt]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rt,6); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rt,6); + output_w32(imm); + } + } + } + else { + emit_mov(rs,rt); + emit_xorimm(rt,imm,rt); + } +} + +static void emit_shlimm(int rs,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("shl %%%s,%d",regname[rt],imm); + assert(imm>0); + if(imm==1) output_byte(0xD1); + else output_byte(0xC1); + output_modrm(3,rt,4); + if(imm>1) output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_shlimm(rt,imm,rt); + } +} + +static void emit_shrimm(int rs,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("shr %%%s,%d",regname[rt],imm); + assert(imm>0); + if(imm==1) output_byte(0xD1); + else output_byte(0xC1); + output_modrm(3,rt,5); + if(imm>1) output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_shrimm(rt,imm,rt); + } +} + +static void emit_sarimm(int rs,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("sar %%%s,%d",regname[rt],imm); + assert(imm>0); + if(imm==1) output_byte(0xD1); + else output_byte(0xC1); + output_modrm(3,rt,7); + if(imm>1) output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_sarimm(rt,imm,rt); + } +} + +static void emit_rorimm(int rs,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("ror %%%s,%d",regname[rt],imm); + assert(imm>0); + if(imm==1) output_byte(0xD1); + else output_byte(0xC1); + output_modrm(3,rt,1); + if(imm>1) output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_rorimm(rt,imm,rt); + } +} + +static void emit_shldimm(int rs,int rs2,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); + assert(imm>0); + output_byte(0x0F); + output_byte(0xA4); + output_modrm(3,rt,rs2); + output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_shldimm(rt,rs2,imm,rt); + } +} + +static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) +{ + if(rs==rt) { + assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); + assert(imm>0); + output_byte(0x0F); + output_byte(0xAC); + output_modrm(3,rt,rs2); + output_byte(imm); + } + else { + emit_mov(rs,rt); + emit_shrdimm(rt,rs2,imm,rt); + } +} + +static void emit_shlcl(int r) +{ + assem_debug("shl %%%s,%%cl",regname[r]); + output_byte(0xD3); + output_modrm(3,r,4); +} +static void emit_shrcl(int r) +{ + assem_debug("shr %%%s,%%cl",regname[r]); + output_byte(0xD3); + output_modrm(3,r,5); +} +static void emit_sarcl(int r) +{ + assem_debug("sar %%%s,%%cl",regname[r]); + output_byte(0xD3); + output_modrm(3,r,7); +} + +static void emit_shldcl(int r1,int r2) +{ + assem_debug("shld %%%s,%%%s,%%cl",regname[r1],regname[r2]); + output_byte(0x0F); + output_byte(0xA5); + output_modrm(3,r1,r2); +} +static void emit_shrdcl(int r1,int r2) +{ + assem_debug("shrd %%%s,%%%s,%%cl",regname[r1],regname[r2]); + output_byte(0x0F); + output_byte(0xAD); + output_modrm(3,r1,r2); +} + +static void emit_cmpimm(int rs,int imm) +{ + assem_debug("cmp $%d,%%%s",imm,regname[rs]); + if(imm<128&&imm>=-128) { + output_byte(0x83); + output_modrm(3,rs,7); + output_byte(imm); + } + else + { + output_byte(0x81); + output_modrm(3,rs,7); + output_w32(imm); + } +} + +static void emit_cmovne(const u_int *addr,int rt) +{ + assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]); + if(addr==&const_zero) assem_debug(" [zero]"); + else if(addr==&const_one) assem_debug(" [one]"); + else assem_debug(""); + output_byte(0x0F); + output_byte(0x45); + output_modrm(0,5,rt); + output_w32((int)addr); +} +static void emit_cmovl(const u_int *addr,int rt) +{ + assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]); + if(addr==&const_zero) assem_debug(" [zero]"); + else if(addr==&const_one) assem_debug(" [one]"); + else assem_debug(""); + output_byte(0x0F); + output_byte(0x4C); + output_modrm(0,5,rt); + output_w32((int)addr); +} +static void emit_cmovs(const u_int *addr,int rt) +{ + assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]); + if(addr==&const_zero) assem_debug(" [zero]"); + else if(addr==&const_one) assem_debug(" [one]"); + else assem_debug(""); + output_byte(0x0F); + output_byte(0x48); + output_modrm(0,5,rt); + output_w32((int)addr); +} +static void emit_cmovne_reg(int rs,int rt) +{ + assem_debug("cmovne %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x45); + output_modrm(3,rs,rt); +} +static void emit_cmovl_reg(int rs,int rt) +{ + assem_debug("cmovl %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x4C); + output_modrm(3,rs,rt); +} +static void emit_cmovs_reg(int rs,int rt) +{ + assem_debug("cmovs %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x48); + output_modrm(3,rs,rt); +} +static void emit_cmovnc_reg(int rs,int rt) +{ + assem_debug("cmovae %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x43); + output_modrm(3,rs,rt); +} +static void emit_cmova_reg(int rs,int rt) +{ + assem_debug("cmova %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x47); + output_modrm(3,rs,rt); +} +static void emit_cmovp_reg(int rs,int rt) +{ + assem_debug("cmovp %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x4A); + output_modrm(3,rs,rt); +} +static void emit_cmovnp_reg(int rs,int rt) +{ + assem_debug("cmovnp %%%s,%%%s",regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0x4B); + output_modrm(3,rs,rt); +} +static void emit_setl(int rt) +{ + assem_debug("setl %%%s",regname[rt]); + output_byte(0x0F); + output_byte(0x9C); + output_modrm(3,rt,2); +} +static void emit_movzbl_reg(int rs, int rt) +{ + assem_debug("movzbl %%%s,%%%s",regname[rs]+1,regname[rt]); + output_byte(0x0F); + output_byte(0xB6); + output_modrm(3,rs,rt); +} + +static void emit_slti32(int rs,int imm,int rt) +{ + if(rs!=rt) emit_zeroreg(rt); + emit_cmpimm(rs,imm); + if(rt<4) { + emit_setl(rt); + if(rs==rt) emit_movzbl_reg(rt,rt); + } + else + { + if(rs==rt) emit_movimm(0,rt); + emit_cmovl(&const_one,rt); + } +} +static void emit_sltiu32(int rs,int imm,int rt) +{ + if(rs!=rt) emit_zeroreg(rt); + emit_cmpimm(rs,imm); + if(rs==rt) emit_movimm(0,rt); + emit_adcimm(0,rt); +} +static void emit_slti64_32(int rsh,int rsl,int imm,int rt) +{ + assert(rsh!=rt); + emit_slti32(rsl,imm,rt); + if(imm>=0) + { + emit_test(rsh,rsh); + emit_cmovne(&const_zero,rt); + emit_cmovs(&const_one,rt); + } + else + { + emit_cmpimm(rsh,-1); + emit_cmovne(&const_zero,rt); + emit_cmovl(&const_one,rt); + } +} +static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) +{ + assert(rsh!=rt); + emit_sltiu32(rsl,imm,rt); + if(imm>=0) + { + emit_test(rsh,rsh); + emit_cmovne(&const_zero,rt); + } + else + { + emit_cmpimm(rsh,-1); + emit_cmovne(&const_one,rt); + } +} + +static void emit_cmp(int rs,int rt) +{ + assem_debug("cmp %%%s,%%%s",regname[rt],regname[rs]); + output_byte(0x39); + output_modrm(3,rs,rt); +} +static void emit_set_gz32(int rs, int rt) +{ + //assem_debug("set_gz32"); + emit_cmpimm(rs,1); + emit_movimm(1,rt); + emit_cmovl(&const_zero,rt); +} +static void emit_set_nz32(int rs, int rt) +{ + //assem_debug("set_nz32"); + emit_cmpimm(rs,1); + emit_movimm(1,rt); + emit_sbbimm(0,rt); +} +static void emit_set_gz64_32(int rsh, int rsl, int rt) +{ + //assem_debug("set_gz64"); + emit_set_gz32(rsl,rt); + emit_test(rsh,rsh); + emit_cmovne(&const_one,rt); + emit_cmovs(&const_zero,rt); +} +static void emit_set_nz64_32(int rsh, int rsl, int rt) +{ + //assem_debug("set_nz64"); + emit_or_and_set_flags(rsh,rsl,rt); + emit_cmovne(&const_one,rt); +} +static void emit_set_if_less32(int rs1, int rs2, int rt) +{ + //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); + if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); + emit_cmp(rs1,rs2); + if(rs1==rt||rs2==rt) emit_movimm(0,rt); + emit_cmovl(&const_one,rt); +} +static void emit_set_if_carry32(int rs1, int rs2, int rt) +{ + //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); + if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); + emit_cmp(rs1,rs2); + if(rs1==rt||rs2==rt) emit_movimm(0,rt); + emit_adcimm(0,rt); +} +static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) +{ + //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); + assert(u1!=rt); + assert(u2!=rt); + emit_cmp(l1,l2); + emit_mov(u1,rt); + emit_sbb(u2,rt); + emit_movimm(0,rt); + emit_cmovl(&const_one,rt); +} +static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) +{ + //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); + assert(u1!=rt); + assert(u2!=rt); + emit_cmp(l1,l2); + emit_mov(u1,rt); + emit_sbb(u2,rt); + emit_movimm(0,rt); + emit_adcimm(0,rt); +} + +static void emit_call(int a) +{ + assem_debug("call %x (%x+%x)",a,(int)out+5,a-(int)out-5); + output_byte(0xe8); + output_w32(a-(int)out-4); +} +static void emit_jmp(int a) +{ + assem_debug("jmp %x (%x+%x)",a,(int)out+5,a-(int)out-5); + output_byte(0xe9); + output_w32(a-(int)out-4); +} +static void emit_jne(int a) +{ + assem_debug("jne %x",a); + output_byte(0x0f); + output_byte(0x85); + output_w32(a-(int)out-4); +} +static void emit_jeq(int a) +{ + assem_debug("jeq %x",a); + output_byte(0x0f); + output_byte(0x84); + output_w32(a-(int)out-4); +} +static void emit_js(int a) +{ + assem_debug("js %x",a); + output_byte(0x0f); + output_byte(0x88); + output_w32(a-(int)out-4); +} +static void emit_jns(int a) +{ + assem_debug("jns %x",a); + output_byte(0x0f); + output_byte(0x89); + output_w32(a-(int)out-4); +} +static void emit_jl(int a) +{ + assem_debug("jl %x",a); + output_byte(0x0f); + output_byte(0x8c); + output_w32(a-(int)out-4); +} +static void emit_jge(int a) +{ + assem_debug("jge %x",a); + output_byte(0x0f); + output_byte(0x8d); + output_w32(a-(int)out-4); +} +static void emit_jno(int a) +{ + assem_debug("jno %x",a); + output_byte(0x0f); + output_byte(0x81); + output_w32(a-(int)out-4); +} +static void emit_jc(int a) +{ + assem_debug("jc %x",a); + output_byte(0x0f); + output_byte(0x82); + output_w32(a-(int)out-4); +} +static void emit_jae(int a) +{ + assem_debug("jae %x",a); + output_byte(0x0f); + output_byte(0x83); + output_w32(a-(int)out-4); +} +static void emit_jb(int a) +{ + assem_debug("jb %x",a); + output_byte(0x0f); + output_byte(0x82); + output_w32(a-(int)out-4); +} + +static void emit_pushimm(int imm) +{ + assem_debug("push $%x",imm); + output_byte(0x68); + output_w32(imm); +} +static void emit_pushmem(int addr) +{ + assem_debug("push *%x",addr); + output_byte(0xFF); + output_modrm(0,5,6); + output_w32(addr); +} +static void emit_pusha() +{ + assem_debug("pusha"); + output_byte(0x60); +} +static void emit_popa() +{ + assem_debug("popa"); + output_byte(0x61); +} +static void emit_pushreg(u_int r) +{ + assem_debug("push %%%s",regname[r]); + assert(r<8); + output_byte(0x50+r); +} +static void emit_popreg(u_int r) +{ + assem_debug("pop %%%s",regname[r]); + assert(r<8); + output_byte(0x58+r); +} +static void emit_callreg(u_int r) +{ + assem_debug("call *%%%s",regname[r]); + assert(r<8); + output_byte(0xFF); + output_modrm(3,r,2); +} +/*static void emit_jmpreg(u_int r) +{ + assem_debug("jmp *%%%s",regname[r]); + assert(r<8); + output_byte(0xFF); + output_modrm(3,r,4); +}*/ +static void emit_jmpmem_indexed(u_int addr,u_int r) +{ + assem_debug("jmp *%x(%%%s)",addr,regname[r]); + assert(r<8); + output_byte(0xFF); + output_modrm(2,r,4); + output_w32(addr); +} + +static void emit_readword(int addr, int rt) +{ + assem_debug("mov %x,%%%s",addr,regname[rt]); + output_byte(0x8B); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_readword_indexed(int addr, int rs, int rt) +{ + assem_debug("mov %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x8B); + if(addr<128&&addr>=-128) { + output_modrm(1,rs,rt); + if(rs==ESP) output_sib(0,4,4); + output_byte(addr); + } + else + { + output_modrm(2,rs,rt); + if(rs==ESP) output_sib(0,4,4); + output_w32(addr); + } +} +static void emit_readword_tlb(int addr, int map, int rt) +{ + if(map<0) emit_readword(addr+(int)g_rdram-0x80000000, rt); + else + { + assem_debug("mov (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); + output_byte(0x8B); + output_modrm(0,4,rt); + output_sib(2,map,5); + output_w32(addr); + } +} +static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_readword_indexed(addr+(int)g_rdram-0x80000000, rs, rt); + else { + assem_debug("mov %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); + assert(rs!=ESP); + output_byte(0x8B); + if(addr==0&&rs!=EBP) { + output_modrm(0,4,rt); + output_sib(2,map,rs); + } + else if(addr<128&&addr>=-128) { + output_modrm(1,4,rt); + output_sib(2,map,rs); + output_byte(addr); + } + else + { + output_modrm(2,4,rt); + output_sib(2,map,rs); + output_w32(addr); + } + } +} +static void emit_movmem_indexedx4(int addr, int rs, int rt) +{ + assem_debug("mov (%x,%%%s,4),%%%s",addr,regname[rs],regname[rt]); + output_byte(0x8B); + output_modrm(0,4,rt); + output_sib(2,rs,5); + output_w32(addr); +} +static void emit_readdword_tlb(int addr, int map, int rh, int rl) +{ + if(map<0) { + if(rh>=0) emit_readword(addr+(int)g_rdram-0x80000000, rh); + emit_readword(addr+(int)g_rdram-0x7FFFFFFC, rl); + } + else { + if(rh>=0) emit_movmem_indexedx4(addr, map, rh); + emit_movmem_indexedx4(addr+4, map, rl); + } +} +static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) +{ + assert(rh!=rs); + if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); + emit_readword_indexed_tlb(addr+4, rs, map, rl); +} +static void emit_movsbl(int addr, int rt) +{ + assem_debug("movsbl %x,%%%s",addr,regname[rt]); + output_byte(0x0F); + output_byte(0xBE); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_movsbl_indexed(int addr, int rs, int rt) +{ + assem_debug("movsbl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0xBE); + output_modrm(2,rs,rt); + output_w32(addr); +} +static void emit_movsbl_tlb(int addr, int map, int rt) +{ + if(map<0) emit_movsbl(addr+(int)g_rdram-0x80000000, rt); + else + { + assem_debug("movsbl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); + output_byte(0x0F); + output_byte(0xBE); + output_modrm(0,4,rt); + output_sib(2,map,5); + output_w32(addr); + } +} +static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_movsbl_indexed(addr+(int)g_rdram-0x80000000, rs, rt); + else { + assem_debug("movsbl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); + assert(rs!=ESP); + output_byte(0x0F); + output_byte(0xBE); + if(addr==0&&rs!=EBP) { + output_modrm(0,4,rt); + output_sib(2,map,rs); + } + else if(addr<128&&addr>=-128) { + output_modrm(1,4,rt); + output_sib(2,map,rs); + output_byte(addr); + } + else + { + output_modrm(2,4,rt); + output_sib(2,map,rs); + output_w32(addr); + } + } +} +static void emit_movswl(int addr, int rt) +{ + assem_debug("movswl %x,%%%s",addr,regname[rt]); + output_byte(0x0F); + output_byte(0xBF); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_movswl_indexed(int addr, int rs, int rt) +{ + assem_debug("movswl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0xBF); + output_modrm(2,rs,rt); + output_w32(addr); +} +static void emit_movswl_tlb(int addr, int map, int rt) +{ + if(map<0) emit_movswl(addr+(int)g_rdram-0x80000000, rt); + else + { + assem_debug("movswl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); + output_byte(0x0F); + output_byte(0xBF); + output_modrm(0,4,rt); + output_sib(2,map,5); + output_w32(addr); + } +} +static void emit_movzbl(int addr, int rt) +{ + assem_debug("movzbl %x,%%%s",addr,regname[rt]); + output_byte(0x0F); + output_byte(0xB6); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_movzbl_indexed(int addr, int rs, int rt) +{ + assem_debug("movzbl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0xB6); + output_modrm(2,rs,rt); + output_w32(addr); +} +static void emit_movzbl_tlb(int addr, int map, int rt) +{ + if(map<0) emit_movzbl(addr+(int)g_rdram-0x80000000, rt); + else + { + assem_debug("movzbl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); + output_byte(0x0F); + output_byte(0xB6); + output_modrm(0,4,rt); + output_sib(2,map,5); + output_w32(addr); + } +} +static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) +{ + if(map<0) emit_movzbl_indexed(addr+(int)g_rdram-0x80000000, rs, rt); + else { + assem_debug("movzbl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); + assert(rs!=ESP); + output_byte(0x0F); + output_byte(0xB6); + if(addr==0&&rs!=EBP) { + output_modrm(0,4,rt); + output_sib(2,map,rs); + } + else if(addr<128&&addr>=-128) { + output_modrm(1,4,rt); + output_sib(2,map,rs); + output_byte(addr); + } + else + { + output_modrm(2,4,rt); + output_sib(2,map,rs); + output_w32(addr); + } + } +} +static void emit_movzwl(int addr, int rt) +{ + assem_debug("movzwl %x,%%%s",addr,regname[rt]); + output_byte(0x0F); + output_byte(0xB7); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_movzwl_indexed(int addr, int rs, int rt) +{ + assem_debug("movzwl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x0F); + output_byte(0xB7); + output_modrm(2,rs,rt); + output_w32(addr); +} +static void emit_movzwl_tlb(int addr, int map, int rt) +{ + if(map<0) emit_movzwl(addr+(int)g_rdram-0x80000000, rt); + else + { + assem_debug("movzwl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); + output_byte(0x0F); + output_byte(0xB7); + output_modrm(0,4,rt); + output_sib(2,map,5); + output_w32(addr); + } +} +/* +static void emit_movzwl_reg(int rs, int rt) +{ + assem_debug("movzwl %%%s,%%%s",regname[rs]+1,regname[rt]); + output_byte(0x0F); + output_byte(0xB7); + output_modrm(3,rs,rt); +}*/ + +static void emit_xchg(int rs, int rt) +{ + assem_debug("xchg %%%s,%%%s",regname[rs],regname[rt]); + if(rs==EAX) { + output_byte(0x90+rt); + } + else + { + output_byte(0x87); + output_modrm(3,rs,rt); + } +} +static void emit_writeword(int rt, int addr) +{ + assem_debug("movl %%%s,%x",regname[rt],addr); + output_byte(0x89); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_writeword_indexed(int rt, int addr, int rs) +{ + assem_debug("mov %%%s,%x+%%%s",regname[rt],addr,regname[rs]); + output_byte(0x89); + if(addr<128&&addr>=-128) { + output_modrm(1,rs,rt); + if(rs==ESP) output_sib(0,4,4); + output_byte(addr); + } + else + { + output_modrm(2,rs,rt); + if(rs==ESP) output_sib(0,4,4); + output_w32(addr); + } +} +static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map, int temp) +{ + if(map<0) emit_writeword_indexed(rt, addr+(int)g_rdram-0x80000000, rs); + else { + assem_debug("mov %%%s,%x(%%%s,%%%s,1)",regname[rt],addr,regname[rs],regname[map]); + assert(rs!=ESP); + output_byte(0x89); + if(addr==0&&rs!=EBP) { + output_modrm(0,4,rt); + output_sib(0,map,rs); + } + else if(addr<128&&addr>=-128) { + output_modrm(1,4,rt); + output_sib(0,map,rs); + output_byte(addr); + } + else + { + output_modrm(2,4,rt); + output_sib(0,map,rs); + output_w32(addr); + } + } +} +static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map, int temp) +{ + assert(rh>=0); + emit_writeword_indexed_tlb(rh, addr, rs, map, temp); + emit_writeword_indexed_tlb(rl, addr+4, rs, map, temp); +} +static void emit_writehword(int rt, int addr) +{ + assem_debug("movw %%%s,%x",regname[rt]+1,addr); + output_byte(0x66); + output_byte(0x89); + output_modrm(0,5,rt); + output_w32(addr); +} +static void emit_writehword_indexed(int rt, int addr, int rs) +{ + assem_debug("movw %%%s,%x+%%%s",regname[rt]+1,addr,regname[rs]); + output_byte(0x66); + output_byte(0x89); + if(addr<128&&addr>=-128) { + output_modrm(1,rs,rt); + output_byte(addr); + } + else + { + output_modrm(2,rs,rt); + output_w32(addr); + } +} +static void emit_writebyte(int rt, int addr) +{ + if(rt<4) { + assem_debug("movb %%%cl,%x",regname[rt][1],addr); + output_byte(0x88); + output_modrm(0,5,rt); + output_w32(addr); + } + else + { + emit_xchg(EAX,rt); + emit_writebyte(EAX,addr); + emit_xchg(EAX,rt); + } +} +static void emit_writebyte_indexed(int rt, int addr, int rs) +{ + if(rt<4) { + assem_debug("movb %%%cl,%x+%%%s",regname[rt][1],addr,regname[rs]); + output_byte(0x88); + if(addr<128&&addr>=-128) { + output_modrm(1,rs,rt); + output_byte(addr); + } + else + { + output_modrm(2,rs,rt); + output_w32(addr); + } + } + else + { + emit_xchg(EAX,rt); + emit_writebyte_indexed(EAX,addr,rs==EAX?rt:rs); + emit_xchg(EAX,rt); + } +} +static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map, int temp) +{ + if(map<0) emit_writebyte_indexed(rt, addr+(int)g_rdram-0x80000000, rs); + else + if(rt<4) { + assem_debug("movb %%%cl,%x(%%%s,%%%s,1)",regname[rt][1],addr,regname[rs],regname[map]); + assert(rs!=ESP); + output_byte(0x88); + if(addr==0&&rs!=EBP) { + output_modrm(0,4,rt); + output_sib(0,map,rs); + } + else if(addr<128&&addr>=-128) { + output_modrm(1,4,rt); + output_sib(0,map,rs); + output_byte(addr); + } + else + { + output_modrm(2,4,rt); + output_sib(0,map,rs); + output_w32(addr); + } + } + else + { + emit_xchg(EAX,rt); + emit_writebyte_indexed_tlb(EAX,addr,rs==EAX?rt:rs,map==EAX?rt:map,temp); + emit_xchg(EAX,rt); + } +} +static void emit_writeword_imm(int imm, int addr) +{ + assem_debug("movl $%x,%x",imm,addr); + output_byte(0xC7); + output_modrm(0,5,0); + output_w32(addr); + output_w32(imm); +} +static void emit_writeword_imm_esp(int imm, int addr) +{ + assem_debug("mov $%x,%x(%%esp)",imm,addr); + assert(addr>=-128&&addr<128); + output_byte(0xC7); + output_modrm(1,4,0); + output_sib(0,4,4); + output_byte(addr); + output_w32(imm); +} +static void emit_writebyte_imm(int imm, int addr) +{ + assem_debug("movb $%x,%x",imm,addr); + assert(imm>=-128&&imm<128); + output_byte(0xC6); + output_modrm(0,5,0); + output_w32(addr); + output_byte(imm); +} + +static void emit_mul(int rs) +{ + assem_debug("mul %%%s",regname[rs]); + output_byte(0xF7); + output_modrm(3,rs,4); +} +static void emit_imul(int rs) +{ + assem_debug("imul %%%s",regname[rs]); + output_byte(0xF7); + output_modrm(3,rs,5); +} +static void emit_div(int rs) +{ + assem_debug("div %%%s",regname[rs]); + output_byte(0xF7); + output_modrm(3,rs,6); +} +static void emit_idiv(int rs) +{ + assem_debug("idiv %%%s",regname[rs]); + output_byte(0xF7); + output_modrm(3,rs,7); +} +static void emit_cdq() +{ + assem_debug("cdq"); + output_byte(0x99); +} + +// Load 2 immediates optimizing for small code size +static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) +{ + emit_movimm(imm1,rt1); + if(imm2-imm1<128&&imm2-imm1>=-128) emit_addimm(rt1,imm2-imm1,rt2); + else emit_movimm(imm2,rt2); +} + +// special case for checking pending_exception +static void emit_cmpmem_imm_byte(int addr,int imm) +{ + assert(imm<128&&imm>=-127); + assem_debug("cmpb $%d,%x",imm,addr); + output_byte(0x80); + output_modrm(0,5,7); + output_w32(addr); + output_byte(imm); +} + +// special case for checking invalid_code +static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) +{ + assert(imm<128&&imm>=-127); + assert(r>=0&&r<8); + emit_shrimm(r,12,r); + assem_debug("cmp $%d,%x+%%%s",imm,addr,regname[r]); + output_byte(0x80); + output_modrm(2,r,7); + output_w32(addr); + output_byte(imm); +} + +// special case for checking hash_table +static void emit_cmpmem_indexed(int addr,int rs,int rt) +{ + assert(rs>=0&&rs<8); + assert(rt>=0&&rt<8); + assem_debug("cmp %x+%%%s,%%%s",addr,regname[rs],regname[rt]); + output_byte(0x39); + output_modrm(2,rs,rt); + output_w32(addr); +} + +// Used to preload hash table entries +#ifdef IMM_PREFETCH +static void emit_prefetch(void *addr) +{ + assem_debug("prefetch %x",(int)addr); + output_byte(0x0F); + output_byte(0x18); + output_modrm(0,5,1); + output_w32((int)addr); +} +#endif + +/*void emit_submem(int r,int addr) +{ + assert(r>=0&&r<8); + assem_debug("sub %x,%%%s",addr,regname[r]); + output_byte(0x2B); + output_modrm(0,5,r); + output_w32((int)addr); +} +static void emit_subfrommem(int addr,int r) +{ + assert(r>=0&&r<8); + assem_debug("sub %%%s,%x",regname[r],addr); + output_byte(0x29); + output_modrm(0,5,r); + output_w32((int)addr); +}*/ + +static void emit_flds(int r) +{ + assem_debug("flds (%%%s)",regname[r]); + output_byte(0xd9); + if(r!=EBP) output_modrm(0,r,0); + else {output_modrm(1,EBP,0);output_byte(0);} +} +static void emit_fldl(int r) +{ + assem_debug("fldl (%%%s)",regname[r]); + output_byte(0xdd); + if(r!=EBP) output_modrm(0,r,0); + else {output_modrm(1,EBP,0);output_byte(0);} +} +static void emit_fucomip(u_int r) +{ + assem_debug("fucomip %d",r); + assert(r<8); + output_byte(0xdf); + output_byte(0xe8+r); +} +static void emit_fchs() +{ + assem_debug("fchs"); + output_byte(0xd9); + output_byte(0xe0); +} +static void emit_fabs() +{ + assem_debug("fabs"); + output_byte(0xd9); + output_byte(0xe1); +} +static void emit_fsqrt() +{ + assem_debug("fsqrt"); + output_byte(0xd9); + output_byte(0xfa); +} +static void emit_fadds(int r) +{ + assem_debug("fadds (%%%s)",regname[r]); + output_byte(0xd8); + if(r!=EBP) output_modrm(0,r,0); + else {output_modrm(1,EBP,0);output_byte(0);} +} +static void emit_faddl(int r) +{ + assem_debug("faddl (%%%s)",regname[r]); + output_byte(0xdc); + if(r!=EBP) output_modrm(0,r,0); + else {output_modrm(1,EBP,0);output_byte(0);} +} +static void emit_fadd(int r) +{ + assem_debug("fadd st%d",r); + output_byte(0xd8); + output_byte(0xc0+r); +} +static void emit_fsubs(int r) +{ + assem_debug("fsubs (%%%s)",regname[r]); + output_byte(0xd8); + if(r!=EBP) output_modrm(0,r,4); + else {output_modrm(1,EBP,4);output_byte(0);} +} +static void emit_fsubl(int r) +{ + assem_debug("fsubl (%%%s)",regname[r]); + output_byte(0xdc); + if(r!=EBP) output_modrm(0,r,4); + else {output_modrm(1,EBP,4);output_byte(0);} +} +static void emit_fsub(int r) +{ + assem_debug("fsub st%d",r); + output_byte(0xd8); + output_byte(0xe0+r); +} +static void emit_fmuls(int r) +{ + assem_debug("fmuls (%%%s)",regname[r]); + output_byte(0xd8); + if(r!=EBP) output_modrm(0,r,1); + else {output_modrm(1,EBP,1);output_byte(0);} +} +static void emit_fmull(int r) +{ + assem_debug("fmull (%%%s)",regname[r]); + output_byte(0xdc); + if(r!=EBP) output_modrm(0,r,1); + else {output_modrm(1,EBP,1);output_byte(0);} +} +static void emit_fmul(int r) +{ + assem_debug("fmul st%d",r); + output_byte(0xd8); + output_byte(0xc8+r); +} +static void emit_fdivs(int r) +{ + assem_debug("fdivs (%%%s)",regname[r]); + output_byte(0xd8); + if(r!=EBP) output_modrm(0,r,6); + else {output_modrm(1,EBP,6);output_byte(0);} +} +static void emit_fdivl(int r) +{ + assem_debug("fdivl (%%%s)",regname[r]); + output_byte(0xdc); + if(r!=EBP) output_modrm(0,r,6); + else {output_modrm(1,EBP,6);output_byte(0);} +} +static void emit_fdiv(int r) +{ + assem_debug("fdiv st%d",r); + output_byte(0xd8); + output_byte(0xf0+r); +} +static void emit_fpop() +{ + // fstp st(0) + assem_debug("fpop"); + output_byte(0xdd); + output_byte(0xd8); +} +static void emit_fildl(int r) +{ + assem_debug("fildl (%%%s)",regname[r]); + output_byte(0xdb); + if(r!=EBP) output_modrm(0,r,0); + else {output_modrm(1,EBP,0);output_byte(0);} +} +static void emit_fildll(int r) +{ + assem_debug("fildll (%%%s)",regname[r]); + output_byte(0xdf); + if(r!=EBP) output_modrm(0,r,5); + else {output_modrm(1,EBP,5);output_byte(0);} +} +static void emit_fistpl(int r) +{ + assem_debug("fistpl (%%%s)",regname[r]); + output_byte(0xdb); + if(r!=EBP) output_modrm(0,r,3); + else {output_modrm(1,EBP,3);output_byte(0);} +} +static void emit_fistpll(int r) +{ + assem_debug("fistpll (%%%s)",regname[r]); + output_byte(0xdf); + if(r!=EBP) output_modrm(0,r,7); + else {output_modrm(1,EBP,7);output_byte(0);} +} +static void emit_fstps(int r) +{ + assem_debug("fstps (%%%s)",regname[r]); + output_byte(0xd9); + if(r!=EBP) output_modrm(0,r,3); + else {output_modrm(1,EBP,3);output_byte(0);} +} +static void emit_fstpl(int r) +{ + assem_debug("fstpl (%%%s)",regname[r]); + output_byte(0xdd); + if(r!=EBP) output_modrm(0,r,3); + else {output_modrm(1,EBP,3);output_byte(0);} +} +static void emit_fnstcw_stack() +{ + assem_debug("fnstcw (%%esp)"); + output_byte(0xd9); + output_modrm(0,4,7); + output_sib(0,4,4); +} +static void emit_fldcw_stack() +{ + assem_debug("fldcw (%%esp)"); + output_byte(0xd9); + output_modrm(0,4,5); + output_sib(0,4,4); +} +static void emit_fldcw_indexed(int addr,int r) +{ + assem_debug("fldcw %x(%%%s)",addr,regname[r]); + output_byte(0xd9); + output_modrm(0,4,5); + output_sib(1,r,5); + output_w32(addr); +} +static void emit_fldcw(int addr) +{ + assem_debug("fldcw %x",addr); + output_byte(0xd9); + output_modrm(0,5,5); + output_w32(addr); +} +#ifdef __SSE__ +static void emit_movss_load(u_int addr,u_int ssereg) +{ + assem_debug("movss (%%%s),xmm%d",regname[addr],ssereg); + assert(ssereg<8); + output_byte(0xf3); + output_byte(0x0f); + output_byte(0x10); + if(addr!=EBP) output_modrm(0,addr,ssereg); + else {output_modrm(1,EBP,ssereg);output_byte(0);} +} +static void emit_movsd_load(u_int addr,u_int ssereg) +{ + assem_debug("movsd (%%%s),xmm%d",regname[addr],ssereg); + assert(ssereg<8); + output_byte(0xf2); + output_byte(0x0f); + output_byte(0x10); + if(addr!=EBP) output_modrm(0,addr,ssereg); + else {output_modrm(1,EBP,ssereg);output_byte(0);} +} +static void emit_movd_store(u_int ssereg,u_int addr) +{ + assem_debug("movd xmm%d,(%%%s)",ssereg,regname[addr]); + assert(ssereg<8); + output_byte(0x66); + output_byte(0x0f); + output_byte(0x7e); + if(addr!=EBP) output_modrm(0,addr,ssereg); + else {output_modrm(1,EBP,ssereg);output_byte(0);} +} +static void emit_cvttps2dq(u_int ssereg1,u_int ssereg2) +{ + assem_debug("cvttps2dq xmm%d,xmm%d",ssereg1,ssereg2); + assert(ssereg1<8); + assert(ssereg2<8); + output_byte(0xf3); + output_byte(0x0f); + output_byte(0x5b); + output_modrm(3,ssereg1,ssereg2); +} +static void emit_cvttpd2dq(u_int ssereg1,u_int ssereg2) +{ + assem_debug("cvttpd2dq xmm%d,xmm%d",ssereg1,ssereg2); + assert(ssereg1<8); + assert(ssereg2<8); + output_byte(0x66); + output_byte(0x0f); + output_byte(0xe6); + output_modrm(3,ssereg1,ssereg2); +} +#endif + +/* Stubs/epilogue */ + +static void emit_extjump2(int addr, int target, int linker) +{ + u_char *ptr=(u_char *)addr; + if(*ptr==0x0f) + { + assert(ptr[1]>=0x80&&ptr[1]<=0x8f); + addr+=2; + } + else + { + assert(*ptr==0xe8||*ptr==0xe9); + addr++; + } + emit_movimm(target,EAX); + emit_movimm(addr,EBX); + //assert(addr>=0x7000000&&addr<0x7FFFFFF); + //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000)); +//DEBUG > +#ifdef DEBUG_CYCLE_COUNT + emit_readword((int)&last_count,ECX); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); +#endif +//DEBUG < + emit_jmp(linker); +} + +static void emit_extjump(int addr, int target) +{ + emit_extjump2(addr, target, (int)dyna_linker); +} +static void emit_extjump_ds(int addr, int target) +{ + emit_extjump2(addr, target, (int)dyna_linker_ds); +} + +static void do_readstub(int n) +{ + assem_debug("do_readstub %x",start+stubs[n][3]*4); + set_jump_target(stubs[n][1],(int)out); + int type=stubs[n][0]; + int i=stubs[n][3]; + int rs=stubs[n][4]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + signed char *i_regmap=i_regs->regmap; + int addr=get_reg(i_regmap,AGEN1+(i&1)); + int rth,rt; + int ds; + if(itype[i]==C1LS||itype[i]==LOADLR) { + rth=get_reg(i_regmap,FTEMP|64); + rt=get_reg(i_regmap,FTEMP); + }else{ + rth=get_reg(i_regmap,rt1[i]|64); + rt=get_reg(i_regmap,rt1[i]); + } + assert(rs>=0); + if(addr<0) addr=rt; + if(addr<0&&itype[i]!=C1LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1); + assert(addr>=0); + int ftable=0; + if(type==LOADB_STUB||type==LOADBU_STUB) + ftable=(int)readmemb; + if(type==LOADH_STUB||type==LOADHU_STUB) + ftable=(int)readmemh; + if(type==LOADW_STUB) + ftable=(int)readmem; + if(type==LOADD_STUB) + ftable=(int)readmemd; + emit_writeword(rs,(int)&address); + emit_shrimm(rs,16,addr); + emit_movmem_indexedx4(ftable,addr,addr); + emit_pusha(); + ds=i_regs!=®s[i]; + int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]); + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&~(1<>rs1[i])&1)<<1)+ds,32); + emit_add(cc,temp,cc); + emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_callreg(addr); + // We really shouldn't need to update the count here, + // but not doing so causes random crashes... + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(stubs[n][6]+1),HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + emit_popa(); + if((cc=get_reg(i_regmap,CCREG))>=0) { + emit_loadreg(CCREG,cc); + } + if(rt>=0) { + if(type==LOADB_STUB) + emit_movsbl((int)&readmem_dword,rt); + if(type==LOADBU_STUB) + emit_movzbl((int)&readmem_dword,rt); + if(type==LOADH_STUB) + emit_movswl((int)&readmem_dword,rt); + if(type==LOADHU_STUB) + emit_movzwl((int)&readmem_dword,rt); + if(type==LOADW_STUB) + emit_readword((int)&readmem_dword,rt); + if(type==LOADD_STUB) { + emit_readword((int)&readmem_dword,rt); + if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth); + } + } + emit_jmp(stubs[n][2]); // return address +} + +static void inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) +{ + assem_debug("inline_readstub"); + int rs=get_reg(regmap,target); + int rth=get_reg(regmap,target|64); + int rt=get_reg(regmap,target); + if(rs<0) rs=get_reg(regmap,-1); + assert(rs>=0); + int ftable=0; + if(type==LOADB_STUB||type==LOADBU_STUB) + ftable=(int)readmemb; + if(type==LOADH_STUB||type==LOADHU_STUB) + ftable=(int)readmemh; + if(type==LOADW_STUB) + ftable=(int)readmem; + if(type==LOADD_STUB) + ftable=(int)readmemd; + #ifdef HOST_IMM_ADDR32 + emit_writeword_imm(addr,(int)&address); + #else + emit_writeword(rs,(int)&address); + #endif + emit_pusha(); + if((signed int)addr>=(signed int)0xC0000000) { + // Theoretically we can have a pagefault here, if the TLB has never + // been enabled and the address is outside the range 80000000..BFFFFFFF + // Write out the registers so the pagefault can be handled. This is + // a very rare case and likely represents a bug. + int ds=regmap!=regs[i].regmap; + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty); + else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty); + } + int cc=get_reg(regmap,CCREG); + int temp; + if(cc<0) { + if(rs==HOST_CCREG) + { + cc=0;temp=1; + assert(cc!=HOST_CCREG); + assert(temp!=HOST_CCREG); + emit_loadreg(CCREG,cc); + } + else + { + cc=HOST_CCREG; + emit_loadreg(CCREG,cc); + temp=!rs; + } + } + else + { + temp=!rs; + } + emit_readword((int)&last_count,temp); + emit_addimm(cc,CLOCK_DIVIDER*(adj+1),cc); + emit_add(cc,temp,cc); + emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + if((signed int)addr>=(signed int)0xC0000000) { + // Pagefault address + int ds=regmap!=regs[i].regmap; + emit_writeword_imm_esp(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,32); + } + emit_call(((u_int *)ftable)[addr>>16]); + // We really shouldn't need to update the count here, + // but not doing so causes random crashes... + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(adj+1),HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + emit_popa(); + if((cc=get_reg(regmap,CCREG))>=0) { + emit_loadreg(CCREG,cc); + } + if(rt>=0) { + if(type==LOADB_STUB) + emit_movsbl((int)&readmem_dword,rt); + if(type==LOADBU_STUB) + emit_movzbl((int)&readmem_dword,rt); + if(type==LOADH_STUB) + emit_movswl((int)&readmem_dword,rt); + if(type==LOADHU_STUB) + emit_movzwl((int)&readmem_dword,rt); + if(type==LOADW_STUB) + emit_readword((int)&readmem_dword,rt); + if(type==LOADD_STUB) { + emit_readword((int)&readmem_dword,rt); + if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth); + } + } +} + +static void do_writestub(int n) +{ + assem_debug("do_writestub %x",start+stubs[n][3]*4); + set_jump_target(stubs[n][1],(int)out); + int type=stubs[n][0]; + int i=stubs[n][3]; + int rs=stubs[n][4]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + signed char *i_regmap=i_regs->regmap; + int addr=get_reg(i_regmap,AGEN1+(i&1)); + int rth,rt,r; + int ds; + if(itype[i]==C1LS) { + rth=get_reg(i_regmap,FTEMP|64); + rt=get_reg(i_regmap,r=FTEMP); + }else{ + rth=get_reg(i_regmap,rs2[i]|64); + rt=get_reg(i_regmap,r=rs2[i]); + } + assert(rs>=0); + assert(rt>=0); + if(addr<0) addr=get_reg(i_regmap,-1); + assert(addr>=0); + int ftable=0; + if(type==STOREB_STUB) + ftable=(int)writememb; + if(type==STOREH_STUB) + ftable=(int)writememh; + if(type==STOREW_STUB) + ftable=(int)writemem; + if(type==STORED_STUB) + ftable=(int)writememd; + emit_writeword(rs,(int)&address); + emit_shrimm(rs,16,addr); + emit_movmem_indexedx4(ftable,addr,addr); + if(type==STOREB_STUB) + emit_writebyte(rt,(int)&cpu_byte); + if(type==STOREH_STUB) + emit_writehword(rt,(int)&cpu_hword); + if(type==STOREW_STUB) + emit_writeword(rt,(int)&cpu_word); + if(type==STORED_STUB) { + emit_writeword(rt,(int)&cpu_dword); + emit_writeword(r?rth:rt,(int)&cpu_dword+4); + } + emit_pusha(); + ds=i_regs!=®s[i]; + int real_rs=get_reg(i_regmap,rs1[i]); + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&~(1<>rs1[i])&1)<<1)+ds,32); + emit_add(cc,temp,cc); + emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_callreg(addr); + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(stubs[n][6]+1),HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + emit_popa(); + if((cc=get_reg(i_regmap,CCREG))>=0) { + emit_loadreg(CCREG,cc); + } + emit_jmp(stubs[n][2]); // return address +} + +static void inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) +{ + assem_debug("inline_writestub"); + int rs=get_reg(regmap,-1); + int rth=get_reg(regmap,target|64); + int rt=get_reg(regmap,target); + assert(rs>=0); + assert(rt>=0); + int ftable=0; + if(type==STOREB_STUB) + ftable=(int)writememb; + if(type==STOREH_STUB) + ftable=(int)writememh; + if(type==STOREW_STUB) + ftable=(int)writemem; + if(type==STORED_STUB) + ftable=(int)writememd; + emit_writeword(rs,(int)&address); + if(type==STOREB_STUB) + emit_writebyte(rt,(int)&cpu_byte); + if(type==STOREH_STUB) + emit_writehword(rt,(int)&cpu_hword); + if(type==STOREW_STUB) + emit_writeword(rt,(int)&cpu_word); + if(type==STORED_STUB) { + emit_writeword(rt,(int)&cpu_dword); + emit_writeword(target?rth:rt,(int)&cpu_dword+4); + } + emit_pusha(); + if((signed int)addr>=(signed int)0xC0000000) { + // Theoretically we can have a pagefault here, if the TLB has never + // been enabled and the address is outside the range 80000000..BFFFFFFF + // Write out the registers so the pagefault can be handled. This is + // a very rare case and likely represents a bug. + int ds=regmap!=regs[i].regmap; + if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty); + else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty); + } + int cc=get_reg(regmap,CCREG); + int temp; + if(cc<0) { + if(rs==HOST_CCREG) + { + cc=0;temp=1; + assert(cc!=HOST_CCREG); + assert(temp!=HOST_CCREG); + emit_loadreg(CCREG,cc); + } + else + { + cc=HOST_CCREG; + emit_loadreg(CCREG,cc); + temp=!rs; + } + } + else + { + temp=!rs; + } + emit_readword((int)&last_count,temp); + emit_addimm(cc,CLOCK_DIVIDER*(adj+1),cc); + emit_add(cc,temp,cc); + emit_writeword(cc,(int)&g_cp0_regs[CP0_COUNT_REG]); + if((signed int)addr>=(signed int)0xC0000000) { + // Pagefault address + int ds=regmap!=regs[i].regmap; + emit_writeword_imm_esp(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,32); + } + emit_call(((u_int *)ftable)[addr>>16]); + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(adj+1),HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + emit_popa(); + if((cc=get_reg(regmap,CCREG))>=0) { + emit_loadreg(CCREG,cc); + } +} + +static void do_unalignedwritestub(int n) +{ + set_jump_target(stubs[n][1],(int)out); + output_byte(0xCC); + emit_jmp(stubs[n][2]); // return address +} + +static void do_invstub(int n) +{ + set_jump_target(stubs[n][1],(int)out); + emit_call(invalidate_block_reg[stubs[n][4]]); + emit_jmp(stubs[n][2]); // return address +} + +static int do_dirty_stub(int i) +{ + assem_debug("do_dirty_stub %x",start+i*4); + emit_pushimm(start+i*4); + emit_movimm((int)start<(int)0xC0000000?(int)source:(int)start,EAX); + emit_movimm((int)copy,EBX); + emit_movimm(slen*4,ECX); + emit_call((int)start<(int)0xC0000000?(int)&verify_code:(int)&verify_code_vm); + emit_addimm(ESP,4,ESP); + int entry=(int)out; + load_regs_entry(i); + if(entry==(int)out) entry=instr_addr[i]; + emit_jmp(instr_addr[i]); + return entry; +} + +static void do_dirty_stub_ds() +{ + emit_pushimm(start+1); + emit_movimm((int)start<(int)0xC0000000?(int)source:(int)start,EAX); + emit_movimm((int)copy,EBX); + emit_movimm(slen*4,ECX); + emit_call((int)&verify_code_ds); + emit_addimm(ESP,4,ESP); +} + +static void do_cop1stub(int n) +{ + assem_debug("do_cop1stub %x",start+stubs[n][3]*4); + set_jump_target(stubs[n][1],(int)out); + int i=stubs[n][3]; + struct regstat *i_regs=(struct regstat *)stubs[n][5]; + int ds=stubs[n][6]; + if(!ds) { + load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + //if(i_regs!=®s[i]) DebugMessage(M64MSG_VERBOSE, "oops: regs[i]=%x i_regs=%x",(int)®s[i],(int)i_regs); + } + //else {DebugMessage(M64MSG_VERBOSE, "fp exception in delay slot");} + wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); + if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_movimm(start+(i-ds)*4,EAX); // Get PC + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... + emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception); +} + +/* TLB */ + +static int do_tlb_r(int s,int ar,int map,int cache,int x,int a,int shift,int c,u_int addr) +{ + if(c) { + if((signed int)addr>=(signed int)0xC0000000) { + emit_readword((int)(memory_map+(addr>>12)),map); + } + else + return -1; // No mapping + } + else { + if(s!=map) emit_mov(s,map); + emit_shrimm(map,12,map); + // Schedule this while we wait on the load + //if(x) emit_xorimm(addr,x,addr); + if(shift>=0) emit_lea8(s,shift); + if(~a) emit_andimm(s,a,ar); + emit_movmem_indexedx4((int)memory_map,map,map); + } + return map; +} +static int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr) +{ + if(!c||(signed int)addr>=(signed int)0xC0000000) { + emit_test(map,map); + *jaddr=(int)out; + emit_js(0); + } + return map; +} + +static void gen_tlb_addr_r(int ar, int map) { + if(map>=0) { + emit_leairrx4(0,ar,map,ar); + } +} + +static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) +{ + if(c) { + if(addr<0x80800000||addr>=0xC0000000) { + emit_readword((int)(memory_map+(addr>>12)),map); + } + else + return -1; // No mapping + } + else { + if(s!=map) emit_mov(s,map); + //if(s!=ar) emit_mov(s,ar); + emit_shrimm(map,12,map); + // Schedule this while we wait on the load + //if(x) emit_xorimm(s,x,addr); + emit_movmem_indexedx4((int)memory_map,map,map); + } + emit_shlimm(map,2,map); + return map; +} +static void do_tlb_w_branch(int map, int c, u_int addr, int *jaddr) +{ + if(!c||addr<0x80800000||addr>=0xC0000000) { + *jaddr=(int)out; + emit_jc(0); + } +} + +static void gen_tlb_addr_w(int ar, int map) { + if(map>=0) { + emit_leairrx1(0,ar,map,ar); + } +} + +// We don't need this for x86 +static void generate_map_const(u_int addr,int reg) { + // void *mapaddr=memory_map+(addr>>12); +} + +/* Special assem */ + +static void shift_assemble_x86(int i,struct regstat *i_regs) +{ + if(rt1[i]) { + if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV + { + char s,t,shift; + t=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + shift=get_reg(i_regs->regmap,rs2[i]); + if(t>=0){ + if(rs1[i]==0) + { + emit_zeroreg(t); + } + else if(rs2[i]==0) + { + assert(s>=0); + if(s!=t) emit_mov(s,t); + } + else + { + char temp=get_reg(i_regs->regmap,-1); + assert(s>=0); + if(t==ECX&&s!=ECX) { + if(shift!=ECX) emit_mov(shift,ECX); + if(rt1[i]==rs2[i]) {shift=temp;} + if(s!=shift) emit_mov(s,shift); + } + else + { + if(rt1[i]==rs2[i]) {emit_mov(shift,temp);shift=temp;} + if(s!=t) emit_mov(s,t); + if(shift!=ECX) { + if(i_regs->regmap[ECX]<0) + emit_mov(shift,ECX); + else + emit_xchg(shift,ECX); + } + } + if(opcode2[i]==4) // SLLV + { + emit_shlcl(t==ECX?shift:t); + } + if(opcode2[i]==6) // SRLV + { + emit_shrcl(t==ECX?shift:t); + } + if(opcode2[i]==7) // SRAV + { + emit_sarcl(t==ECX?shift:t); + } + if(shift!=ECX&&i_regs->regmap[ECX]>=0) emit_xchg(shift,ECX); + } + } + } else { // DSLLV/DSRLV/DSRAV + char sh,sl,th,tl,shift; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + shift=get_reg(i_regs->regmap,rs2[i]); + if(tl>=0){ + if(rs1[i]==0) + { + emit_zeroreg(tl); + if(th>=0) emit_zeroreg(th); + } + else if(rs2[i]==0) + { + assert(sl>=0); + if(sl!=tl) emit_mov(sl,tl); + if(th>=0&&sh!=th) emit_mov(sh,th); + } + else + { + // FIXME: What if shift==tl ? + assert(shift!=tl); + int temp=get_reg(i_regs->regmap,-1); + int real_th=th; + if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register + assert(sl>=0); + assert(sh>=0); + if(tl==ECX&&sl!=ECX) { + if(shift!=ECX) emit_mov(shift,ECX); + if(sl!=shift) emit_mov(sl,shift); + if(th>=0 && sh!=th) emit_mov(sh,th); + } + else if(th==ECX&&sh!=ECX) { + if(shift!=ECX) emit_mov(shift,ECX); + if(sh!=shift) emit_mov(sh,shift); + if(sl!=tl) emit_mov(sl,tl); + } + else + { + if(sl!=tl) emit_mov(sl,tl); + if(th>=0 && sh!=th) emit_mov(sh,th); + if(shift!=ECX) { + if(i_regs->regmap[ECX]<0) + emit_mov(shift,ECX); + else + emit_xchg(shift,ECX); + } + } + if(opcode2[i]==0x14) // DSLLV + { + if(th>=0) emit_shldcl(th==ECX?shift:th,tl==ECX?shift:tl); + emit_shlcl(tl==ECX?shift:tl); + emit_testimm(ECX,32); + if(th>=0) emit_cmovne_reg(tl==ECX?shift:tl,th==ECX?shift:th); + emit_cmovne(&const_zero,tl==ECX?shift:tl); + } + if(opcode2[i]==0x16) // DSRLV + { + assert(th>=0); + emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); + emit_shrcl(th==ECX?shift:th); + emit_testimm(ECX,32); + emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); + if(real_th>=0) emit_cmovne(&const_zero,th==ECX?shift:th); + } + if(opcode2[i]==0x17) // DSRAV + { + assert(th>=0); + emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); + if(real_th>=0) { + assert(temp>=0); + emit_mov(th==ECX?shift:th,temp==ECX?shift:temp); + } + emit_sarcl(th==ECX?shift:th); + if(real_th>=0) emit_sarimm(temp==ECX?shift:temp,31,temp==ECX?shift:temp); + emit_testimm(ECX,32); + emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); + if(real_th>=0) emit_cmovne_reg(temp==ECX?shift:temp,th==ECX?shift:th); + } + if(shift!=ECX&&(i_regs->regmap[ECX]>=0||temp==ECX)) emit_xchg(shift,ECX); + } + } + } + } +} +#define shift_assemble shift_assemble_x86 + +static void loadlr_assemble_x86(int i,struct regstat *i_regs) +{ + int s,th,tl,temp,temp2,addr,map=-1; + int offset; + int jaddr=0; + int memtarget,c=0; + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + temp=get_reg(i_regs->regmap,-1); + temp2=get_reg(i_regs->regmap,FTEMP); + addr=get_reg(i_regs->regmap,AGEN1+(i&1)); + assert(addr<0); + offset=imm[i]; + for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { + c=(i_regs->wasconst>>s)&1; + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } + if(!using_tlb) { + if(!c) { + emit_lea8(addr,temp); + if (opcode[i]==0x22||opcode[i]==0x26) { + emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR + }else{ + emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR + } + emit_cmpimm(addr,0x800000); + jaddr=(int)out; + emit_jno(0); + } + else { + if (opcode[i]==0x22||opcode[i]==0x26) { + emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR + }else{ + emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR + } + } + }else{ // using tlb + int a; + if(c) { + a=-1; + }else if (opcode[i]==0x22||opcode[i]==0x26) { + a=0xFFFFFFFC; // LWL/LWR + }else{ + a=0xFFFFFFF8; // LDL/LDR + } + map=get_reg(i_regs->regmap,TLREG); + assert(map>=0); + reglist&=~(1<regmap,FTEMP,ccadj[i],reglist); + if(rt1[i]) { + assert(tl>=0); + emit_andimm(temp,24,temp); + if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR + if(temp==ECX) + { + int temp3=EDX; + if(temp3==temp2) temp3++; + emit_pushreg(temp3); + emit_movimm(-1,temp3); + if (opcode[i]==0x26) { + emit_shrcl(temp3); + emit_shrcl(temp2); + }else{ + emit_shlcl(temp3); + emit_shlcl(temp2); + } + emit_mov(temp3,ECX); + emit_not(ECX,ECX); + emit_popreg(temp3); + } + else + { + int temp3=EBP; + if(temp3==temp) temp3++; + if(temp3==temp2) temp3++; + if(temp3==temp) temp3++; + emit_xchg(ECX,temp); + emit_pushreg(temp3); + emit_movimm(-1,temp3); + if (opcode[i]==0x26) { + emit_shrcl(temp3); + emit_shrcl(temp2==ECX?temp:temp2); + }else{ + emit_shlcl(temp3); + emit_shlcl(temp2==ECX?temp:temp2); + } + emit_not(temp3,temp3); + emit_mov(temp,ECX); + emit_mov(temp3,temp); + emit_popreg(temp3); + } + emit_and(temp,tl,tl); + emit_or(temp2,tl,tl); + //emit_storereg(rt1[i],tl); // DEBUG + /*emit_pusha(); + //save_regs(0x100f); + emit_readword((int)&last_count,ECX); + if(get_reg(i_regs->regmap,CCREG)<0) + emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)memdebug); + emit_popa(); + //restore_regs(0x100f);*/ + } + } + if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR + if(s>=0) + if((i_regs->wasdirty>>s)&1) + emit_storereg(rs1[i],s); + if(get_reg(i_regs->regmap,rs1[i]|64)>=0) + if((i_regs->wasdirty>>get_reg(i_regs->regmap,rs1[i]|64))&1) + emit_storereg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64)); + int temp2h=get_reg(i_regs->regmap,FTEMP|64); + if(!c||memtarget) { + //if(th>=0) emit_readword_indexed((int)g_rdram-0x80000000,temp2,temp2h); + //emit_readword_indexed((int)g_rdram-0x7FFFFFFC,temp2,temp2); + emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); + if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist); + if(rt1[i]) { + assert(th>=0); + assert(tl>=0); + emit_andimm(temp,56,temp); + emit_pushreg(temp); + emit_pushreg(temp2h); + emit_pushreg(temp2); + emit_pushreg(th); + emit_pushreg(tl); + if(opcode[i]==0x1A) emit_call((int)ldl_merge); + if(opcode[i]==0x1B) emit_call((int)ldr_merge); + emit_addimm(ESP,20,ESP); + if(tl!=EDX) { + if(tl!=EAX) emit_mov(EAX,tl); + if(th!=EDX) emit_mov(EDX,th); + } else + if(th!=EAX) { + if(th!=EDX) emit_mov(EDX,th); + if(tl!=EAX) emit_mov(EAX,tl); + } else { + emit_xchg(EAX,EDX); + } + if(s>=0) emit_loadreg(rs1[i],s); + if(get_reg(i_regs->regmap,rs1[i]|64)>=0) + emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64)); + } + } +} +#define loadlr_assemble loadlr_assemble_x86 + +static void cop0_assemble(int i,struct regstat *i_regs) +{ + if(opcode2[i]==0) // MFC0 + { + if(rt1[i]) { + signed char t=get_reg(i_regs->regmap,rt1[i]); + char copr=(source[i]>>11)&0x1f; + if(t>=0) { + emit_writeword_imm((int)&fake_pc,(int)&PC); + emit_writebyte_imm((source[i]>>11)&0x1f,(int)&(fake_pc.f.r.nrd)); + if(copr==9) { + emit_readword((int)&last_count,ECX); + emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + } + emit_call((int)cached_interpreter_table.MFC0); + emit_readword((int)&readmem_dword,t); + } + } + } + else if(opcode2[i]==4) // MTC0 + { + signed char s=get_reg(i_regs->regmap,rs1[i]); + char copr=(source[i]>>11)&0x1f; + assert(s>=0); + emit_writeword(s,(int)&readmem_dword); + emit_pusha(); + emit_writeword_imm((int)&fake_pc,(int)&PC); + emit_writebyte_imm((source[i]>>11)&0x1f,(int)&(fake_pc.f.r.nrd)); + if(copr==9||copr==11||copr==12) { + if(copr==12&&!is_delayslot) { + wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); + } + emit_readword((int)&last_count,ECX); + emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + } + // What a mess. The status register (12) can enable interrupts, + // so needs a special case to handle a pending interrupt. + // The interrupt must be taken immediately, because a subsequent + // instruction might disable interrupts again. + if(copr==12&&!is_delayslot) { + emit_writeword_imm(start+i*4+4,(int)&pcaddr); + emit_writebyte_imm(0,(int)&pending_exception); + } + //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12); + //else + emit_call((int)cached_interpreter_table.MTC0); + if(copr==9||copr==11||copr==12) { + emit_readword((int)&g_cp0_regs[CP0_COUNT_REG],HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); + emit_storereg(CCREG,HOST_CCREG); + } + emit_popa(); + if(copr==12) { + assert(!is_delayslot); + //if(is_delayslot) output_byte(0xcc); + emit_cmpmem_imm_byte((int)&pending_exception,0); + emit_jne((int)&do_interrupt); + } + cop1_usable=0; + } + else + { + assert(opcode2[i]==0x10); + if((source[i]&0x3f)==0x01) // TLBR + emit_call((int)cached_interpreter_table.TLBR); + if((source[i]&0x3f)==0x02) // TLBWI + emit_call((int)TLBWI_new); + if((source[i]&0x3f)==0x06) { // TLBWR + // The TLB entry written by TLBWR is dependent on the count, + // so update the cycle count + emit_readword((int)&last_count,ECX); + if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)TLBWR_new); + } + if((source[i]&0x3f)==0x08) // TLBP + emit_call((int)cached_interpreter_table.TLBP); + if((source[i]&0x3f)==0x18) // ERET + { + int count=ccadj[i]; + if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here? + emit_jmp((int)jump_eret); + } + } +} + +static void cop1_assemble(int i,struct regstat *i_regs) +{ + // Check cop1 unusable + if(!cop1_usable) { + signed char rs=get_reg(i_regs->regmap,CSREG); + assert(rs>=0); + emit_testimm(rs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + if (opcode2[i]==0) { // MFC1 + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],tl); + emit_readword_indexed(0,tl,tl); + } + } + else if (opcode2[i]==1) { // DMFC1 + signed char tl=get_reg(i_regs->regmap,rt1[i]); + signed char th=get_reg(i_regs->regmap,rt1[i]|64); + if(tl>=0) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],tl); + if(th>=0) emit_readword_indexed(4,tl,th); + emit_readword_indexed(0,tl,tl); + } + } + else if (opcode2[i]==4) { // MTC1 + signed char sl=get_reg(i_regs->regmap,rs1[i]); + signed char temp=get_reg(i_regs->regmap,-1); + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_writeword_indexed(sl,0,temp); + } + else if (opcode2[i]==5) { // DMTC1 + signed char sl=get_reg(i_regs->regmap,rs1[i]); + signed char sh=rs1[i]>0?get_reg(i_regs->regmap,rs1[i]|64):sl; + signed char temp=get_reg(i_regs->regmap,-1); + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_writeword_indexed(sh,4,temp); + emit_writeword_indexed(sl,0,temp); + } + else if (opcode2[i]==2) // CFC1 + { + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) { + u_int copr=(source[i]>>11)&0x1f; + if(copr==0) emit_readword((int)&FCR0,tl); + if(copr==31) emit_readword((int)&FCR31,tl); + } + } + else if (opcode2[i]==6) // CTC1 + { + signed char sl=get_reg(i_regs->regmap,rs1[i]); + u_int copr=(source[i]>>11)&0x1f; + assert(sl>=0); + if(copr==31) + { + emit_writeword(sl,(int)&FCR31); + // Set the rounding mode + char temp=get_reg(i_regs->regmap,-1); + emit_movimm(3,temp); + emit_and(sl,temp,temp); + emit_fldcw_indexed((int)&rounding_modes,temp); + } + } +} + +static void fconv_assemble_x86(int i,struct regstat *i_regs) +{ + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char rs=get_reg(i_regs->regmap,CSREG); + assert(rs>=0); + emit_testimm(rs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } +#ifdef __SSE__ + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_movss_load(temp,0); + emit_cvttps2dq(0,0); // float->int, truncate + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_movd_store(0,temp); + return; + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_movsd_load(temp,0); + emit_cvttpd2dq(0,0); // double->int, truncate + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_movd_store(0,temp); + return; + } +#endif + + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_fildl(temp); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fstps(temp); + return; + } + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_fildl(temp); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fstpl(temp); + return; + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { // cvt_s_l + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fildll(temp); + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fstps(temp); + return; + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { // cvt_d_l + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fildll(temp); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fstpl(temp); + return; + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fstpl(temp); + return; + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fstps(temp); + return; + } + + if(opcode2[i]==0x10) { // cvt_*_s + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + } + if(opcode2[i]==0x11) { // cvt_*_d + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + } + if((source[i]&0x3f)<0x10) { + emit_fnstcw_stack(); + if((source[i]&3)==0) emit_fldcw((int)&round_mode); //DebugMessage(M64MSG_VERBOSE, "round"); + if((source[i]&3)==1) emit_fldcw((int)&trunc_mode); //DebugMessage(M64MSG_VERBOSE, "trunc"); + if((source[i]&3)==2) emit_fldcw((int)&ceil_mode); //DebugMessage(M64MSG_VERBOSE, "ceil"); + if((source[i]&3)==3) emit_fldcw((int)&floor_mode); //DebugMessage(M64MSG_VERBOSE, "floor"); + } + if((source[i]&0x3f)==0x24||(source[i]&0x3c)==0x0c) { // cvt_w_* + if(opcode2[i]!=0x10||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fistpl(temp); + } + if((source[i]&0x3f)==0x25||(source[i]&0x3c)==0x08) { // cvt_l_* + if(opcode2[i]!=0x11||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fistpll(temp); + } + if((source[i]&0x3f)<0x10) { + emit_fldcw_stack(); + } + return; + + // C emulation code for debugging + + emit_pusha(); + + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)cvt_s_w); + } + if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)cvt_d_w); + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)cvt_s_l); + } + if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)cvt_d_l); + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)cvt_d_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)cvt_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)cvt_l_s); + } + + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)cvt_s_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)cvt_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)cvt_l_d); + } + + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)round_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)trunc_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)ceil_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)floor_l_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)round_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)trunc_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)ceil_w_s); + } + if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + emit_call((int)floor_w_s); + } + + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)round_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)trunc_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)ceil_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)floor_l_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)round_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)trunc_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)ceil_w_d); + } + if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + emit_call((int)floor_w_d); + } + + emit_addimm(ESP,8,ESP); + emit_popa(); + //emit_loadreg(CSREG,rs); + return; +} +#define fconv_assemble fconv_assemble_x86 + +static void fcomp_assemble(int i,struct regstat *i_regs) +{ + signed char fs=get_reg(i_regs->regmap,FSREG); + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char cs=get_reg(i_regs->regmap,CSREG); + assert(cs>=0); + emit_testimm(cs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + + if((source[i]&0x3f)==0x30) { + emit_andimm(fs,~0x800000,fs); + return; + } + + if((source[i]&0x3e)==0x38) { + // sf/ngle - these should throw exceptions for NaNs + emit_andimm(fs,~0x800000,fs); + return; + } + + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],temp); + emit_flds(temp); + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + emit_movimm(0x800000,temp); + emit_or(fs,temp,fs); + emit_xor(temp,fs,temp); + emit_fucomip(1); + emit_fpop(); + if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_s + if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_s + if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_s + if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_s + if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_s + if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_s + if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_s + if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_s + if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_s + if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_s + if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_s + if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_s + if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_s + return; + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],temp); + emit_fldl(temp); + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + emit_movimm(0x800000,temp); + emit_or(fs,temp,fs); + emit_xor(temp,fs,temp); + emit_fucomip(1); + emit_fpop(); + if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_d + if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_d + if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_d + if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_d + if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_d + if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_d + if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_d + if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_d + if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_d + if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_d + if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_d + if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_d + if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_d + return; + } + + emit_pusha(); + if(opcode2[i]==0x10) { + emit_pushmem((int)®_cop1_simple[(source[i]>>16)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + if((source[i]&0x3f)==0x30) emit_call((int)c_f_s); + if((source[i]&0x3f)==0x31) emit_call((int)c_un_s); + if((source[i]&0x3f)==0x32) emit_call((int)c_eq_s); + if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_s); + if((source[i]&0x3f)==0x34) emit_call((int)c_olt_s); + if((source[i]&0x3f)==0x35) emit_call((int)c_ult_s); + if((source[i]&0x3f)==0x36) emit_call((int)c_ole_s); + if((source[i]&0x3f)==0x37) emit_call((int)c_ule_s); + if((source[i]&0x3f)==0x38) emit_call((int)c_sf_s); + if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_s); + if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_s); + if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_s); + if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_s); + if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_s); + if((source[i]&0x3f)==0x3e) emit_call((int)c_le_s); + if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_s); + } + if(opcode2[i]==0x11) { + emit_pushmem((int)®_cop1_double[(source[i]>>16)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + if((source[i]&0x3f)==0x30) emit_call((int)c_f_d); + if((source[i]&0x3f)==0x31) emit_call((int)c_un_d); + if((source[i]&0x3f)==0x32) emit_call((int)c_eq_d); + if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_d); + if((source[i]&0x3f)==0x34) emit_call((int)c_olt_d); + if((source[i]&0x3f)==0x35) emit_call((int)c_ult_d); + if((source[i]&0x3f)==0x36) emit_call((int)c_ole_d); + if((source[i]&0x3f)==0x37) emit_call((int)c_ule_d); + if((source[i]&0x3f)==0x38) emit_call((int)c_sf_d); + if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_d); + if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_d); + if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_d); + if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_d); + if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_d); + if((source[i]&0x3f)==0x3e) emit_call((int)c_le_d); + if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_d); + } + emit_addimm(ESP,8,ESP); + emit_popa(); + emit_loadreg(FSREG,fs); + return; +} + +static void float_assemble(int i,struct regstat *i_regs) +{ + signed char temp=get_reg(i_regs->regmap,-1); + assert(temp>=0); + // Check cop1 unusable + if(!cop1_usable) { + signed char cs=get_reg(i_regs->regmap,CSREG); + assert(cs>=0); + emit_testimm(cs,0x20000000); + int jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + + if((source[i]&0x3f)==6) // mov + { + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + emit_fstps(temp); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + emit_fstpl(temp); + } + } + return; + } + + if((source[i]&0x3f)>3) + { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + } + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + } + } + if((source[i]&0x3f)==4) // sqrt + emit_fsqrt(); + if((source[i]&0x3f)==5) // abs + emit_fabs(); + if((source[i]&0x3f)==7) // neg + emit_fchs(); + if(opcode2[i]==0x10) { + emit_fstps(temp); + } + if(opcode2[i]==0x11) { + emit_fstpl(temp); + } + return; + } + if((source[i]&0x3f)<4) + { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>11)&0x1f],temp); + emit_flds(temp); + } + if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>11)&0x1f],temp); + emit_fldl(temp); + } + if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { + if(opcode2[i]==0x10) { + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],temp); + if((source[i]&0x3f)==0) emit_fadds(temp); + if((source[i]&0x3f)==1) emit_fsubs(temp); + if((source[i]&0x3f)==2) emit_fmuls(temp); + if((source[i]&0x3f)==3) emit_fdivs(temp); + } + else if(opcode2[i]==0x11) { + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],temp); + if((source[i]&0x3f)==0) emit_faddl(temp); + if((source[i]&0x3f)==1) emit_fsubl(temp); + if((source[i]&0x3f)==2) emit_fmull(temp); + if((source[i]&0x3f)==3) emit_fdivl(temp); + } + } + else { + if((source[i]&0x3f)==0) emit_fadd(0); + if((source[i]&0x3f)==1) emit_fsub(0); + if((source[i]&0x3f)==2) emit_fmul(0); + if((source[i]&0x3f)==3) emit_fdiv(0); + } + if(opcode2[i]==0x10) { + if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_simple[(source[i]>>6)&0x1f],temp); + } + emit_fstps(temp); + } + if(opcode2[i]==0x11) { + if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { + emit_readword((int)®_cop1_double[(source[i]>>6)&0x1f],temp); + } + emit_fstpl(temp); + } + return; + } + + if(opcode2[i]==0x10) { // Single precision + emit_pusha(); + emit_pushmem((int)®_cop1_simple[(source[i]>> 6)&0x1f]); + if((source[i]&0x3f)<4) + emit_pushmem((int)®_cop1_simple[(source[i]>>16)&0x1f]); + emit_pushmem((int)®_cop1_simple[(source[i]>>11)&0x1f]); + switch(source[i]&0x3f) + { + case 0x00: emit_call((int)add_s);break; + case 0x01: emit_call((int)sub_s);break; + case 0x02: emit_call((int)mul_s);break; + case 0x03: emit_call((int)div_s);break; + case 0x04: emit_call((int)sqrt_s);break; + case 0x05: emit_call((int)abs_s);break; + case 0x06: emit_call((int)mov_s);break; + case 0x07: emit_call((int)neg_s);break; + } + emit_addimm(ESP,(source[i]&0x3f)<4?12:8,ESP); + emit_popa(); + } + if(opcode2[i]==0x11) { // Double precision + emit_pusha(); + emit_pushmem((int)®_cop1_double[(source[i]>> 6)&0x1f]); + if((source[i]&0x3f)<4) + emit_pushmem((int)®_cop1_double[(source[i]>>16)&0x1f]); + emit_pushmem((int)®_cop1_double[(source[i]>>11)&0x1f]); + switch(source[i]&0x3f) + { + case 0x00: emit_call((int)add_d);break; + case 0x01: emit_call((int)sub_d);break; + case 0x02: emit_call((int)mul_d);break; + case 0x03: emit_call((int)div_d);break; + case 0x04: emit_call((int)sqrt_d);break; + case 0x05: emit_call((int)abs_d);break; + case 0x06: emit_call((int)mov_d);break; + case 0x07: emit_call((int)neg_d);break; + } + emit_addimm(ESP,(source[i]&0x3f)<4?12:8,ESP); + emit_popa(); + } +} + +static void multdiv_assemble_x86(int i,struct regstat *i_regs) +{ + // case 0x18: MULT + // case 0x19: MULTU + // case 0x1A: DIV + // case 0x1B: DIVU + // case 0x1C: DMULT + // case 0x1D: DMULTU + // case 0x1E: DDIV + // case 0x1F: DDIVU + if(rs1[i]&&rs2[i]) + { + if((opcode2[i]&4)==0) // 32-bit + { + if(opcode2[i]==0x18) // MULT + { + char m1=get_reg(i_regs->regmap,rs1[i]); + char m2=get_reg(i_regs->regmap,rs2[i]); + assert(m1>=0); + assert(m2>=0); + emit_mov(m1,EAX); + emit_imul(m2); + } + if(opcode2[i]==0x19) // MULTU + { + char m1=get_reg(i_regs->regmap,rs1[i]); + char m2=get_reg(i_regs->regmap,rs2[i]); + assert(m1>=0); + assert(m2>=0); + emit_mov(m1,EAX); + emit_mul(m2); + } + if(opcode2[i]==0x1A) // DIV + { + char d1=get_reg(i_regs->regmap,rs1[i]); + char d2=get_reg(i_regs->regmap,rs2[i]); + assert(d1>=0); + assert(d2>=0); + emit_mov(d1,EAX); + emit_cdq(); + emit_test(d2,d2); + emit_jeq((int)out+8); + emit_idiv(d2); + } + if(opcode2[i]==0x1B) // DIVU + { + char d1=get_reg(i_regs->regmap,rs1[i]); + char d2=get_reg(i_regs->regmap,rs2[i]); + assert(d1>=0); + assert(d2>=0); + emit_mov(d1,EAX); + emit_zeroreg(EDX); + emit_test(d2,d2); + emit_jeq((int)out+8); + emit_div(d2); + } + } + else // 64-bit + { + if(opcode2[i]==0x1C) // DMULT + { + char m1h=get_reg(i_regs->regmap,rs1[i]|64); + char m1l=get_reg(i_regs->regmap,rs1[i]); + char m2h=get_reg(i_regs->regmap,rs2[i]|64); + char m2l=get_reg(i_regs->regmap,rs2[i]); + assert(m1h>=0); + assert(m2h>=0); + assert(m1l>=0); + assert(m2l>=0); + emit_pushreg(m2h); + emit_pushreg(m2l); + emit_pushreg(m1h); + emit_pushreg(m1l); + emit_call((int)&mult64); + emit_popreg(m1l); + emit_popreg(m1h); + emit_popreg(m2l); + emit_popreg(m2h); + char hih=get_reg(i_regs->regmap,HIREG|64); + char hil=get_reg(i_regs->regmap,HIREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); + if(hil>=0) emit_loadreg(HIREG,hil); + char loh=get_reg(i_regs->regmap,LOREG|64); + char lol=get_reg(i_regs->regmap,LOREG); + if(loh>=0) emit_loadreg(LOREG|64,loh); + if(lol>=0) emit_loadreg(LOREG,lol); + } + if(opcode2[i]==0x1D) // DMULTU + { + char m1h=get_reg(i_regs->regmap,rs1[i]|64); + char m1l=get_reg(i_regs->regmap,rs1[i]); + char m2h=get_reg(i_regs->regmap,rs2[i]|64); + char m2l=get_reg(i_regs->regmap,rs2[i]); + char temp=get_reg(i_regs->regmap,-1); + assert(m1h>=0); + assert(m2h>=0); + assert(m1l>=0); + assert(m2l>=0); + assert(temp>=0); + emit_mov(m1l,EAX); + emit_mul(m2l); + emit_storereg(LOREG,EAX); + emit_mov(EDX,temp); + emit_mov(m1h,EAX); + emit_mul(m2l); + emit_add(EAX,temp,temp); + emit_adcimm(0,EDX); + emit_storereg(HIREG,EDX); + emit_mov(m2h,EAX); + emit_mul(m1l); + emit_add(EAX,temp,temp); + emit_adcimm(0,EDX); + emit_storereg(LOREG|64,temp); + emit_mov(EDX,temp); + emit_mov(m2h,EAX); + emit_mul(m1h); + emit_add(EAX,temp,EAX); + emit_loadreg(HIREG,temp); + emit_adcimm(0,EDX); + emit_add(EAX,temp,EAX); + emit_adcimm(0,EDX); + // DEBUG + /* + emit_pushreg(m2h); + emit_pushreg(m2l); + emit_pushreg(m1h); + emit_pushreg(m1l); + emit_call((int)&multu64); + emit_popreg(m1l); + emit_popreg(m1h); + emit_popreg(m2l); + emit_popreg(m2h); + char hih=get_reg(i_regs->regmap,HIREG|64); + char hil=get_reg(i_regs->regmap,HIREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); // DEBUG + if(hil>=0) emit_loadreg(HIREG,hil); // DEBUG + */ + // Shouldn't be necessary + //char loh=get_reg(i_regs->regmap,LOREG|64); + //char lol=get_reg(i_regs->regmap,LOREG); + //if(loh>=0) emit_loadreg(LOREG|64,loh); + //if(lol>=0) emit_loadreg(LOREG,lol); + } + if(opcode2[i]==0x1E) // DDIV + { + char d1h=get_reg(i_regs->regmap,rs1[i]|64); + char d1l=get_reg(i_regs->regmap,rs1[i]); + char d2h=get_reg(i_regs->regmap,rs2[i]|64); + char d2l=get_reg(i_regs->regmap,rs2[i]); + assert(d1h>=0); + assert(d2h>=0); + assert(d1l>=0); + assert(d2l>=0); + //emit_pushreg(d2h); + //emit_pushreg(d2l); + //emit_pushreg(d1h); + //emit_pushreg(d1l); + emit_addimm(ESP,-16,ESP); + emit_writeword_indexed(d2h,12,ESP); + emit_writeword_indexed(d2l,8,ESP); + emit_writeword_indexed(d1h,4,ESP); + emit_writeword_indexed(d1l,0,ESP); + emit_call((int)&div64); + //emit_popreg(d1l); + //emit_popreg(d1h); + //emit_popreg(d2l); + //emit_popreg(d2h); + emit_readword_indexed(0,ESP,d1l); + emit_readword_indexed(4,ESP,d1h); + emit_readword_indexed(8,ESP,d2l); + emit_readword_indexed(12,ESP,d2h); + emit_addimm(ESP,16,ESP); + char hih=get_reg(i_regs->regmap,HIREG|64); + char hil=get_reg(i_regs->regmap,HIREG); + char loh=get_reg(i_regs->regmap,LOREG|64); + char lol=get_reg(i_regs->regmap,LOREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); + if(hil>=0) emit_loadreg(HIREG,hil); + if(loh>=0) emit_loadreg(LOREG|64,loh); + if(lol>=0) emit_loadreg(LOREG,lol); + } + if(opcode2[i]==0x1F) // DDIVU + { + char d1h=get_reg(i_regs->regmap,rs1[i]|64); + char d1l=get_reg(i_regs->regmap,rs1[i]); + char d2h=get_reg(i_regs->regmap,rs2[i]|64); + char d2l=get_reg(i_regs->regmap,rs2[i]); + assert(d1h>=0); + assert(d2h>=0); + assert(d1l>=0); + assert(d2l>=0); + //emit_pushreg(d2h); + //emit_pushreg(d2l); + //emit_pushreg(d1h); + //emit_pushreg(d1l); + emit_addimm(ESP,-16,ESP); + emit_writeword_indexed(d2h,12,ESP); + emit_writeword_indexed(d2l,8,ESP); + emit_writeword_indexed(d1h,4,ESP); + emit_writeword_indexed(d1l,0,ESP); + emit_call((int)&divu64); + //emit_popreg(d1l); + //emit_popreg(d1h); + //emit_popreg(d2l); + //emit_popreg(d2h); + emit_readword_indexed(0,ESP,d1l); + emit_readword_indexed(4,ESP,d1h); + emit_readword_indexed(8,ESP,d2l); + emit_readword_indexed(12,ESP,d2h); + emit_addimm(ESP,16,ESP); + char hih=get_reg(i_regs->regmap,HIREG|64); + char hil=get_reg(i_regs->regmap,HIREG); + char loh=get_reg(i_regs->regmap,LOREG|64); + char lol=get_reg(i_regs->regmap,LOREG); + if(hih>=0) emit_loadreg(HIREG|64,hih); + if(hil>=0) emit_loadreg(HIREG,hil); + if(loh>=0) emit_loadreg(LOREG|64,loh); + if(lol>=0) emit_loadreg(LOREG,lol); + } + } + } + else + { + // Multiply by zero is zero. + // MIPS does not have a divide by zero exception. + // The result is undefined, we return zero. + char hr=get_reg(i_regs->regmap,HIREG); + char lr=get_reg(i_regs->regmap,LOREG); + if(hr>=0) emit_zeroreg(hr); + if(lr>=0) emit_zeroreg(lr); + } +} +#define multdiv_assemble multdiv_assemble_x86 + +static void do_preload_rhash(int r) { + emit_movimm(0xf8,r); +} + +static void do_preload_rhtbl(int r) { + // Don't need this for x86 +} + +static void do_rhash(int rs,int rh) { + emit_and(rs,rh,rh); +} + +static void do_miniht_load(int ht,int rh) { + // Don't need this for x86. The load and compare can be combined into + // a single instruction (below) +} + +static void do_miniht_jump(int rs,int rh,int ht) { + emit_cmpmem_indexed((int)mini_ht,rh,rs); + emit_jne(jump_vaddr_reg[rs]); + emit_jmpmem_indexed((int)mini_ht+4,rh); +} + +static void do_miniht_insert(int return_address,int rt,int temp) { + emit_movimm(return_address,rt); // PC into link register + //emit_writeword_imm(return_address,(int)&mini_ht[(return_address&0xFF)>>8][0]); + emit_writeword(rt,(int)&mini_ht[(return_address&0xFF)>>3][0]); + add_to_linker((int)out,return_address,1); + emit_writeword_imm(0,(int)&mini_ht[(return_address&0xFF)>>3][1]); +} + +// We don't need this for x86 +static void literal_pool(int n) {} +static void literal_pool_jumpover(int n) {} + +// CPU-architecture-specific initialization, not needed for x86 +static void arch_init() {} diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.h b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.h new file mode 100644 index 000000000..5c261d854 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/assem_x86.h @@ -0,0 +1,32 @@ +#ifndef M64P_R4300_ASSEM_X86_H +#define M64P_R4300_ASSEM_X86_H + +#define HOST_REGS 8 +#define HOST_CCREG 6 +#define HOST_BTREG 5 +#define EXCLUDE_REG 4 + +//#define IMM_PREFETCH 1 +#define HOST_IMM_ADDR32 1 +#define INVERTED_CARRY 1 +#define DESTRUCTIVE_WRITEBACK 1 +#define DESTRUCTIVE_SHIFT 1 + +#define USE_MINI_HT 1 + +#ifdef __cplusplus +extern "C" { +#endif +extern void *base_addr; // Code generator target address +#ifdef __cplusplus +} +#endif + +#define TARGET_SIZE_2 25 // 2^25 = 32 megabytes +#define JUMP_TABLE_SIZE 0 // Not needed for 32-bit x86 + +/* x86 calling convention: + caller-save: %eax %ecx %edx + callee-save: %ebp %ebx %esi %edi */ + +#endif /* M64P_R4300_ASSEM_X86_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_arm.S b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_arm.S new file mode 100644 index 000000000..05dc8effd --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_arm.S @@ -0,0 +1,1227 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - linkage_arm.s * + * Copyright (C) 2009-2011 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + .cpu arm9tdmi +#ifndef __ARM_NEON__ +#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP)) + .fpu vfp +#else + .fpu softvfp +#endif +#else + .fpu neon +#endif + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 +#ifndef __ARM_NEON__ + .eabi_attribute 23, 3 +#endif + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 +#ifndef __ARM_NEON__ +#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP)) + .eabi_attribute 28, 1 +#endif +#endif + .eabi_attribute 30, 6 + .eabi_attribute 18, 4 + .file "linkage_arm.S" + .global extra_memory + .hidden extra_memory + .global dynarec_local + .hidden dynarec_local + .global reg + .hidden reg + .global hi + .hidden hi + .global lo + .hidden lo + .global reg_cop1_simple + .hidden reg_cop1_simple + .global reg_cop1_double + .hidden reg_cop1_double + .global g_cp0_regs + .hidden g_cp0_regs + .global FCR0 + .hidden FCR0 + .global FCR31 + .hidden FCR31 + .global rounding_modes + .hidden rounding_modes + .global next_interupt + .hidden next_interupt + .global cycle_count + .hidden cycle_count + .global last_count + .hidden last_count + .global pending_exception + .hidden pending_exception + .global pcaddr + .hidden pcaddr + .global stop + .hidden stop + .global invc_ptr + .hidden invc_ptr + .global address + .hidden address + .global readmem_dword + .hidden readmem_dword + .global cpu_dword + .hidden cpu_dword + .global cpu_word + .hidden cpu_word + .global cpu_hword + .hidden cpu_hword + .global cpu_byte + .hidden cpu_byte + .global branch_target + .hidden branch_target + .global PC + .hidden PC + .global fake_pc + .hidden fake_pc + .global mini_ht + .hidden mini_ht + .global restore_candidate + .hidden restore_candidate + .global ram_offset + .hidden ram_offset + .global memory_map + .hidden memory_map + .bss + .align 12 + .type extra_memory, %object + .size extra_memory, 33554432 +extra_memory: + .space 33554432+64+16+16+8+8+8+8+256+8+8+128+128+128+16+8+132+4+256+512+4194304 +dynarec_local = extra_memory + 33554432 + .type dynarec_local, %object + .size dynarec_local, 64 +next_interupt = dynarec_local + 64 + .type next_interupt, %object + .size next_interupt, 4 +cycle_count = next_interupt + 4 + .type cycle_count, %object + .size cycle_count, 4 +last_count = cycle_count + 4 + .type last_count, %object + .size last_count, 4 +pending_exception = last_count + 4 + .type pending_exception, %object + .size pending_exception, 4 +pcaddr = pending_exception + 4 + .type pcaddr, %object + .size pcaddr, 4 +stop = pcaddr + 4 + .type stop, %object + .size stop, 4 +invc_ptr = stop + 4 + .type invc_ptr, %object + .size invc_ptr, 4 +address = invc_ptr + 4 + .type address, %object + .size address, 4 +readmem_dword = address + 4 + .type readmem_dword, %object + .size readmem_dword, 8 +cpu_dword = readmem_dword + 8 + .type cpu_dword, %object + .size cpu_dword, 8 +cpu_word = cpu_dword + 8 + .type cpu_word, %object + .size cpu_word, 4 +cpu_hword = cpu_word + 4 + .type cpu_hword, %object + .size cpu_hword, 2 +cpu_byte = cpu_hword + 2 + .type cpu_byte, %object + .size cpu_byte, 1 /* 1 byte free */ +FCR0 = cpu_hword + 4 + .type FCR0, %object + .size FCR0, 4 +FCR31 = FCR0 + 4 + .type FCR31, %object + .size FCR31, 4 +reg = FCR31 + 4 + .type reg, %object + .size reg, 256 +hi = reg + 256 + .type hi, %object + .size hi, 8 +lo = hi + 8 + .type lo, %object + .size lo, 8 +g_cp0_regs = lo + 8 + .type g_cp0_regs, %object + .size g_cp0_regs, 128 +reg_cop1_simple = g_cp0_regs + 128 + .type reg_cop1_simple, %object + .size reg_cop1_simple, 128 +reg_cop1_double = reg_cop1_simple + 128 + .type reg_cop1_double, %object + .size reg_cop1_double, 128 +rounding_modes = reg_cop1_double + 128 + .type rounding_modes, %object + .size rounding_modes, 16 +branch_target = rounding_modes + 16 + .type branch_target, %object + .size branch_target, 4 +PC = branch_target + 4 + .type PC, %object + .size PC, 4 +fake_pc = PC + 4 + .type fake_pc, %object + .size fake_pc, 132 +ram_offset = fake_pc + 132 + .type ram_offset, %object + .size ram_offset, 4 +mini_ht = ram_offset + 4 + .type mini_ht, %object + .size mini_ht, 256 +restore_candidate = mini_ht + 256 + .type restore_candidate, %object + .size restore_candidate, 512 +memory_map = restore_candidate + 512 + .type memory_map, %object + .size memory_map, 4194304 + + .text + .align 2 + .global dyna_linker + .hidden dyna_linker + .type dyna_linker, %function +dyna_linker: + /* r0 = virtual target address */ + /* r1 = instruction to patch */ + ldr r4, .tlbptr + lsr r5, r0, #12 + mov r12, r0 + cmp r0, #0xC0000000 + mov r6, #4096 + ldrge r12, [r4, r5, lsl #2] + mov r2, #0x80000 + ldr r3, .jiptr + tst r12, r12 + sub r6, r6, #1 + moveq r12, r0 + ldr r7, [r1] + eor r2, r2, r12, lsr #12 + and r6, r6, r12, lsr #12 + cmp r2, #2048 + add r12, r7, #2 + orrcs r2, r6, #2048 + ldr r5, [r3, r2, lsl #2] + lsl r12, r12, #8 + /* jump_in lookup */ +.A1: + movs r4, r5 + beq .A3 + ldr r3, [r5] + ldr r5, [r4, #12] + teq r3, r0 + bne .A1 + ldr r3, [r4, #4] + ldr r4, [r4, #8] + tst r3, r3 + bne .A1 +.A2: + mov r5, r1 + add r1, r1, r12, asr #6 + teq r1, r4 + moveq pc, r4 /* Stale i-cache */ + bl add_link + sub r2, r4, r5 + and r1, r7, #0xff000000 + lsl r2, r2, #6 + sub r1, r1, #2 + add r1, r1, r2, lsr #8 + str r1, [r5] + mov pc, r4 +.A3: + /* hash_table lookup */ + cmp r2, #2048 + ldr r3, .jdptr + eor r4, r0, r0, lsl #16 + lslcc r2, r0, #9 + ldr r6, .htptr + lsr r4, r4, #12 + lsrcc r2, r2, #21 + bic r4, r4, #15 + ldr r5, [r3, r2, lsl #2] + ldr r7, [r6, r4]! + teq r7, r0 + ldreq pc, [r6, #4] + ldr r7, [r6, #8] + teq r7, r0 + ldreq pc, [r6, #12] + /* jump_dirty lookup */ +.A6: + movs r4, r5 + beq .A8 + ldr r3, [r5] + ldr r5, [r4, #12] + teq r3, r0 + bne .A6 +.A7: + ldr r1, [r4, #8] + /* hash_table insert */ + ldr r2, [r6] + ldr r3, [r6, #4] + str r0, [r6] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + mov pc, r1 +.A8: + mov r4, r0 + mov r5, r1 + bl new_recompile_block + tst r0, r0 + mov r0, r4 + mov r1, r5 + beq dyna_linker + /* pagefault */ + mov r1, r0 + mov r2, #8 + .size dyna_linker, .-dyna_linker + .type exec_pagefault, %function +exec_pagefault: + /* r0 = instruction pointer */ + /* r1 = fault address */ + /* r2 = cause */ + ldr r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + mvn r6, #0xF000000F + ldr r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */ + bic r6, r6, #0x0F800000 + str r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */ + orr r3, r3, #2 + str r1, [fp, #g_cp0_regs+32-dynarec_local] /* BadVAddr */ + bic r4, r4, r6 + str r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + and r5, r6, r1, lsr #9 + str r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */ + and r1, r1, r6, lsl #9 + str r1, [fp, #g_cp0_regs+40-dynarec_local] /* EntryHi */ + orr r4, r4, r5 + str r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */ + mov r0, #0x80000000 + bl get_addr_ht + mov pc, r0 + .size exec_pagefault, .-exec_pagefault +/* Special dynamic linker for the case where a page fault + may occur in a branch delay slot */ + .global dyna_linker_ds + .hidden dyna_linker_ds + .type dyna_linker_ds, %function +dyna_linker_ds: + /* r0 = virtual target address */ + /* r1 = instruction to patch */ + ldr r4, .tlbptr + lsr r5, r0, #12 + mov r12, r0 + cmp r0, #0xC0000000 + mov r6, #4096 + ldrge r12, [r4, r5, lsl #2] + mov r2, #0x80000 + ldr r3, .jiptr + tst r12, r12 + sub r6, r6, #1 + moveq r12, r0 + ldr r7, [r1] + eor r2, r2, r12, lsr #12 + and r6, r6, r12, lsr #12 + cmp r2, #2048 + add r12, r7, #2 + orrcs r2, r6, #2048 + ldr r5, [r3, r2, lsl #2] + lsl r12, r12, #8 + /* jump_in lookup */ +.B1: + movs r4, r5 + beq .B3 + ldr r3, [r5] + ldr r5, [r4, #12] + teq r3, r0 + bne .B1 + ldr r3, [r4, #4] + ldr r4, [r4, #8] + tst r3, r3 + bne .B1 +.B2: + mov r5, r1 + add r1, r1, r12, asr #6 + teq r1, r4 + moveq pc, r4 /* Stale i-cache */ + bl add_link + sub r2, r4, r5 + and r1, r7, #0xff000000 + lsl r2, r2, #6 + sub r1, r1, #2 + add r1, r1, r2, lsr #8 + str r1, [r5] + mov pc, r4 +.B3: + /* hash_table lookup */ + cmp r2, #2048 + ldr r3, .jdptr + eor r4, r0, r0, lsl #16 + lslcc r2, r0, #9 + ldr r6, .htptr + lsr r4, r4, #12 + lsrcc r2, r2, #21 + bic r4, r4, #15 + ldr r5, [r3, r2, lsl #2] + ldr r7, [r6, r4]! + teq r7, r0 + ldreq pc, [r6, #4] + ldr r7, [r6, #8] + teq r7, r0 + ldreq pc, [r6, #12] + /* jump_dirty lookup */ +.B6: + movs r4, r5 + beq .B8 + ldr r3, [r5] + ldr r5, [r4, #12] + teq r3, r0 + bne .B6 +.B7: + ldr r1, [r4, #8] + /* hash_table insert */ + ldr r2, [r6] + ldr r3, [r6, #4] + str r0, [r6] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + mov pc, r1 +.B8: + mov r4, r0 + bic r0, r0, #7 + mov r5, r1 + orr r0, r0, #1 + bl new_recompile_block + tst r0, r0 + mov r0, r4 + mov r1, r5 + beq dyna_linker_ds + /* pagefault */ + bic r1, r0, #7 + mov r2, #0x80000008 /* High bit set indicates pagefault in delay slot */ + sub r0, r1, #4 + b exec_pagefault + .size dyna_linker_ds, .-dyna_linker_ds +.jiptr: + .word jump_in +.jdptr: + .word jump_dirty +.tlbptr: + .word tlb_LUT_r +.htptr: + .word hash_table + .align 2 + .global jump_vaddr_r0 + .hidden jump_vaddr_r0 + .type jump_vaddr_r0, %function +jump_vaddr_r0: + eor r2, r0, r0, lsl #16 + b jump_vaddr + .size jump_vaddr_r0, .-jump_vaddr_r0 + .global jump_vaddr_r1 + .hidden jump_vaddr_r1 + .type jump_vaddr_r1, %function +jump_vaddr_r1: + eor r2, r1, r1, lsl #16 + mov r0, r1 + b jump_vaddr + .size jump_vaddr_r1, .-jump_vaddr_r1 + .global jump_vaddr_r2 + .hidden jump_vaddr_r2 + .type jump_vaddr_r2, %function +jump_vaddr_r2: + mov r0, r2 + eor r2, r2, r2, lsl #16 + b jump_vaddr + .size jump_vaddr_r2, .-jump_vaddr_r2 + .global jump_vaddr_r3 + .hidden jump_vaddr_r3 + .type jump_vaddr_r3, %function +jump_vaddr_r3: + eor r2, r3, r3, lsl #16 + mov r0, r3 + b jump_vaddr + .size jump_vaddr_r3, .-jump_vaddr_r3 + .global jump_vaddr_r4 + .hidden jump_vaddr_r4 + .type jump_vaddr_r4, %function +jump_vaddr_r4: + eor r2, r4, r4, lsl #16 + mov r0, r4 + b jump_vaddr + .size jump_vaddr_r4, .-jump_vaddr_r4 + .global jump_vaddr_r5 + .hidden jump_vaddr_r5 + .type jump_vaddr_r5, %function +jump_vaddr_r5: + eor r2, r5, r5, lsl #16 + mov r0, r5 + b jump_vaddr + .size jump_vaddr_r5, .-jump_vaddr_r5 + .global jump_vaddr_r6 + .hidden jump_vaddr_r6 + .type jump_vaddr_r6, %function +jump_vaddr_r6: + eor r2, r6, r6, lsl #16 + mov r0, r6 + b jump_vaddr + .size jump_vaddr_r6, .-jump_vaddr_r6 + .global jump_vaddr_r8 + .hidden jump_vaddr_r8 + .type jump_vaddr_r8, %function +jump_vaddr_r8: + eor r2, r8, r8, lsl #16 + mov r0, r8 + b jump_vaddr + .size jump_vaddr_r8, .-jump_vaddr_r8 + .global jump_vaddr_r9 + .hidden jump_vaddr_r9 + .type jump_vaddr_r9, %function +jump_vaddr_r9: + eor r2, r9, r9, lsl #16 + mov r0, r9 + b jump_vaddr + .size jump_vaddr_r9, .-jump_vaddr_r9 + .global jump_vaddr_r10 + .hidden jump_vaddr_r10 + .type jump_vaddr_r10, %function +jump_vaddr_r10: + eor r2, r10, r10, lsl #16 + mov r0, r10 + b jump_vaddr + .size jump_vaddr_r10, .-jump_vaddr_r10 + .global jump_vaddr_r12 + .hidden jump_vaddr_r12 + .type jump_vaddr_r12, %function +jump_vaddr_r12: + eor r2, r12, r12, lsl #16 + mov r0, r12 + b jump_vaddr + .size jump_vaddr_r12, .-jump_vaddr_r12 + .global jump_vaddr_r7 + .hidden jump_vaddr_r7 + .type jump_vaddr_r7, %function +jump_vaddr_r7: + eor r2, r7, r7, lsl #16 + add r0, r7, #0 + .size jump_vaddr_r7, .-jump_vaddr_r7 + .global jump_vaddr + .hidden jump_vaddr + .type jump_vaddr, %function +jump_vaddr: + ldr r1, .htptr + mvn r3, #15 + and r2, r3, r2, lsr #12 + ldr r2, [r1, r2]! + teq r2, r0 + ldreq pc, [r1, #4] + ldr r2, [r1, #8] + teq r2, r0 + ldreq pc, [r1, #12] + str r10, [fp, #cycle_count-dynarec_local] + bl get_addr + ldr r10, [fp, #cycle_count-dynarec_local] + mov pc, r0 + .size jump_vaddr, .-jump_vaddr + .align 2 + .global verify_code_ds + .hidden verify_code_ds + .type verify_code_ds, %function +verify_code_ds: + str r8, [fp, #branch_target-dynarec_local] + .size verify_code_ds, .-verify_code_ds + .global verify_code_vm + .hidden verify_code_vm + .type verify_code_vm, %function +verify_code_vm: + /* r0 = instruction pointer (virtual address) */ + /* r1 = source (virtual address) */ + /* r2 = target */ + /* r3 = length */ + cmp r1, #0xC0000000 + blt verify_code + add r12, fp, #memory_map-dynarec_local + lsr r4, r1, #12 + add r5, r1, r3 + sub r5, #1 + ldr r6, [r12, r4, lsl #2] + lsr r5, r5, #12 + movs r7, r6 + bmi .D5 + add r1, r1, r6, lsl #2 + lsl r6, r6, #2 +.D1: + add r4, r4, #1 + teq r6, r7, lsl #2 + bne .D5 + ldr r7, [r12, r4, lsl #2] + cmp r4, r5 + bls .D1 + .size verify_code_vm, .-verify_code_vm + .global verify_code + .hidden verify_code + .type verify_code, %function +verify_code: + /* r1 = source */ + /* r2 = target */ + /* r3 = length */ + tst r3, #4 + mov r4, #0 + add r3, r1, r3 + mov r5, #0 + ldrne r4, [r1], #4 + mov r12, #0 + ldrne r5, [r2], #4 + teq r1, r3 + beq .D3 +.D2: + ldr r7, [r1], #4 + eor r9, r4, r5 + ldr r8, [r2], #4 + orrs r9, r9, r12 + bne .D4 + ldr r4, [r1], #4 + eor r12, r7, r8 + ldr r5, [r2], #4 + cmp r1, r3 + bcc .D2 + teq r7, r8 +.D3: + teqeq r4, r5 +.D4: + ldr r8, [fp, #branch_target-dynarec_local] + moveq pc, lr +.D5: + bl get_addr + mov pc, r0 + .size verify_code, .-verify_code + .align 2 + .global cc_interrupt + .hidden cc_interrupt + .type cc_interrupt, %function +cc_interrupt: + ldr r0, [fp, #last_count-dynarec_local] + mov r1, #0 + mov r2, #0x1fc + add r10, r0, r10 + str r1, [fp, #pending_exception-dynarec_local] + and r2, r2, r10, lsr #17 + add r3, fp, #restore_candidate-dynarec_local + str r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + ldr r4, [r2, r3] + mov r10, lr + tst r4, r4 + bne .E4 +.E1: + bl gen_interupt + mov lr, r10 + ldr r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + ldr r0, [fp, #next_interupt-dynarec_local] + ldr r1, [fp, #pending_exception-dynarec_local] + ldr r2, [fp, #stop-dynarec_local] + str r0, [fp, #last_count-dynarec_local] + sub r10, r10, r0 + tst r2, r2 + bne .E3 + tst r1, r1 + moveq pc, lr +.E2: + ldr r0, [fp, #pcaddr-dynarec_local] + bl get_addr_ht + mov pc, r0 +.E3: + add r12, fp, #28 + ldmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc} +.E4: + /* Move 'dirty' blocks to the 'clean' list */ + lsl r5, r2, #3 + str r1, [r2, r3] +.E5: + lsrs r4, r4, #1 + mov r0, r5 + add r5, r5, #1 + blcs clean_blocks + tst r5, #31 + bne .E5 + b .E1 + + .size cc_interrupt, .-cc_interrupt + .align 2 + .global do_interrupt + .hidden do_interrupt + .type do_interrupt, %function +do_interrupt: + ldr r0, [fp, #pcaddr-dynarec_local] + bl get_addr_ht + ldr r1, [fp, #next_interupt-dynarec_local] + ldr r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + str r1, [fp, #last_count-dynarec_local] + sub r10, r10, r1 + add r10, r10, #2 + mov pc, r0 + .size do_interrupt, .-do_interrupt + .align 2 + .global fp_exception + .hidden fp_exception + .type fp_exception, %function +fp_exception: + mov r2, #0x10000000 +.E7: + ldr r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + mov r3, #0x80000000 + str r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */ + orr r1, #2 + add r2, r2, #0x2c + str r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + str r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */ + add r0, r3, #0x180 + bl get_addr_ht + mov pc, r0 + .size fp_exception, .-fp_exception + .align 2 + .global fp_exception_ds + .hidden fp_exception_ds + .type fp_exception_ds, %function +fp_exception_ds: + mov r2, #0x90000000 /* Set high bit if delay slot */ + b .E7 + .size fp_exception_ds, .-fp_exception_ds + .align 2 + .global jump_syscall + .hidden jump_syscall + .type jump_syscall, %function +jump_syscall: + ldr r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + mov r3, #0x80000000 + str r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */ + orr r1, #2 + mov r2, #0x20 + str r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + str r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */ + add r0, r3, #0x180 + bl get_addr_ht + mov pc, r0 + .size jump_syscall, .-jump_syscall + .align 2 + .global indirect_jump_indexed + .hidden indirect_jump_indexed + .type indirect_jump_indexed, %function +indirect_jump_indexed: + ldr r0, [r0, r1, lsl #2] + .size indirect_jump_indexed, .-indirect_jump_indexed + .align 2 + .global indirect_jump + .hidden indirect_jump + .type indirect_jump, %function +indirect_jump: + ldr r12, [fp, #last_count-dynarec_local] + add r2, r2, r12 + str r2, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + mov pc, r0 + .size indirect_jump, .-indirect_jump + .align 2 + .global jump_eret + .hidden jump_eret + .type jump_eret, %function +jump_eret: + ldr r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + ldr r0, [fp, #last_count-dynarec_local] + bic r1, r1, #2 + add r10, r0, r10 + str r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + str r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + bl check_interupt + ldr r1, [fp, #next_interupt-dynarec_local] + ldr r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */ + str r1, [fp, #last_count-dynarec_local] + subs r10, r10, r1 + bpl .E11 +.E8: + add r6, fp, #reg+256-dynarec_local + mov r5, #248 + mov r1, #0 +.E9: + ldr r2, [r6, #-8]! + ldr r3, [r6, #4] + eor r3, r3, r2, asr #31 + subs r3, r3, #1 + adc r1, r1, r1 + subs r5, r5, #8 + bne .E9 + ldr r2, [fp, #hi-dynarec_local] + ldr r3, [fp, #hi+4-dynarec_local] + eors r3, r3, r2, asr #31 + ldr r2, [fp, #lo-dynarec_local] + ldreq r3, [fp, #lo+4-dynarec_local] + eoreq r3, r3, r2, asr #31 + subs r3, r3, #1 + adc r1, r1, r1 + bl get_addr_32 + mov pc, r0 +.E11: + str r0, [fp, #pcaddr-dynarec_local] + bl cc_interrupt + ldr r0, [fp, #pcaddr-dynarec_local] + b .E8 + .size jump_eret, .-jump_eret + .align 2 + .global new_dyna_start + .hidden new_dyna_start + .type new_dyna_start, %function +new_dyna_start: + ldr r12, .dlptr + ldr r1, .tgtptr + mov r0, #0xa4000000 + stmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + sub fp, r12, #28 + ldr r4, [r1] + add r0, r0, #0x40 + bl new_recompile_block + ldr r0, [fp, #next_interupt-dynarec_local] + ldr r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + str r0, [fp, #last_count-dynarec_local] + sub r10, r10, r0 + mov pc, r4 +.dlptr: + .word dynarec_local+28 +.tgtptr: + .word out + .size new_dyna_start, .-new_dyna_start + .align 2 + .global invalidate_addr_r0 + .hidden invalidate_addr_r0 + .type invalidate_addr_r0, %function +invalidate_addr_r0: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r0, #12 + b invalidate_addr_call + .size invalidate_addr_r0, .-invalidate_addr_r0 + .align 2 + .global invalidate_addr_r1 + .hidden invalidate_addr_r1 + .type invalidate_addr_r1, %function +invalidate_addr_r1: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r1, #12 + b invalidate_addr_call + .size invalidate_addr_r1, .-invalidate_addr_r1 + .align 2 + .global invalidate_addr_r2 + .hidden invalidate_addr_r2 + .type invalidate_addr_r2, %function +invalidate_addr_r2: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r2, #12 + b invalidate_addr_call + .size invalidate_addr_r2, .-invalidate_addr_r2 + .align 2 + .global invalidate_addr_r3 + .hidden invalidate_addr_r3 + .type invalidate_addr_r3, %function +invalidate_addr_r3: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r3, #12 + b invalidate_addr_call + .size invalidate_addr_r3, .-invalidate_addr_r3 + .align 2 + .global invalidate_addr_r4 + .hidden invalidate_addr_r4 + .type invalidate_addr_r4, %function +invalidate_addr_r4: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r4, #12 + b invalidate_addr_call + .size invalidate_addr_r4, .-invalidate_addr_r4 + .align 2 + .global invalidate_addr_r5 + .hidden invalidate_addr_r5 + .type invalidate_addr_r5, %function +invalidate_addr_r5: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r5, #12 + b invalidate_addr_call + .size invalidate_addr_r5, .-invalidate_addr_r5 + .align 2 + .global invalidate_addr_r6 + .hidden invalidate_addr_r6 + .type invalidate_addr_r6, %function +invalidate_addr_r6: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r6, #12 + b invalidate_addr_call + .size invalidate_addr_r6, .-invalidate_addr_r6 + .align 2 + .global invalidate_addr_r7 + .hidden invalidate_addr_r7 + .type invalidate_addr_r7, %function +invalidate_addr_r7: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r7, #12 + b invalidate_addr_call + .size invalidate_addr_r7, .-invalidate_addr_r7 + .align 2 + .global invalidate_addr_r8 + .hidden invalidate_addr_r8 + .type invalidate_addr_r8, %function +invalidate_addr_r8: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r8, #12 + b invalidate_addr_call + .size invalidate_addr_r8, .-invalidate_addr_r8 + .align 2 + .global invalidate_addr_r9 + .hidden invalidate_addr_r9 + .type invalidate_addr_r9, %function +invalidate_addr_r9: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r9, #12 + b invalidate_addr_call + .size invalidate_addr_r9, .-invalidate_addr_r9 + .align 2 + .global invalidate_addr_r10 + .hidden invalidate_addr_r10 + .type invalidate_addr_r10, %function +invalidate_addr_r10: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r10, #12 + b invalidate_addr_call + .size invalidate_addr_r10, .-invalidate_addr_r10 + .align 2 + .global invalidate_addr_r12 + .hidden invalidate_addr_r12 + .type invalidate_addr_r12, %function +invalidate_addr_r12: + stmia fp, {r0, r1, r2, r3, r12, lr} + lsr r0, r12, #12 + .size invalidate_addr_r12, .-invalidate_addr_r12 + .align 2 + .type invalidate_addr_call, %function +invalidate_addr_call: + bl invalidate_block + ldmia fp, {r0, r1, r2, r3, r12, pc} + .size invalidate_addr_call, .-invalidate_addr_call + .align 2 + .global write_rdram_new + .hidden write_rdram_new + .type write_rdram_new, %function +write_rdram_new: + ldr r3, [fp, #ram_offset-dynarec_local] + ldr r2, [fp, #address-dynarec_local] + ldr r0, [fp, #cpu_word-dynarec_local] + str r0, [r2, r3, lsl #2] + b .E12 + .size write_rdram_new, .-write_rdram_new + .align 2 + .global write_rdramb_new + .hidden write_rdramb_new + .type write_rdramb_new, %function +write_rdramb_new: + ldr r3, [fp, #ram_offset-dynarec_local] + ldr r2, [fp, #address-dynarec_local] + ldrb r0, [fp, #cpu_byte-dynarec_local] + eor r2, r2, #3 + strb r0, [r2, r3, lsl #2] + b .E12 + .size write_rdramb_new, .-write_rdramb_new + .align 2 + .global write_rdramh_new + .hidden write_rdramh_new + .type write_rdramh_new, %function +write_rdramh_new: + ldr r3, [fp, #ram_offset-dynarec_local] + ldr r2, [fp, #address-dynarec_local] + ldrh r0, [fp, #cpu_hword-dynarec_local] + eor r2, r2, #2 + lsl r3, r3, #2 + strh r0, [r2, r3] + b .E12 + .size write_rdramh_new, .-write_rdramh_new + .align 2 + .global write_rdramd_new + .hidden write_rdramd_new + .type write_rdramd_new, %function +write_rdramd_new: + ldr r3, [fp, #ram_offset-dynarec_local] + ldr r2, [fp, #address-dynarec_local] +/* ldrd r0, [fp, #cpu_dword-dynarec_local]*/ + ldr r0, [fp, #cpu_dword-dynarec_local] + ldr r1, [fp, #cpu_dword+4-dynarec_local] + add r3, r2, r3, lsl #2 + str r0, [r3, #4] + str r1, [r3] + b .E12 + .size write_rdramd_new, .-write_rdramd_new + .align 2 + .type do_invalidate, %function +do_invalidate: + ldr r2, [fp, #address-dynarec_local] +.E12: + ldr r1, [fp, #invc_ptr-dynarec_local] + lsr r0, r2, #12 + ldrb r2, [r1, r0] + tst r2, r2 + beq invalidate_block + mov pc, lr + .size do_invalidate, .-do_invalidate + .align 2 + .global read_nomem_new + .hidden read_nomem_new + .type read_nomem_new, %function +read_nomem_new: + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + lsr r0, r2, #12 + ldr r12, [r12, r0, lsl #2] + mov r1, #8 + tst r12, r12 + bmi tlb_exception + ldr r0, [r2, r12, lsl #2] + str r0, [fp, #readmem_dword-dynarec_local] + mov pc, lr + .size read_nomem_new, .-read_nomem_new + .align 2 + .global read_nomemb_new + .hidden read_nomemb_new + .type read_nomemb_new, %function +read_nomemb_new: + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + lsr r0, r2, #12 + ldr r12, [r12, r0, lsl #2] + mov r1, #8 + tst r12, r12 + bmi tlb_exception + eor r2, r2, #3 + ldrb r0, [r2, r12, lsl #2] + str r0, [fp, #readmem_dword-dynarec_local] + mov pc, lr + .size read_nomemb_new, .-read_nomemb_new + .align 2 + .global read_nomemh_new + .hidden read_nomemh_new + .type read_nomemh_new, %function +read_nomemh_new: + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + lsr r0, r2, #12 + ldr r12, [r12, r0, lsl #2] + mov r1, #8 + tst r12, r12 + bmi tlb_exception + lsl r12, r12, #2 + eor r2, r2, #2 + ldrh r0, [r2, r12] + str r0, [fp, #readmem_dword-dynarec_local] + mov pc, lr + .size read_nomemh_new, .-read_nomemh_new + .align 2 + .global read_nomemd_new + .hidden read_nomemd_new + .type read_nomemd_new, %function +read_nomemd_new: + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + lsr r0, r2, #12 + ldr r12, [r12, r0, lsl #2] + mov r1, #8 + tst r12, r12 + bmi tlb_exception + lsl r12, r12, #2 +/* ldrd r0, [r2, r12]*/ + add r3, r2, #4 + ldr r0, [r2, r12] + ldr r1, [r3, r12] + str r0, [fp, #readmem_dword+4-dynarec_local] + str r1, [fp, #readmem_dword-dynarec_local] + mov pc, lr + .size read_nomemd_new, .-read_nomemd_new + .align 2 + .global write_nomem_new + .hidden write_nomem_new + .type write_nomem_new, %function +write_nomem_new: + str r3, [fp, #24] + str lr, [fp, #28] + bl do_invalidate + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + ldr lr, [fp, #28] + lsr r0, r2, #12 + ldr r3, [fp, #24] + ldr r12, [r12, r0, lsl #2] + mov r1, #0xc + tst r12, #0x40000000 + bne tlb_exception + ldr r0, [fp, #cpu_word-dynarec_local] + str r0, [r2, r12, lsl #2] + mov pc, lr + .size write_nomem_new, .-write_nomem_new + .align 2 + .global write_nomemb_new + .hidden write_nomemb_new + .type write_nomemb_new, %function +write_nomemb_new: + str r3, [fp, #24] + str lr, [fp, #28] + bl do_invalidate + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + ldr lr, [fp, #28] + lsr r0, r2, #12 + ldr r3, [fp, #24] + ldr r12, [r12, r0, lsl #2] + mov r1, #0xc + tst r12, #0x40000000 + bne tlb_exception + eor r2, r2, #3 + ldrb r0, [fp, #cpu_byte-dynarec_local] + strb r0, [r2, r12, lsl #2] + mov pc, lr + .size write_nomemb_new, .-write_nomemb_new + .align 2 + .global write_nomemh_new + .hidden write_nomemh_new + .type write_nomemh_new, %function +write_nomemh_new: + str r3, [fp, #24] + str lr, [fp, #28] + bl do_invalidate + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + ldr lr, [fp, #28] + lsr r0, r2, #12 + ldr r3, [fp, #24] + ldr r12, [r12, r0, lsl #2] + mov r1, #0xc + lsls r12, #2 + bcs tlb_exception + eor r2, r2, #2 + ldrh r0, [fp, #cpu_hword-dynarec_local] + strh r0, [r2, r12] + mov pc, lr + .size write_nomemh_new, .-write_nomemh_new + .align 2 + .global write_nomemd_new + .hidden write_nomemd_new + .type write_nomemd_new, %function +write_nomemd_new: + str r3, [fp, #24] + str lr, [fp, #28] + bl do_invalidate + ldr r2, [fp, #address-dynarec_local] + add r12, fp, #memory_map-dynarec_local + ldr lr, [fp, #28] + lsr r0, r2, #12 + ldr r3, [fp, #24] + ldr r12, [r12, r0, lsl #2] + mov r1, #0xc + lsls r12, #2 + bcs tlb_exception + add r3, r2, #4 + ldr r0, [fp, #cpu_dword+4-dynarec_local] + ldr r1, [fp, #cpu_dword-dynarec_local] +/* strd r0, [r2, r12]*/ + str r0, [r2, r12] + str r1, [r3, r12] + mov pc, lr + .size write_nomemd_new, .-write_nomemd_new + .align 2 + .type tlb_exception, %function +tlb_exception: + /* r1 = cause */ + /* r2 = address */ + /* r3 = instr addr/flags */ + ldr r4, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + add r5, fp, #memory_map-dynarec_local + lsr r6, r3, #12 + orr r1, r1, r3, lsl #31 + orr r4, r4, #2 + ldr r7, [r5, r6, lsl #2] + bic r8, r3, #3 + str r4, [fp, #g_cp0_regs+48-dynarec_local] /* Status */ + mov r6, #0x6000000 + str r1, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */ + orr r6, r6, #0x22 + ldr r0, [r8, r7, lsl #2] + add r4, r8, r1, asr #29 + add r5, fp, #reg-dynarec_local + str r4, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */ + mov r7, #0xf8 + ldr r8, [fp, #g_cp0_regs+16-dynarec_local] /* Context */ + lsl r1, r0, #16 + lsr r4, r0, #26 + and r7, r7, r0, lsr #18 + mvn r9, #0xF000000F + sub r2, r2, r1, asr #16 + bic r9, r9, #0x0F800000 + rors r6, r6, r4 + mov r0, #0x80000000 + ldrcs r2, [r5, r7] + bic r8, r8, r9 + tst r3, #2 + str r2, [r5, r7] + add r4, r2, r1, asr #16 + add r6, fp, #reg+4-dynarec_local + asr r3, r2, #31 + str r4, [fp, #g_cp0_regs+32-dynarec_local] /* BadVAddr */ + add r0, r0, #0x180 + and r4, r9, r4, lsr #9 + strne r3, [r6, r7] + orr r8, r8, r4 + str r8, [fp, #g_cp0_regs+16-dynarec_local] /* Context */ + bl get_addr_ht + ldr r1, [fp, #next_interupt-dynarec_local] + ldr r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */ + str r1, [fp, #last_count-dynarec_local] + sub r10, r10, r1 + mov pc, r0 + .size tlb_exception, .-tlb_exception + .align 2 + .global breakpoint + .hidden breakpoint + .type breakpoint, %function +breakpoint: + /* Set breakpoint here for debugging */ + mov pc, lr + .size breakpoint, .-breakpoint +/* The following bug-fix implements __clear_cache (missing in Android) */ + .align 2 + .global __clear_cache_bugfix + .hidden __clear_cache_bugfix + .type __clear_cache_bugfix, %function +__clear_cache_bugfix: + push {r7, lr} + mov r2, #0 + mov r7, #0x2 + add r7, r7, #0xf0000 + svc 0x00000000 + pop {r7, pc} + .size __clear_cache_bugfix, .-__clear_cache_bugfix +/* End of bug-fix */ + .section .note.GNU-stack,"",%progbits diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.S b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.S new file mode 100644 index 000000000..8d5dde885 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.S @@ -0,0 +1,929 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - linkage_x86.s * + * Copyright (C) 2009-2011 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + .file "linkage_x86.s" + .bss + .align 4 + + .section .rodata + .text +.globl dyna_linker + .hidden dyna_linker + .type dyna_linker, @function +dyna_linker: + /* eax = virtual target address */ + /* ebx = instruction to patch */ + mov %eax, %edi + mov %eax, %ecx + shr $12, %edi + cmp $0xC0000000, %eax + cmovge tlb_LUT_r(,%edi,4), %ecx + test %ecx, %ecx + cmovz %eax, %ecx + xor $0x80000000, %ecx + mov $2047, %edx + shr $12, %ecx + and %ecx, %edx + or $2048, %edx + cmp %edx, %ecx + cmova %edx, %ecx + /* jump_in lookup */ + mov jump_in(,%ecx,4), %edx +.A1: + test %edx, %edx + je .A3 + mov (%edx), %edi + xor %eax, %edi + or 4(%edx), %edi + je .A2 + movl 12(%edx), %edx + jmp .A1 +.A2: + mov (%ebx), %edi + mov %esi, %ebp + lea 4(%ebx,%edi,1), %esi + mov %eax, %edi + pusha + call add_link + popa + mov 8(%edx), %edi + mov %ebp, %esi + lea -4(%edi), %edx + subl %ebx, %edx + movl %edx, (%ebx) + jmp *%edi +.A3: + /* hash_table lookup */ + mov %eax, %edi + mov %eax, %edx + shr $16, %edi + shr $12, %edx + xor %eax, %edi + and $2047, %edx + movzwl %di, %edi + shl $4, %edi + cmp $2048, %ecx + cmovc %edx, %ecx + cmp hash_table(%edi), %eax + jne .A5 +.A4: + mov hash_table+4(%edi), %edx + jmp *%edx +.A5: + cmp hash_table+8(%edi), %eax + lea 8(%edi), %edi + je .A4 + /* jump_dirty lookup */ + mov jump_dirty(,%ecx,4), %edx +.A6: + testl %edx, %edx + je .A8 + mov (%edx), %ecx + xor %eax, %ecx + or 4(%edx), %ecx + je .A7 + movl 12(%edx), %edx + jmp .A6 +.A7: + mov 8(%edx), %edx + /* hash_table insert */ + mov hash_table-8(%edi), %ebx + mov hash_table-4(%edi), %ecx + mov %eax, hash_table-8(%edi) + mov %edx, hash_table-4(%edi) + mov %ebx, hash_table(%edi) + mov %ecx, hash_table+4(%edi) + jmp *%edx +.A8: + mov %eax, %edi + pusha + call new_recompile_block + test %eax, %eax + popa + je dyna_linker + /* pagefault */ + mov %eax, %ebx + mov $0x08, %ecx + .size dyna_linker, .-dyna_linker + + .type exec_pagefault, @function +exec_pagefault: + /* eax = instruction pointer */ + /* ebx = fault address */ + /* ecx = cause */ + mov g_cp0_regs+48, %edx + add $-12, %esp + mov g_cp0_regs+16, %edi + or $2, %edx + mov %ebx, g_cp0_regs+32 /* BadVAddr */ + and $0xFF80000F, %edi + mov %edx, g_cp0_regs+48 /* Status */ + mov %ecx, g_cp0_regs+52 /* Cause */ + mov %eax, g_cp0_regs+56 /* EPC */ + mov %ebx, %ecx + shr $9, %ebx + and $0xFFFFE000, %ecx + and $0x007FFFF0, %ebx + mov %ecx, g_cp0_regs+40 /* EntryHI */ + or %ebx, %edi + mov %edi, g_cp0_regs+16 /* Context */ + push $0x80000000 + call get_addr_ht + add $16, %esp + jmp *%eax + .size exec_pagefault, .-exec_pagefault + +/* Special dynamic linker for the case where a page fault + may occur in a branch delay slot */ +.globl dyna_linker_ds + .hidden dyna_linker_ds + .type dyna_linker_ds, @function +dyna_linker_ds: + mov %eax, %edi + mov %eax, %ecx + shr $12, %edi + cmp $0xC0000000, %eax + cmovge tlb_LUT_r(,%edi,4), %ecx + test %ecx, %ecx + cmovz %eax, %ecx + xor $0x80000000, %ecx + mov $2047, %edx + shr $12, %ecx + and %ecx, %edx + or $2048, %edx + cmp %edx, %ecx + cmova %edx, %ecx + /* jump_in lookup */ + mov jump_in(,%ecx,4), %edx +.B1: + test %edx, %edx + je .B3 + mov (%edx), %edi + xor %eax, %edi + or 4(%edx), %edi + je .B2 + movl 12(%edx), %edx + jmp .B1 +.B2: + mov (%ebx), %edi + mov %esi, %ecx + lea 4(%ebx,%edi,1), %esi + mov %eax, %edi + pusha + call add_link + popa + mov 8(%edx), %edi + mov %ecx, %esi + lea -4(%edi), %edx + subl %ebx, %edx + movl %edx, (%ebx) + jmp *%edi +.B3: + /* hash_table lookup */ + mov %eax, %edi + mov %eax, %edx + shr $16, %edi + shr $12, %edx + xor %eax, %edi + and $2047, %edx + movzwl %di, %edi + shl $4, %edi + cmp $2048, %ecx + cmovc %edx, %ecx + cmp hash_table(%edi), %eax + jne .B5 +.B4: + mov hash_table+4(%edi), %edx + jmp *%edx +.B5: + cmp hash_table+8(%edi), %eax + lea 8(%edi), %edi + je .B4 + /* jump_dirty lookup */ + mov jump_dirty(,%ecx,4), %edx +.B6: + testl %edx, %edx + je .B8 + mov (%edx), %ecx + xor %eax, %ecx + or 4(%edx), %ecx + je .B7 + movl 12(%edx), %edx + jmp .B6 +.B7: + mov 8(%edx), %edx + /* hash_table insert */ + mov hash_table-8(%edi), %ebx + mov hash_table-4(%edi), %ecx + mov %eax, hash_table-8(%edi) + mov %edx, hash_table-4(%edi) + mov %ebx, hash_table(%edi) + mov %ecx, hash_table+4(%edi) + jmp *%edx +.B8: + mov %eax, %edi + and $0xFFFFFFF8, %edi + inc %edi + pusha + call new_recompile_block + test %eax, %eax + popa + je dyna_linker_ds + /* pagefault */ + and $0xFFFFFFF8, %eax + mov $0x80000008, %ecx /* High bit set indicates pagefault in delay slot */ + mov %eax, %ebx + sub $4, %eax + jmp exec_pagefault + .size dyna_linker_ds, .-dyna_linker_ds + +.globl jump_vaddr_eax + .hidden jump_vaddr_eax + .type jump_vaddr_eax, @function +jump_vaddr_eax: + mov %eax, %edi + jmp jump_vaddr_edi + .size jump_vaddr_eax, .-jump_vaddr_eax +.globl jump_vaddr_ecx + .hidden jump_vaddr_ecx + .type jump_vaddr_ecx, @function +jump_vaddr_ecx: + mov %ecx, %edi + jmp jump_vaddr_edi + .size jump_vaddr_ecx, .-jump_vaddr_ecx +.globl jump_vaddr_edx + .hidden jump_vaddr_edx + .type jump_vaddr_edx, @function +jump_vaddr_edx: + mov %edx, %edi + jmp jump_vaddr_edi + .size jump_vaddr_edx, .-jump_vaddr_edx +.globl jump_vaddr_ebx + .hidden jump_vaddr_ebx + .type jump_vaddr_ebx, @function +jump_vaddr_ebx: + mov %ebx, %edi + jmp jump_vaddr_edi + .size jump_vaddr_ebx, .-jump_vaddr_ebx +.globl jump_vaddr_ebp + .hidden jump_vaddr_ebp + .type jump_vaddr_ebp, @function +jump_vaddr_ebp: + mov %ebp, %edi + .size jump_vaddr_ebp, .-jump_vaddr_ebp +.globl jump_vaddr_edi + .hidden jump_vaddr_edi + .type jump_vaddr_edi, @function +jump_vaddr_edi: + mov %edi, %eax + .size jump_vaddr_edi, .-jump_vaddr_edi + + .type jump_vaddr, @function +jump_vaddr: + /* Check hash table */ + shr $16, %eax + xor %edi, %eax + movzwl %ax, %eax + shl $4, %eax + cmp hash_table(%eax), %edi + jne .C2 +.C1: + mov hash_table+4(%eax), %edi + jmp *%edi +.C2: + cmp hash_table+8(%eax), %edi + lea 8(%eax), %eax + je .C1 + /* No hit on hash table, call compiler */ + add $-12, %esp + push %edi + mov %esi, cycle_count /* CCREG */ + call get_addr + mov cycle_count, %esi + add $16, %esp + jmp *%eax + .size jump_vaddr, .-jump_vaddr + +.globl verify_code_ds + .hidden verify_code_ds + .type verify_code_ds, @function +verify_code_ds: + mov %ebp, branch_target + .size verify_code_ds, .-verify_code_ds + +.globl verify_code_vm + .hidden verify_code_vm + .type verify_code_vm, @function +verify_code_vm: + /* eax = source (virtual address) */ + /* ebx = target */ + /* ecx = length */ + cmp $0xC0000000, %eax + jl verify_code + mov %eax, %edx + lea -1(%eax,%ecx,1), %ebp + shr $12, %edx + shr $12, %ebp + mov memory_map(,%edx,4), %edi + test %edi, %edi + js .D5 + lea (%eax,%edi,4), %eax +.D1: + xor memory_map(,%edx,4), %edi + shl $2, %edi + jne .D5 + mov memory_map(,%edx,4), %edi + inc %edx + cmp %ebp, %edx + jbe .D1 + .size verify_code_vm, .-verify_code_vm + +.globl verify_code + .hidden verify_code + .type verify_code, @function +verify_code: + /* eax = source */ + /* ebx = target */ + /* ecx = length */ + mov -4(%eax,%ecx,1), %edi + xor -4(%ebx,%ecx,1), %edi + jne .D5 + mov %ecx, %edx + add $-4, %ecx + je .D3 + test $4, %edx + cmove %edx, %ecx + mov %esi, cycle_count +.D2: + mov -4(%eax,%ecx,1), %edx + mov -4(%ebx,%ecx,1), %ebp + mov -8(%eax,%ecx,1), %esi + xor %edx, %ebp + mov -8(%ebx,%ecx,1), %edi + jne .D4 + xor %esi, %edi + jne .D4 + add $-8, %ecx + jne .D2 + mov cycle_count, %esi + mov branch_target, %ebp +.D3: + ret +.D4: + mov cycle_count, %esi +.D5: + mov branch_target, %ebp + push %esi /* for stack alignment, unused */ + push 8(%esp) + call get_addr + add $16, %esp /* pop stack */ + jmp *%eax + .size verify_code, .-verify_code + +.globl cc_interrupt + .hidden cc_interrupt + .type cc_interrupt, @function +cc_interrupt: + add last_count, %esi + add $-28, %esp /* Align stack */ + mov %esi, g_cp0_regs+36 /* Count */ + shr $19, %esi + movl $0, pending_exception + and $0x7f, %esi + cmpl $0, restore_candidate(,%esi,4) + jne .E4 +.E1: + call gen_interupt + mov g_cp0_regs+36, %esi + mov next_interupt, %eax + mov pending_exception, %ebx + mov stop, %ecx + add $28, %esp + mov %eax, last_count + sub %eax, %esi + test %ecx, %ecx + jne .E3 + test %ebx, %ebx + jne .E2 + ret +.E2: + add $-8, %esp + mov pcaddr, %edi + mov %esi, cycle_count /* CCREG */ + push %edi + call get_addr_ht + mov cycle_count, %esi + add $16, %esp + jmp *%eax +.E3: + add $16, %esp /* pop stack */ + pop %edi /* restore edi */ + pop %esi /* restore esi */ + pop %ebx /* restore ebx */ + pop %ebp /* restore ebp */ + ret /* exit dynarec */ +.E4: + /* Move 'dirty' blocks to the 'clean' list */ + mov restore_candidate(,%esi,4), %ebx + mov %esi, %ebp + movl $0, restore_candidate(,%esi,4) + shl $5, %ebp +.E5: + shr $1, %ebx + jnc .E6 + mov %ebp, (%esp) + call clean_blocks +.E6: + inc %ebp + test $31, %ebp + jne .E5 + jmp .E1 + .size cc_interrupt, .-cc_interrupt + +.globl do_interrupt + .hidden do_interrupt + .type do_interrupt, @function +do_interrupt: + mov pcaddr, %edi + add $-12, %esp + push %edi + call get_addr_ht + add $16, %esp + mov g_cp0_regs+36, %esi + mov next_interupt, %ebx + mov %ebx, last_count + sub %ebx, %esi + add $2, %esi + jmp *%eax + .size do_interrupt, .-do_interrupt + +.globl fp_exception + .hidden fp_exception + .type fp_exception, @function +fp_exception: + mov $0x1000002c, %edx +.E7: + mov g_cp0_regs+48, %ebx + add $-12, %esp + or $2, %ebx + mov %ebx, g_cp0_regs+48 /* Status */ + mov %edx, g_cp0_regs+52 /* Cause */ + mov %eax, g_cp0_regs+56 /* EPC */ + push $0x80000180 + call get_addr_ht + add $16, %esp + jmp *%eax + .size fp_exception, .-fp_exception + +.globl fp_exception_ds + .hidden fp_exception_ds + .type fp_exception_ds, @function +fp_exception_ds: + mov $0x9000002c, %edx /* Set high bit if delay slot */ + jmp .E7 + .size fp_exception_ds, .-fp_exception_ds + +.globl jump_syscall + .hidden jump_syscall + .type jump_syscall, @function +jump_syscall: + mov $0x20, %edx + mov g_cp0_regs+48, %ebx + add $-12, %esp + or $2, %ebx + mov %ebx, g_cp0_regs+48 /* Status */ + mov %edx, g_cp0_regs+52 /* Cause */ + mov %eax, g_cp0_regs+56 /* EPC */ + push $0x80000180 + call get_addr_ht + add $16, %esp + jmp *%eax + .size jump_syscall, .-jump_syscall + +.globl jump_eret + .hidden jump_eret + .type jump_eret, @function +jump_eret: + mov g_cp0_regs+48, %ebx /* Status */ + add last_count, %esi + and $0xFFFFFFFD, %ebx + mov %esi, g_cp0_regs+36 /* Count */ + mov %ebx, g_cp0_regs+48 /* Status */ + call check_interupt + mov next_interupt, %eax + mov g_cp0_regs+36, %esi + mov %eax, last_count + sub %eax, %esi + mov g_cp0_regs+56, %eax /* EPC */ + jns .E11 +.E8: + mov $248, %ebx + xor %edi, %edi +.E9: + mov reg(%ebx), %ecx + mov reg+4(%ebx), %edx + sar $31, %ecx + xor %ecx, %edx + neg %edx + adc %edi, %edi + sub $8, %ebx + jne .E9 + mov hi(%ebx), %ecx + mov hi+4(%ebx), %edx + sar $31, %ecx + xor %ecx, %edx + jne .E10 + mov lo(%ebx), %ecx + mov lo+4(%ebx), %edx + sar $31, %ecx + xor %ecx, %edx +.E10: + neg %edx + adc %edi, %edi + add $-8, %esp + push %edi + push %eax + mov %esi, cycle_count + call get_addr_32 + mov cycle_count, %esi + add $16, %esp + jmp *%eax +.E11: + mov %eax, pcaddr + call cc_interrupt + mov pcaddr, %eax + jmp .E8 + .size jump_eret, .-jump_eret + +.globl new_dyna_start + .hidden new_dyna_start + .type new_dyna_start, @function +new_dyna_start: + push %ebp + push %ebx + push %esi + push %edi + add $-8, %esp /* align stack */ + push $0xa4000040 + call new_recompile_block + movl next_interupt, %edi + movl g_cp0_regs+36, %esi + movl %edi, last_count + subl %edi, %esi + jmp *base_addr + .size new_dyna_start, .-new_dyna_start + +/* Note: Assumes %ebx, %ebp, %esi, %edi are callee-saved */ +.globl invalidate_block_eax + .hidden invalidate_block_eax + .type invalidate_block_eax, @function +invalidate_block_eax: + push %eax + push %ecx + push %edx + push %eax + jmp invalidate_block_call + .size invalidate_block_eax, .-invalidate_block_eax +.globl invalidate_block_ecx + .hidden invalidate_block_ecx + .type invalidate_block_ecx, @function +invalidate_block_ecx: + push %eax + push %ecx + push %edx + push %ecx + jmp invalidate_block_call + .size invalidate_block_ecx, .-invalidate_block_ecx +.globl invalidate_block_edx + .hidden invalidate_block_edx + .type invalidate_block_edx, @function +invalidate_block_edx: + push %eax + push %ecx + push %edx + push %edx + jmp invalidate_block_call + .size invalidate_block_edx, .-invalidate_block_edx +.globl invalidate_block_ebx + .hidden invalidate_block_ebx + .type invalidate_block_ebx, @function +invalidate_block_ebx: + push %eax + push %ecx + push %edx + push %ebx + jmp invalidate_block_call + .size invalidate_block_ebx, .-invalidate_block_ebx +.globl invalidate_block_ebp + .hidden invalidate_block_ebp + .type invalidate_block_ebp, @function +invalidate_block_ebp: + push %eax + push %ecx + push %edx + push %ebp + jmp invalidate_block_call + .size invalidate_block_ebp, .-invalidate_block_ebp +.globl invalidate_block_esi + .hidden invalidate_block_esi + .type invalidate_block_esi, @function +invalidate_block_esi: + push %eax + push %ecx + push %edx + push %esi + jmp invalidate_block_call + .size invalidate_block_esi, .-invalidate_block_esi +.globl invalidate_block_edi + .hidden invalidate_block_edi + .type invalidate_block_edi, @function +invalidate_block_edi: + push %eax + push %ecx + push %edx + push %edi + .size invalidate_block_edi, .-invalidate_block_edi + + .type invalidate_block_call, @function +invalidate_block_call: + call invalidate_block + pop %eax /* Throw away */ + pop %edx + pop %ecx + pop %eax + ret + .size invalidate_block_call, .-invalidate_block_call + +.globl write_rdram_new + .hidden write_rdram_new + .type write_rdram_new, @function +write_rdram_new: + mov address, %edi + mov cpu_word, %ecx + mov %ecx, g_rdram-0x80000000(%edi) + jmp .E12 + .size write_rdram_new, .-write_rdram_new + +.globl write_rdramb_new + .hidden write_rdramb_new + .type write_rdramb_new, @function +write_rdramb_new: + mov address, %edi + xor $3, %edi + movb cpu_byte, %cl + movb %cl, g_rdram-0x80000000(%edi) + jmp .E12 + .size write_rdramb_new, .-write_rdramb_new + +.globl write_rdramh_new + .hidden write_rdramh_new + .type write_rdramh_new, @function +write_rdramh_new: + mov address, %edi + xor $2, %edi + movw cpu_hword, %cx + movw %cx, g_rdram-0x80000000(%edi) + jmp .E12 + .size write_rdramh_new, .-write_rdramh_new + +.globl write_rdramd_new + .hidden write_rdramd_new + .type write_rdramd_new, @function +write_rdramd_new: + mov address, %edi + mov cpu_dword+4, %ecx + mov cpu_dword, %edx + mov %ecx, g_rdram-0x80000000(%edi) + mov %edx, g_rdram-0x80000000+4(%edi) + jmp .E12 + .size write_rdramd_new, .-write_rdramd_new + + .type do_invalidate, @function +do_invalidate: + mov address, %edi + mov %edi, %ebx /* Return ebx to caller */ +.E12: + shr $12, %edi + cmpb $1, invalid_code(%edi) + je .E13 + push %edi + call invalidate_block + pop %edi +.E13: + ret + .size do_invalidate, .-do_invalidate + +.globl read_nomem_new + .hidden read_nomem_new + .type read_nomem_new, @function +read_nomem_new: + mov address, %edi + mov %edi, %ebx + shr $12, %edi + mov memory_map(,%edi,4),%edi + mov $0x8, %eax + test %edi, %edi + js tlb_exception + mov (%ebx,%edi,4), %ecx + mov %ecx, readmem_dword + ret + .size read_nomem_new, .-read_nomem_new + +.globl read_nomemb_new + .hidden read_nomemb_new + .type read_nomemb_new, @function +read_nomemb_new: + mov address, %edi + mov %edi, %ebx + shr $12, %edi + mov memory_map(,%edi,4),%edi + mov $0x8, %eax + test %edi, %edi + js tlb_exception + xor $3, %ebx + movzbl (%ebx,%edi,4), %ecx + mov %ecx, readmem_dword + ret + .size read_nomemb_new, .-read_nomemb_new + +.globl read_nomemh_new + .hidden read_nomemh_new + .type read_nomemh_new, @function +read_nomemh_new: + mov address, %edi + mov %edi, %ebx + shr $12, %edi + mov memory_map(,%edi,4),%edi + mov $0x8, %eax + test %edi, %edi + js tlb_exception + xor $2, %ebx + movzwl (%ebx,%edi,4), %ecx + mov %ecx, readmem_dword + ret + .size read_nomemh_new, .-read_nomemh_new + +.globl read_nomemd_new + .hidden read_nomemd_new + .type read_nomemd_new, @function +read_nomemd_new: + mov address, %edi + mov %edi, %ebx + shr $12, %edi + mov memory_map(,%edi,4),%edi + mov $0x8, %eax + test %edi, %edi + js tlb_exception + mov 4(%ebx,%edi,4), %ecx + mov (%ebx,%edi,4), %edx + mov %ecx, readmem_dword + mov %edx, readmem_dword+4 + ret + .size read_nomemd_new, .-read_nomemd_new + +.globl write_nomem_new + .hidden write_nomem_new + .type write_nomem_new, @function +write_nomem_new: + call do_invalidate + mov memory_map(,%edi,4),%edi + mov cpu_word, %ecx + mov $0xc, %eax + shl $2, %edi + jc tlb_exception + mov %ecx, (%ebx,%edi) + ret + .size write_nomem_new, .-write_nomem_new + +.globl write_nomemb_new + .hidden write_nomemb_new + .type write_nomemb_new, @function +write_nomemb_new: + call do_invalidate + mov memory_map(,%edi,4),%edi + movb cpu_byte, %cl + mov $0xc, %eax + shl $2, %edi + jc tlb_exception + xor $3, %ebx + movb %cl, (%ebx,%edi) + ret + .size write_nomemb_new, .-write_nomemb_new + +.globl write_nomemh_new + .hidden write_nomemh_new + .type write_nomemh_new, @function +write_nomemh_new: + call do_invalidate + mov memory_map(,%edi,4),%edi + movw cpu_hword, %cx + mov $0xc, %eax + shl $2, %edi + jc tlb_exception + xor $2, %ebx + movw %cx, (%ebx,%edi) + ret + .size write_nomemh_new, .-write_nomemh_new + +.globl write_nomemd_new + .hidden write_nomemd_new + .type write_nomemd_new, @function +write_nomemd_new: + call do_invalidate + mov memory_map(,%edi,4),%edi + mov cpu_dword+4, %edx + mov cpu_dword, %ecx + mov $0xc, %eax + shl $2, %edi + jc tlb_exception + mov %edx, (%ebx,%edi) + mov %ecx, 4(%ebx,%edi) + ret + .size write_nomemd_new, .-write_nomemd_new + + .type tlb_exception, @function +tlb_exception: + /* eax = cause */ + /* ebx = address */ + /* ebp = instr addr + flags */ + mov 0x24(%esp), %ebp +/* Debug: + push %ebp + push %ebx + push %eax + call tlb_debug + pop %eax + pop %ebx + pop %ebp +/* end debug */ + mov g_cp0_regs+48, %esi + mov %ebp, %ecx + mov %ebp, %edx + mov %ebp, %edi + shl $31, %ebp + shr $12, %ecx + or %ebp, %eax + sar $29, %ebp + and $0xFFFFFFFC, %edx + mov memory_map(,%ecx,4), %ecx + or $2, %esi + mov (%edx, %ecx, 4), %ecx + add %ebp, %edx + mov %esi, g_cp0_regs+48 /* Status */ + mov %eax, g_cp0_regs+52 /* Cause */ + mov %edx, g_cp0_regs+56 /* EPC */ + add $0x24, %esp + mov $0x6000022, %edx + mov %ecx, %ebp + movswl %cx, %eax + shr $26, %ecx + shr $21, %ebp + sub %eax, %ebx + and $0x1f, %ebp + ror %cl, %edx + mov g_cp0_regs+16, %esi + cmovc reg(,%ebp,8), %ebx + and $0xFF80000F, %esi + mov %ebx, reg(,%ebp,8) + add %ebx, %eax + sar $31, %ebx + mov %eax, g_cp0_regs+32 /* BadVAddr */ + shr $9, %eax + test $2, %edi + cmove reg+4(,%ebp,8), %ebx + add $-12, %esp + and $0x007FFFF0, %eax + mov %ebx, reg+4(,%ebp,8) + push $0x80000180 + or %eax, %esi + mov %esi, g_cp0_regs+16 /* Context */ + call get_addr_ht + add $16, %esp + movl next_interupt, %edi + movl g_cp0_regs+36, %esi /* Count */ + movl %edi, last_count + subl %edi, %esi + jmp *%eax + .size tlb_exception, .-tlb_exception + +.globl breakpoint + .hidden breakpoint + .type breakpoint, @function +breakpoint: + .size breakpoint, .-breakpoint diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.asm b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.asm new file mode 100644 index 000000000..1fcb50f07 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/linkage_x86.asm @@ -0,0 +1,873 @@ +;Mupen64plus - linkage_x86.asm +;Copyright (C) 2009-2011 Ari64 +; +;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., +;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +%ifdef ELF_TYPE + %macro cglobal 1 + global %1 + %endmacro + + %macro cextern 1 + extern %1 + %endmacro +%else + %macro cglobal 1 + global _%1 + %define %1 _%1 + %endmacro + + %macro cextern 1 + extern _%1 + %define %1 _%1 + %endmacro +%endif + +cglobal dyna_linker +cglobal dyna_linker_ds +cglobal jump_vaddr_eax +cglobal jump_vaddr_ecx +cglobal jump_vaddr_edx +cglobal jump_vaddr_ebx +cglobal jump_vaddr_ebp +cglobal jump_vaddr_edi +cglobal verify_code_ds +cglobal verify_code_vm +cglobal verify_code +cglobal cc_interrupt +cglobal do_interrupt +cglobal fp_exception +cglobal fp_exception_ds +cglobal jump_syscall +cglobal jump_eret +cglobal new_dyna_start +cglobal invalidate_block_eax +cglobal invalidate_block_ecx +cglobal invalidate_block_edx +cglobal invalidate_block_ebx +cglobal invalidate_block_ebp +cglobal invalidate_block_esi +cglobal invalidate_block_edi +cglobal write_rdram_new +cglobal write_rdramb_new +cglobal write_rdramh_new +cglobal write_rdramd_new +cglobal read_nomem_new +cglobal read_nomemb_new +cglobal read_nomemh_new +cglobal read_nomemd_new +cglobal write_nomem_new +cglobal write_nomemb_new +cglobal write_nomemh_new +cglobal write_nomemd_new +cglobal breakpoint + +cextern base_addr +cextern tlb_LUT_r +cextern jump_in +cextern add_link +cextern hash_table +cextern jump_dirty +cextern new_recompile_block +cextern g_cp0_regs +cextern get_addr_ht +cextern cycle_count +cextern get_addr +cextern branch_target +cextern memory_map +cextern pending_exception +cextern restore_candidate +cextern gen_interupt +cextern next_interupt +cextern stop +cextern last_count +cextern pcaddr +cextern clean_blocks +cextern reg +cextern hi +cextern lo +cextern invalidate_block +cextern address +cextern g_rdram +cextern cpu_byte +cextern cpu_hword +cextern cpu_word +cextern cpu_dword +cextern invalid_code +cextern readmem_dword +cextern check_interupt +cextern get_addr_32 + +section .bss +align 4 + +section .rodata +section .text + +dyna_linker: + ;eax = virtual target address + ;ebx = instruction to patch + mov edi, eax + mov ecx, eax + shr edi, 12 + cmp eax, 0C0000000h + cmovge ecx, [tlb_LUT_r+edi*4] + test ecx, ecx + cmovz ecx, eax + xor ecx, 080000000h + mov edx, 2047 + shr ecx, 12 + and edx, ecx + or edx, 2048 + cmp ecx, edx + cmova ecx, edx + ;jump_in lookup + mov edx, [jump_in+ecx*4] +_A1: + test edx, edx + je _A3 + mov edi, [edx] + xor edi, eax + or edi, [4+edx] + je _A2 + mov edx, DWORD [12+edx] + jmp _A1 +_A2: + mov edi, [ebx] + mov ebp, esi + lea esi, [4+ebx+edi*1] + mov edi, eax + pusha + call add_link + popa + mov edi, [8+edx] + mov esi, ebp + lea edx, [-4+edi] + sub edx, ebx + mov DWORD [ebx], edx + jmp edi +_A3: + ;hash_table lookup + mov edi, eax + mov edx, eax + shr edi, 16 + shr edx, 12 + xor edi, eax + and edx, 2047 + movzx edi, di + shl edi, 4 + cmp ecx, 2048 + cmovc ecx, edx + cmp eax, [hash_table+edi] + jne _A5 +_A4: + mov edx, [hash_table+4+edi] + jmp edx +_A5: + cmp eax, [hash_table+8+edi] + lea edi, [8+edi] + je _A4 + ;jump_dirty lookup + mov edx, [jump_dirty+ecx*4] +_A6: + test edx, edx + je _A8 + mov ecx, [edx] + xor ecx, eax + or ecx, [4+edx] + je _A7 + mov edx, DWORD [12+edx] + jmp _A6 +_A7: + mov edx, [8+edx] + ;hash_table insert + mov ebx, [hash_table-8+edi] + mov ecx, [hash_table-4+edi] + mov [hash_table-8+edi], eax + mov [hash_table-4+edi], edx + mov [hash_table+edi], ebx + mov [hash_table+4+edi], ecx + jmp edx +_A8: + mov edi, eax + pusha + call new_recompile_block + test eax, eax + popa + je dyna_linker + ;pagefault + mov ebx, eax + mov ecx, 008h + +exec_pagefault: + ;eax = instruction pointer + ;ebx = fault address + ;ecx = cause + mov edx, [g_cp0_regs+48] + add esp, -12 + mov edi, [g_cp0_regs+16] + or edx, 2 + mov [g_cp0_regs+32], ebx ;BadVAddr + and edi, 0FF80000Fh + mov [g_cp0_regs+48], edx ;Status + mov [g_cp0_regs+52], ecx ;Cause + mov [g_cp0_regs+56], eax ;EPC + mov ecx, ebx + shr ebx, 9 + and ecx, 0FFFFE000h + and ebx, 0007FFFF0h + mov [g_cp0_regs+40], ecx ;EntryHI + or edi, ebx + mov [g_cp0_regs+16], edi ;Context + push 080000000h + call get_addr_ht + add esp, 16 + jmp eax + +;Special dynamic linker for the case where a page fault +;may occur in a branch delay slot +dyna_linker_ds: + mov edi, eax + mov ecx, eax + shr edi, 12 + cmp eax, 0C0000000h + cmovge ecx, [tlb_LUT_r+edi*4] + test ecx, ecx + cmovz ecx, eax + xor ecx, 080000000h + mov edx, 2047 + shr ecx, 12 + and edx, ecx + or edx, 2048 + cmp ecx, edx + cmova ecx, edx + ;jump_in lookup + mov edx, [jump_in+ecx*4] +_B1: + test edx, edx + je _B3 + mov edi, [edx] + xor edi, eax + or edi, [4+edx] + je _B2 + mov edx, DWORD [12+edx] + jmp _B1 +_B2: + mov edi, [ebx] + mov ecx, esi + lea esi, [4+ebx+edi*1] + mov edi, eax + pusha + call add_link + popa + mov edi, [8+edx] + mov esi, ecx + lea edx, [-4+edi] + sub edx, ebx + mov DWORD [ebx], edx + jmp edi +_B3: + ;hash_table lookup + mov edi, eax + mov edx, eax + shr edi, 16 + shr edx, 12 + xor edi, eax + and edx, 2047 + movzx edi, di + shl edi, 4 + cmp ecx, 2048 + cmovc ecx, edx + cmp eax, [hash_table+edi] + jne _B5 +_B4: + mov edx, [hash_table+4+edi] + jmp edx +_B5: + cmp eax, [hash_table+8+edi] + lea edi, [8+edi] + je _B4 + ;jump_dirty lookup + mov edx, [jump_dirty+ecx*4] +_B6: + test edx, edx + je _B8 + mov ecx, [edx] + xor ecx, eax + or ecx, [4+edx] + je _B7 + mov edx, DWORD [12+edx] + jmp _B6 +_B7: + mov edx, [8+edx] + ;hash_table insert + mov ebx, [hash_table-8+edi] + mov ecx, [hash_table-4+edi] + mov [hash_table-8+edi], eax + mov [hash_table-4+edi], edx + mov [hash_table+edi], ebx + mov [hash_table+4+edi], ecx + jmp edx +_B8: + mov edi, eax + and edi, 0FFFFFFF8h + inc edi + pusha + call new_recompile_block + test eax, eax + popa + je dyna_linker_ds + ;pagefault + and eax, 0FFFFFFF8h + mov ecx, 080000008h ;High bit set indicates pagefault in delay slot + mov ebx, eax + sub eax, 4 + jmp exec_pagefault + +jump_vaddr_eax: + mov edi, eax + jmp jump_vaddr_edi + +jump_vaddr_ecx: + mov edi, ecx + jmp jump_vaddr_edi + +jump_vaddr_edx: + mov edi, edx + jmp jump_vaddr_edi + +jump_vaddr_ebx: + mov edi, ebx + jmp jump_vaddr_edi + +jump_vaddr_ebp: + mov edi, ebp + +jump_vaddr_edi: + mov eax, edi + +jump_vaddr: + ;Check hash table + shr eax, 16 + xor eax, edi + movzx eax, ax + shl eax, 4 + cmp edi, [hash_table+eax] + jne _C2 +_C1: + mov edi, [hash_table+4+eax] + jmp edi +_C2: + cmp edi, [hash_table+8+eax] + lea eax, [8+eax] + je _C1 + ;No hit on hash table, call compiler + add esp, -12 + push edi + mov [cycle_count], esi ;CCREG + call get_addr + mov esi, [cycle_count] + add esp, 16 + jmp eax + +verify_code_ds: + mov [branch_target], ebp + +verify_code_vm: + ;eax = source (virtual address) + ;ebx = target + ;ecx = length + cmp eax, 0C0000000h + jl verify_code + mov edx, eax + lea ebp, [-1+eax+ecx*1] + shr edx, 12 + shr ebp, 12 + mov edi, [memory_map+edx*4] + test edi, edi + js _D5 + lea eax, [eax+edi*4] +_D1: + xor edi, [memory_map+edx*4] + shl edi, 2 + jne _D5 + mov edi, [memory_map+edx*4] + inc edx + cmp edx, ebp + jbe _D1 + +verify_code: + ;eax = source + ;ebx = target + ;ecx = length + mov edi, [-4+eax+ecx*1] + xor edi, [-4+ebx+ecx*1] + jne _D5 + mov edx, ecx + add ecx, -4 + je _D3 + test edx, 4 + cmove ecx, edx + mov [cycle_count], esi +_D2: + mov edx, [-4+eax+ecx*1] + mov ebp, [-4+ebx+ecx*1] + mov esi, [-8+eax+ecx*1] + xor ebp, edx + mov edi, [-8+ebx+ecx*1] + jne _D4 + xor edi, esi + jne _D4 + add ecx, -8 + jne _D2 + mov esi, [cycle_count] + mov ebp, [branch_target] +_D3: + ret +_D4: + mov esi, [cycle_count] +_D5: + mov ebp, [branch_target] + push esi ;for stack alignment, unused + push DWORD [8+esp] + call get_addr + add esp, 16 ;pop stack + jmp eax + +cc_interrupt: + add esi, [last_count] + add esp, -28 ;Align stack + mov [g_cp0_regs+36], esi ;Count + shr esi, 19 + mov DWORD [pending_exception], 0 + and esi, 07fh + cmp DWORD [restore_candidate+esi*4], 0 + jne _E4 +_E1: + call gen_interupt + mov esi, [g_cp0_regs+36] + mov eax, [next_interupt] + mov ebx, [pending_exception] + mov ecx, [stop] + add esp, 28 + mov [last_count], eax + sub esi, eax + test ecx, ecx + jne _E3 + test ebx, ebx + jne _E2 + ret +_E2: + add esp, -8 + mov edi, [pcaddr] + mov [cycle_count], esi ;CCREG + push edi + call get_addr_ht + mov esi, [cycle_count] + add esp, 16 + jmp eax +_E3: + add esp, 16 ;pop stack + pop edi ;restore edi + pop esi ;restore esi + pop ebx ;restore ebx + pop ebp ;restore ebp + ret ;exit dynarec +_E4: + ;Move 'dirty' blocks to the 'clean' list + mov ebx, [restore_candidate+esi*4] + mov ebp, esi + mov DWORD [restore_candidate+esi*4], 0 + shl ebp, 5 +_E5: + shr ebx, 1 + jnc _E6 + mov [esp], ebp + call clean_blocks +_E6: + inc ebp + test ebp, 31 + jne _E5 + jmp _E1 + +do_interrupt: + mov edi, [pcaddr] + add esp, -12 + push edi + call get_addr_ht + add esp, 16 + mov esi, [g_cp0_regs+36] + mov ebx, [next_interupt] + mov [last_count], ebx + sub esi, ebx + add esi, 2 + jmp eax + +fp_exception: + mov edx, 01000002ch +_E7: + mov ebx, [g_cp0_regs+48] + add esp, -12 + or ebx, 2 + mov [g_cp0_regs+48], ebx ;Status + mov [g_cp0_regs+52], edx ;Cause + mov [g_cp0_regs+56], eax ;EPC + push 080000180h + call get_addr_ht + add esp, 16 + jmp eax + +fp_exception_ds: + mov edx, 09000002ch ;Set high bit if delay slot + jmp _E7 + +jump_syscall: + mov edx, 020h + mov ebx, [g_cp0_regs+48] + add esp, -12 + or ebx, 2 + mov [g_cp0_regs+48], ebx ;Status + mov [g_cp0_regs+52], edx ;Cause + mov [g_cp0_regs+56], eax ;EPC + push 080000180h + call get_addr_ht + add esp, 16 + jmp eax + +jump_eret: + mov ebx, [g_cp0_regs+48] ;Status + add esi, [last_count] + and ebx, 0FFFFFFFDh + mov [g_cp0_regs+36], esi ;Count + mov [g_cp0_regs+48], ebx ;Status + call check_interupt + mov eax, [next_interupt] + mov esi, [g_cp0_regs+36] + mov [last_count], eax + sub esi, eax + mov eax, [g_cp0_regs+56] ;EPC + jns _E11 +_E8: + mov ebx, 248 + xor edi, edi +_E9: + mov ecx, [reg+ebx] + mov edx, [reg+4+ebx] + sar ecx, 31 + xor edx, ecx + neg edx + adc edi, edi + sub ebx, 8 + jne _E9 + mov ecx, [hi+ebx] + mov edx, [hi+4+ebx] + sar ecx, 31 + xor edx, ecx + jne _E10 + mov ecx, [lo+ebx] + mov edx, [lo+4+ebx] + sar ecx, 31 + xor edx, ecx +_E10: + neg edx + adc edi, edi + add esp, -8 + push edi + push eax + mov [cycle_count], esi + call get_addr_32 + mov esi, [cycle_count] + add esp, 16 + jmp eax +_E11: + mov [pcaddr], eax + call cc_interrupt + mov eax, [pcaddr] + jmp _E8 + +new_dyna_start: + push ebp + push ebx + push esi + push edi + add esp, -8 ;align stack + push 0a4000040h + call new_recompile_block + mov edi, DWORD [next_interupt] + mov esi, DWORD [g_cp0_regs+36] + mov DWORD [last_count], edi + sub esi, edi + jmp DWORD [base_addr] + +invalidate_block_eax: + push eax + push ecx + push edx + push eax + jmp invalidate_block_call + +invalidate_block_ecx: + push eax + push ecx + push edx + push ecx + jmp invalidate_block_call + +invalidate_block_edx: + push eax + push ecx + push edx + push edx + jmp invalidate_block_call + +invalidate_block_ebx: + push eax + push ecx + push edx + push ebx + jmp invalidate_block_call + +invalidate_block_ebp: + push eax + push ecx + push edx + push ebp + jmp invalidate_block_call + +invalidate_block_esi: + push eax + push ecx + push edx + push esi + jmp invalidate_block_call + +invalidate_block_edi: + push eax + push ecx + push edx + push edi + +invalidate_block_call: + call invalidate_block + pop eax ;Throw away + pop edx + pop ecx + pop eax + ret + +write_rdram_new: + mov edi, [address] + mov ecx, [cpu_word] + mov [g_rdram-0x80000000+edi], ecx + jmp _E12 + +write_rdramb_new: + mov edi, [address] + xor edi, 3 + mov cl, BYTE [cpu_byte] + mov BYTE [g_rdram-0x80000000+edi], cl + jmp _E12 + +write_rdramh_new: + mov edi, [address] + xor edi, 2 + mov cx, WORD [cpu_hword] + mov WORD [g_rdram-0x80000000+edi], cx + jmp _E12 + +write_rdramd_new: + mov edi, [address] + mov ecx, [cpu_dword+4] + mov edx, [cpu_dword+0] + mov [g_rdram-0x80000000+edi], ecx + mov [g_rdram-0x80000000+4+edi], edx + jmp _E12 + + +do_invalidate: + mov edi, [address] + mov ebx, edi ;Return ebx to caller +_E12: + shr edi, 12 + cmp BYTE [invalid_code+edi], 1 + je _E13 + push edi + call invalidate_block + pop edi +_E13: +ret + +read_nomem_new: + mov edi, [address] + mov ebx, edi + shr edi, 12 + mov edi, [memory_map+edi*4] + mov eax, 08h + test edi, edi + js tlb_exception + mov ecx, [ebx+edi*4] + mov [readmem_dword], ecx + ret + +read_nomemb_new: + mov edi, [address] + mov ebx, edi + shr edi, 12 + mov edi, [memory_map+edi*4] + mov eax, 08h + test edi, edi + js tlb_exception + xor ebx, 3 + movzx ecx, BYTE [ebx+edi*4] + mov [readmem_dword], ecx + ret + +read_nomemh_new: + mov edi, [address] + mov ebx, edi + shr edi, 12 + mov edi, [memory_map+edi*4] + mov eax, 08h + test edi, edi + js tlb_exception + xor ebx, 2 + movzx ecx, WORD [ebx+edi*4] + mov [readmem_dword], ecx + ret + +read_nomemd_new: + mov edi, [address] + mov ebx, edi + shr edi, 12 + mov edi, [memory_map+edi*4] + mov eax, 08h + test edi, edi + js tlb_exception + mov ecx, [4+ebx+edi*4] + mov edx, [ebx+edi*4] + mov [readmem_dword], ecx + mov [readmem_dword+4], edx + ret + +write_nomem_new: + call do_invalidate + mov edi, [memory_map+edi*4] + mov ecx, [cpu_word] + mov eax, 0ch + shl edi, 2 + jc tlb_exception + mov [ebx+edi], ecx + ret + +write_nomemb_new: + call do_invalidate + mov edi, [memory_map+edi*4] + mov cl, BYTE [cpu_byte] + mov eax, 0ch + shl edi, 2 + jc tlb_exception + xor ebx, 3 + mov BYTE [ebx+edi], cl + ret + +write_nomemh_new: + call do_invalidate + mov edi, [memory_map+edi*4] + mov cx, WORD [cpu_hword] + mov eax, 0ch + shl edi, 2 + jc tlb_exception + xor ebx, 2 + mov WORD [ebx+edi], cx + ret + +write_nomemd_new: + call do_invalidate + mov edi, [memory_map+edi*4] + mov edx, [cpu_dword+4] + mov ecx, [cpu_dword+0] + mov eax, 0ch + shl edi, 2 + jc tlb_exception + mov [ebx+edi], edx + mov [4+ebx+edi], ecx + ret + + +tlb_exception: + ;eax = cause + ;ebx = address + ;ebp = instr addr + flags + mov ebp, [024h+esp] +;Debug: + ;push ebp + ;push ebx + ;push eax + ;call tlb_debug + ;pop eax + ;pop ebx + ;pop ebp +;end debug + mov esi, [g_cp0_regs+48] + mov ecx, ebp + mov edx, ebp + mov edi, ebp + shl ebp, 31 + shr ecx, 12 + or eax, ebp + sar ebp, 29 + and edx, 0FFFFFFFCh + mov ecx, [memory_map+ecx*4] + or esi, 2 + mov ecx, [edx+ecx*4] + add edx, ebp + mov [g_cp0_regs+48], esi ;Status + mov [g_cp0_regs+52], eax ;Cause + mov [g_cp0_regs+56], edx ;EPC + add esp, 024h + mov edx, 06000022h + mov ebp, ecx + movsx eax, cx + shr ecx, 26 + shr ebp, 21 + sub ebx, eax + and ebp, 01fh + ror edx, cl + mov esi, [g_cp0_regs+16] + cmovc ebx, [reg+ebp*8] + and esi, 0FF80000Fh + mov [reg+ebp*8], ebx + add eax, ebx + sar ebx, 31 + mov [g_cp0_regs+32], eax ;BadVAddr + shr eax, 9 + test edi, 2 + cmove ebx, [reg+4+ebp*8] + add esp, -12 + and eax, 0007FFFF0h + mov [reg+4+ebp*8], ebx + push 080000180h + or esi, eax + mov [g_cp0_regs+16], esi ;Context + call get_addr_ht + add esp, 16 + mov edi, DWORD [next_interupt] + mov esi, DWORD [g_cp0_regs+36] ;Count + mov DWORD [last_count], edi + sub esi, edi + jmp eax + +breakpoint: \ No newline at end of file diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.c b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.c new file mode 100644 index 000000000..aac3a6711 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.c @@ -0,0 +1,11143 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - new_dynarec.c * + * Copyright (C) 2009-2011 Ari64 * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include +#include //include for uint64_t +#include + +#if defined(__APPLE__) +#include // needed for u_int, u_char, etc +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifdef __cplusplus +extern "C" { +#endif +#include "new_dynarec.h" +#include "../recomp.h" +#include "../recomph.h" //include for function prototypes +#include "../cp0.h" +#include "../cp1.h" +#include "../r4300.h" +#include "../ops.h" +#include "../tlb.h" +#include "../interupt.h" +#include "../cached_interp.h" +#include "../../memory/memory.h" +#include "../../main/main.h" +#include "../../main/rom.h" +#include "../../rsp/rsp_core.h" +#ifdef __cplusplus +} +#endif + +#if !defined(_MSC_VER) +#include +#endif + +#if NEW_DYNAREC == NEW_DYNAREC_X86 +#include "assem_x86.h" +#elif NEW_DYNAREC == NEW_DYNAREC_ARM +#include "assem_arm.h" +#else +#error Unsupported dynarec architecture +#endif + +#define MAXBLOCK 4096 +#define MAX_OUTPUT_BLOCK_SIZE 262144 +#define CLOCK_DIVIDER count_per_op + +void *base_addr; + +struct regstat +{ + signed char regmap_entry[HOST_REGS]; + signed char regmap[HOST_REGS]; + uint64_t was32; + uint64_t is32; + uint64_t wasdirty; + uint64_t dirty; + uint64_t u; + uint64_t uu; + u_int wasconst; + u_int isconst; + uint64_t constmap[HOST_REGS]; +}; + +struct ll_entry +{ + u_int vaddr; + u_int reg32; + void *addr; + struct ll_entry *next; +}; + +#ifdef __cplusplus +extern "C" { +#endif +extern u_char restore_candidate[512]; +extern int cycle_count; +extern int last_count; +extern int branch_target; +extern uint64_t readmem_dword; +extern struct ll_entry *jump_in[4096]; +extern struct ll_entry *jump_dirty[4096]; +extern ALIGN(16, u_int hash_table[65536][4]); +#ifdef __cplusplus +} +#endif + +static u_int start; +static u_int *source; +static u_int pagelimit; +static char insn[MAXBLOCK][10]; +static u_char itype[MAXBLOCK]; +static u_char opcode[MAXBLOCK]; +static u_char opcode2[MAXBLOCK]; +static u_char bt[MAXBLOCK]; +static u_char rs1[MAXBLOCK]; +static u_char rs2[MAXBLOCK]; +static u_char rt1[MAXBLOCK]; +static u_char rt2[MAXBLOCK]; +static u_char us1[MAXBLOCK]; +static u_char us2[MAXBLOCK]; +static u_char dep1[MAXBLOCK]; +static u_char dep2[MAXBLOCK]; +static u_char lt1[MAXBLOCK]; +static int imm[MAXBLOCK]; +static u_int ba[MAXBLOCK]; +static char likely[MAXBLOCK]; +static char is_ds[MAXBLOCK]; +static char ooo[MAXBLOCK]; +static uint64_t unneeded_reg[MAXBLOCK]; +static uint64_t unneeded_reg_upper[MAXBLOCK]; +static uint64_t branch_unneeded_reg[MAXBLOCK]; +static uint64_t branch_unneeded_reg_upper[MAXBLOCK]; +static uint64_t p32[MAXBLOCK]; +static uint64_t pr32[MAXBLOCK]; +static signed char regmap_pre[MAXBLOCK][HOST_REGS]; +#ifdef ASSEM_DEBUG +static signed char regmap[MAXBLOCK][HOST_REGS]; +static signed char regmap_entry[MAXBLOCK][HOST_REGS]; +#endif +static uint64_t constmap[MAXBLOCK][HOST_REGS]; +static struct regstat regs[MAXBLOCK]; +static struct regstat branch_regs[MAXBLOCK]; +static signed char minimum_free_regs[MAXBLOCK]; +static u_int needed_reg[MAXBLOCK]; +static uint64_t requires_32bit[MAXBLOCK]; +static u_int wont_dirty[MAXBLOCK]; +static u_int will_dirty[MAXBLOCK]; +static int ccadj[MAXBLOCK]; +static int slen; +static u_int instr_addr[MAXBLOCK]; +static u_int link_addr[MAXBLOCK][3]; +static int linkcount; +static u_int stubs[MAXBLOCK*3][8]; +static int stubcount; +static int literalcount; +static int is_delayslot; +static int cop1_usable; +u_char *out; +struct ll_entry *jump_in[4096]; +static struct ll_entry *jump_out[4096]; +struct ll_entry *jump_dirty[4096]; +ALIGN(16, u_int hash_table[65536][4]); +ALIGN(16, static char shadow[2097152]); +static char *copy; +static int expirep; +u_int using_tlb; +static u_int stop_after_jal; + + /* registers that may be allocated */ + /* 1-31 gpr */ +#define HIREG 32 // hi +#define LOREG 33 // lo +#define FSREG 34 // FPU status (FCSR) +#define CSREG 35 // Coprocessor status +#define CCREG 36 // Cycle count +#define INVCP 37 // Pointer to invalid_code +#define MMREG 38 // Pointer to memory_map +#define ROREG 39 // ram offset (if rdram!=0x80000000) +#define TEMPREG 40 +#define FTEMP 40 // FPU temporary register +#define PTEMP 41 // Prefetch temporary register +#define TLREG 42 // TLB mapping offset +#define RHASH 43 // Return address hash +#define RHTBL 44 // Return address hash table address +#define RTEMP 45 // JR/JALR address register +#define MAXREG 45 +#define AGEN1 46 // Address generation temporary register +#define AGEN2 47 // Address generation temporary register +#define MGEN1 48 // Maptable address generation temporary register +#define MGEN2 49 // Maptable address generation temporary register +#define BTREG 50 // Branch target temporary register + + /* instruction types */ +#define NOP 0 // No operation +#define LOAD 1 // Load +#define STORE 2 // Store +#define LOADLR 3 // Unaligned load +#define STORELR 4 // Unaligned store +#define MOV 5 // Move +#define ALU 6 // Arithmetic/logic +#define MULTDIV 7 // Multiply/divide +#define SHIFT 8 // Shift by register +#define SHIFTIMM 9// Shift by immediate +#define IMM16 10 // 16-bit immediate +#define RJUMP 11 // Unconditional jump to register +#define UJUMP 12 // Unconditional jump +#define CJUMP 13 // Conditional branch (BEQ/BNE/BGTZ/BLEZ) +#define SJUMP 14 // Conditional branch (regimm format) +#define COP0 15 // Coprocessor 0 +#define COP1 16 // Coprocessor 1 +#define C1LS 17 // Coprocessor 1 load/store +#define FJUMP 18 // Conditional branch (floating point) +#define FLOAT 19 // Floating point unit +#define FCONV 20 // Convert integer to float +#define FCOMP 21 // Floating point compare (sets FSREG) +#define SYSCALL 22// SYSCALL +#define OTHER 23 // Other +#define SPAN 24 // Branch/delay slot spans 2 pages +#define NI 25 // Not implemented + + /* stubs */ +#define CC_STUB 1 +#define FP_STUB 2 +#define LOADB_STUB 3 +#define LOADH_STUB 4 +#define LOADW_STUB 5 +#define LOADD_STUB 6 +#define LOADBU_STUB 7 +#define LOADHU_STUB 8 +#define STOREB_STUB 9 +#define STOREH_STUB 10 +#define STOREW_STUB 11 +#define STORED_STUB 12 +#define STORELR_STUB 13 +#define INVCODE_STUB 14 + + /* branch codes */ +#define TAKEN 1 +#define NOTTAKEN 2 +#define NULLDS 3 + +/* bug-fix to implement __clear_cache (missing in Android; http://code.google.com/p/android/issues/detail?id=1803) */ +void __clear_cache_bugfix(char* begin, char *end); +#ifdef ANDROID + #define __clear_cache __clear_cache_bugfix +#endif + +// asm linkage +#ifdef __cplusplus +extern "C" { +#endif +int new_recompile_block(int addr); +void *get_addr_ht(u_int vaddr); +void *get_addr(u_int vaddr); +void *get_addr_32(u_int vaddr,u_int flags); +void add_link(u_int vaddr,void *src); +void clean_blocks(u_int page); +void dyna_linker(); +void dyna_linker_ds(); +void verify_code(); +void verify_code_vm(); +void verify_code_ds(); +void cc_interrupt(); +void fp_exception(); +void fp_exception_ds(); +void jump_syscall(); +void jump_eret(); +#ifdef __cplusplus +} +#endif +static void remove_hash(int vaddr); +#if NEW_DYNAREC == NEW_DYNAREC_ARM +static void invalidate_addr(u_int addr); +#endif + +// TLB +void TLBWI_new(); +void TLBWR_new(); +#ifdef __cplusplus +extern "C" { +#endif +void read_nomem_new(void); +void read_nomemb_new(void); +void read_nomemh_new(void); +void read_nomemd_new(void); +void write_nomem_new(void); +void write_nomemb_new(void); +void write_nomemh_new(void); +void write_nomemd_new(void); +void write_rdram_new(void); +void write_rdramb_new(void); +void write_rdramh_new(void); +void write_rdramd_new(void); +extern u_int memory_map[1048576]; +#ifdef __cplusplus +} +#endif + +// Needed by assembler +static void wb_register(signed char r,signed char regmap[],uint64_t dirty,uint64_t is32); +static void wb_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty); +static void wb_needed_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr); +static void load_all_regs(signed char i_regmap[]); +static void load_needed_regs(signed char i_regmap[],signed char next_regmap[]); +static void load_regs_entry(int t); +static void load_all_consts(signed char regmap[],int is32,u_int dirty,int i); + +static void add_stub(int type,int addr,int retaddr,int a,int b,int c,int d,int e); +static void add_to_linker(int addr,int target,int ext); +static int verify_dirty(void *addr); + +//static int tracedebug=0; + +//#define DEBUG_CYCLE_COUNT 1 + +// Uncomment these two lines to generate debug output: +//#define ASSEM_DEBUG 1 +//#define INV_DEBUG 1 + +// Uncomment this line to output the number of NOTCOMPILED blocks as they occur: +//#define COUNT_NOTCOMPILEDS 1 + +#if defined (COUNT_NOTCOMPILEDS ) + int notcompiledCount = 0; +#endif + +#ifdef __cplusplus +static void nullf(...) {} +#else +static void nullf() {} +#endif + +#if defined( ASSEM_DEBUG ) + #define assem_debug(...) DebugMessage(M64MSG_VERBOSE, __VA_ARGS__) +#else + #define assem_debug nullf +#endif +#if defined( INV_DEBUG ) + #define inv_debug(...) DebugMessage(M64MSG_VERBOSE, __VA_ARGS__) +#else + #define inv_debug nullf +#endif + +#define log_message(...) DebugMessage(M64MSG_VERBOSE, __VA_ARGS__) + +static void tlb_hacks() +{ + // Goldeneye hack + if (strncmp((char *) ROM_HEADER.Name, "GOLDENEYE",9) == 0) + { + u_int addr; + int n; + switch (ROM_HEADER.Country_code&0xFF) + { + case 0x45: // U + addr=0x34b30; + break; + case 0x4A: // J + addr=0x34b70; + break; + case 0x50: // E + addr=0x329f0; + break; + default: + // Unknown country code + addr=0; + break; + } + u_int rom_addr=(u_int)g_rom; + #ifdef ROM_COPY + // Since memory_map is 32-bit, on 64-bit systems the rom needs to be + // in the lower 4G of memory to use this hack. Copy it if necessary. + if((void *)g_rom>(void *)0xffffffff) { + munmap(ROM_COPY, 67108864); + if(mmap(ROM_COPY, 12582912, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0) <= 0) {DebugMessage(M64MSG_ERROR, "mmap() failed");} + memcpy(ROM_COPY,g_rom,12582912); + rom_addr=(u_int)ROM_COPY; + } + #endif + if(addr) { + for(n=0x7F000;n<0x80000;n++) { + memory_map[n]=(((u_int)(rom_addr+addr-0x7F000000))>>2)|0x40000000; + } + } + } +} + +// Get address from virtual address +// This is called from the recompiled JR/JALR instructions +void *get_addr(u_int vaddr) +{ + u_int page=(vaddr^0x80000000)>>12; + u_int vpage=page; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + if(vpage>262143&&tlb_LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead + if(vpage>2048) vpage=2048+(vpage&2047); + struct ll_entry *head; + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr %x,page %d)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,page); + head=jump_in[page]; + while(head!=NULL) { + if(head->vaddr==vaddr&&head->reg32==0) { + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr match %x: %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,(int)head->addr); + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + ht_bin[3]=ht_bin[1]; + ht_bin[2]=ht_bin[0]; + ht_bin[1]=(int)head->addr; + ht_bin[0]=vaddr; + return head->addr; + } + head=head->next; + } + head=jump_dirty[vpage]; + while(head!=NULL) { + if(head->vaddr==vaddr&&head->reg32==0) { + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr match dirty %x: %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,(int)head->addr); + // Don't restore blocks which are about to expire from the cache + if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) + if(verify_dirty(head->addr)) { + //DebugMessage(M64MSG_VERBOSE, "restore candidate: %x (%d) d=%d",vaddr,page,invalid_code[vaddr>>12]); + invalid_code[vaddr>>12]=0; + memory_map[vaddr>>12]|=0x40000000; + if(vpage<2048) { + if(tlb_LUT_r[vaddr>>12]) { + invalid_code[tlb_LUT_r[vaddr>>12]>>12]=0; + memory_map[tlb_LUT_r[vaddr>>12]>>12]|=0x40000000; + } + restore_candidate[vpage>>3]|=1<<(vpage&7); + } + else restore_candidate[page>>3]|=1<<(page&7); + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==vaddr) { + ht_bin[1]=(int)head->addr; // Replace existing entry + } + else + { + ht_bin[3]=ht_bin[1]; + ht_bin[2]=ht_bin[0]; + ht_bin[1]=(int)head->addr; + ht_bin[0]=vaddr; + } + return head->addr; + } + } + head=head->next; + } + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr no-match %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr); + int r=new_recompile_block(vaddr); + if(r==0) return get_addr(vaddr); + // Execute in unmapped page, generate pagefault execption + g_cp0_regs[CP0_STATUS_REG]|=2; + g_cp0_regs[CP0_CAUSE_REG]=(vaddr<<31)|0x8; + g_cp0_regs[CP0_EPC_REG]=(vaddr&1)?vaddr-5:vaddr; + g_cp0_regs[CP0_BADVADDR_REG]=(vaddr&~1); + g_cp0_regs[CP0_CONTEXT_REG]=(g_cp0_regs[CP0_CONTEXT_REG]&0xFF80000F)|((g_cp0_regs[CP0_BADVADDR_REG]>>9)&0x007FFFF0); + g_cp0_regs[CP0_ENTRYHI_REG]=g_cp0_regs[CP0_BADVADDR_REG]&0xFFFFE000; + return get_addr_ht(0x80000000); +} +// Look up address in hash table first +void *get_addr_ht(u_int vaddr) +{ + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr_ht %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr); + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==vaddr) return (void *)ht_bin[1]; + if(ht_bin[2]==vaddr) return (void *)ht_bin[3]; + return get_addr(vaddr); +} + +void *get_addr_32(u_int vaddr,u_int flags) +{ + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr_32 %x,flags %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,flags); + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==vaddr) return (void *)ht_bin[1]; + if(ht_bin[2]==vaddr) return (void *)ht_bin[3]; + u_int page=(vaddr^0x80000000)>>12; + u_int vpage=page; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + if(vpage>262143&&tlb_LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead + if(vpage>2048) vpage=2048+(vpage&2047); + struct ll_entry *head; + head=jump_in[page]; + while(head!=NULL) { + if(head->vaddr==vaddr&&(head->reg32&flags)==0) { + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr_32 match %x: %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,(int)head->addr); + if(head->reg32==0) { + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==-1) { + ht_bin[1]=(int)head->addr; + ht_bin[0]=vaddr; + }else if(ht_bin[2]==-1) { + ht_bin[3]=(int)head->addr; + ht_bin[2]=vaddr; + } + //ht_bin[3]=ht_bin[1]; + //ht_bin[2]=ht_bin[0]; + //ht_bin[1]=(int)head->addr; + //ht_bin[0]=vaddr; + } + return head->addr; + } + head=head->next; + } + head=jump_dirty[vpage]; + while(head!=NULL) { + if(head->vaddr==vaddr&&(head->reg32&flags)==0) { + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr_32 match dirty %x: %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,(int)head->addr); + // Don't restore blocks which are about to expire from the cache + if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) + if(verify_dirty(head->addr)) { + //DebugMessage(M64MSG_VERBOSE, "restore candidate: %x (%d) d=%d",vaddr,page,invalid_code[vaddr>>12]); + invalid_code[vaddr>>12]=0; + memory_map[vaddr>>12]|=0x40000000; + if(vpage<2048) { + if(tlb_LUT_r[vaddr>>12]) { + invalid_code[tlb_LUT_r[vaddr>>12]>>12]=0; + memory_map[tlb_LUT_r[vaddr>>12]>>12]|=0x40000000; + } + restore_candidate[vpage>>3]|=1<<(vpage&7); + } + else restore_candidate[page>>3]|=1<<(page&7); + if(head->reg32==0) { + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==-1) { + ht_bin[1]=(int)head->addr; + ht_bin[0]=vaddr; + }else if(ht_bin[2]==-1) { + ht_bin[3]=(int)head->addr; + ht_bin[2]=vaddr; + } + //ht_bin[3]=ht_bin[1]; + //ht_bin[2]=ht_bin[0]; + //ht_bin[1]=(int)head->addr; + //ht_bin[0]=vaddr; + } + return head->addr; + } + } + head=head->next; + } + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (get_addr_32 no-match %x,flags %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,vaddr,flags); + int r=new_recompile_block(vaddr); + if(r==0) return get_addr(vaddr); + // Execute in unmapped page, generate pagefault execption + g_cp0_regs[CP0_STATUS_REG]|=2; + g_cp0_regs[CP0_CAUSE_REG]=(vaddr<<31)|0x8; + g_cp0_regs[CP0_EPC_REG]=(vaddr&1)?vaddr-5:vaddr; + g_cp0_regs[CP0_BADVADDR_REG]=(vaddr&~1); + g_cp0_regs[CP0_CONTEXT_REG]=(g_cp0_regs[CP0_CONTEXT_REG]&0xFF80000F)|((g_cp0_regs[CP0_BADVADDR_REG]>>9)&0x007FFFF0); + g_cp0_regs[CP0_ENTRYHI_REG]=g_cp0_regs[CP0_BADVADDR_REG]&0xFFFFE000; + return get_addr_ht(0x80000000); +} + +static void clear_all_regs(signed char regmap[]) +{ + int hr; + for (hr=0;hrregmap[hr]&63)==reg) { + cur->dirty|=(uint64_t)1<dirty>>hr)&1) { + reg=cur->regmap[hr]; + if(reg>=64) + if((cur->is32>>(reg&63))&1) cur->regmap[hr]=-1; + } + } +} + +static void set_const(struct regstat *cur,signed char reg,uint64_t value) +{ + int hr; + if(!reg) return; + for (hr=0;hrregmap[hr]==reg) { + cur->isconst|=1<constmap[hr]=value; + } + else if((cur->regmap[hr]^64)==reg) { + cur->isconst|=1<constmap[hr]=value>>32; + } + } +} + +static void clear_const(struct regstat *cur,signed char reg) +{ + int hr; + if(!reg) return; + for (hr=0;hrregmap[hr]&63)==reg) { + cur->isconst&=~(1<regmap[hr]&63)==reg) { + return (cur->isconst>>hr)&1; + } + } + return 0; +} +static uint64_t get_const(struct regstat *cur,signed char reg) +{ + int hr; + if(!reg) return 0; + for (hr=0;hrregmap[hr]==reg) { + return cur->constmap[hr]; + } + } + DebugMessage(M64MSG_ERROR, "Unknown constant in r%d",reg); + exit(1); +} + +// Least soon needed registers +// Look at the next ten instructions and see which registers +// will be used. Try not to reallocate these. +static void lsn(u_char hsn[], int i, int *preferred_reg) +{ + int j; + int b=-1; + for(j=0;j<9;j++) + { + if(i+j>=slen) { + j=slen-i-1; + break; + } + if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) + { + // Don't go past an unconditonal jump + j++; + break; + } + } + for(;j>=0;j--) + { + if(rs1[i+j]) hsn[rs1[i+j]]=j; + if(rs2[i+j]) hsn[rs2[i+j]]=j; + if(rt1[i+j]) hsn[rt1[i+j]]=j; + if(rt2[i+j]) hsn[rt2[i+j]]=j; + if(itype[i+j]==STORE || itype[i+j]==STORELR) { + // Stores can allocate zero + hsn[rs1[i+j]]=j; + hsn[rs2[i+j]]=j; + } + // On some architectures stores need invc_ptr + #if defined(HOST_IMM8) + if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) { + hsn[INVCP]=j; + } + #endif + if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP||itype[i+j]==FJUMP)) + { + hsn[CCREG]=j; + b=j; + } + } + if(b>=0) + { + if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) + { + // Follow first branch + int t=(ba[i+b]-start)>>2; + j=7-b;if(t+j>=slen) j=slen-t-1; + for(;j>=0;j--) + { + if(rs1[t+j]) if(hsn[rs1[t+j]]>j+b+2) hsn[rs1[t+j]]=j+b+2; + if(rs2[t+j]) if(hsn[rs2[t+j]]>j+b+2) hsn[rs2[t+j]]=j+b+2; + //if(rt1[t+j]) if(hsn[rt1[t+j]]>j+b+2) hsn[rt1[t+j]]=j+b+2; + //if(rt2[t+j]) if(hsn[rt2[t+j]]>j+b+2) hsn[rt2[t+j]]=j+b+2; + } + } + // TODO: preferred register based on backward branch + } + // Delay slot should preferably not overwrite branch conditions or cycle count + if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP)) { + if(rs1[i-1]) if(hsn[rs1[i-1]]>1) hsn[rs1[i-1]]=1; + if(rs2[i-1]) if(hsn[rs2[i-1]]>1) hsn[rs2[i-1]]=1; + hsn[CCREG]=1; + // ...or hash tables + hsn[RHASH]=1; + hsn[RHTBL]=1; + } + // Coprocessor load/store needs FTEMP, even if not declared + if(itype[i]==C1LS) { + hsn[FTEMP]=0; + } + // Load L/R also uses FTEMP as a temporary register + if(itype[i]==LOADLR) { + hsn[FTEMP]=0; + } + // Also 64-bit SDL/SDR + if(opcode[i]==0x2c||opcode[i]==0x2d) { + hsn[FTEMP]=0; + } + // Don't remove the TLB registers either + if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) { + hsn[TLREG]=0; + } + // Don't remove the miniht registers + if(itype[i]==UJUMP||itype[i]==RJUMP) + { + hsn[RHASH]=0; + hsn[RHTBL]=0; + } +} + +// We only want to allocate registers if we're going to use them again soon +static int needed_again(int r, int i) +{ + int j; + /*int b=-1;*/ + int rn=10; + + if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) + { + if(ba[i-1]start+slen*4-4) + return 0; // Don't need any registers if exiting the block + } + for(j=0;j<9;j++) + { + if(i+j>=slen) { + j=slen-i-1; + break; + } + if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) + { + // Don't go past an unconditonal jump + j++; + break; + } + if(itype[i+j]==SYSCALL||((source[i+j]&0xfc00003f)==0x0d)) + { + break; + } + } + for(;j>=1;j--) + { + if(rs1[i+j]==r) rn=j; + if(rs2[i+j]==r) rn=j; + if((unneeded_reg[i+j]>>r)&1) rn=10; + if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP||itype[i+j]==FJUMP)) + { + /*b=j;*/ + } + } + /* + if(b>=0) + { + if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) + { + // Follow first branch + int o=rn; + int t=(ba[i+b]-start)>>2; + j=7-b;if(t+j>=slen) j=slen-t-1; + for(;j>=0;j--) + { + if(!((unneeded_reg[t+j]>>r)&1)) { + if(rs1[t+j]==r) if(rn>j+b+2) rn=j+b+2; + if(rs2[t+j]==r) if(rn>j+b+2) rn=j+b+2; + } + else rn=o; + } + } + }*/ + if(rn<10) return 1; + return 0; +} + +// Try to match register allocations at the end of a loop with those +// at the beginning +static int loop_reg(int i, int r, int hr) +{ + int j,k; + for(j=0;j<9;j++) + { + if(i+j>=slen) { + j=slen-i-1; + break; + } + if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) + { + // Don't go past an unconditonal jump + j++; + break; + } + } + k=0; + if(i>0){ + if(itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP) + k--; + } + for(;k>r)&1)) return hr; + if(r>64&&((unneeded_reg_upper[i+k]>>r)&1)) return hr; + if(i+k>=0&&(itype[i+k]==UJUMP||itype[i+k]==CJUMP||itype[i+k]==SJUMP||itype[i+k]==FJUMP)) + { + if(ba[i+k]>=start && ba[i+k]<(start+i*4)) + { + int t=(ba[i+k]-start)>>2; + int reg=get_reg(regs[t].regmap_entry,r); + if(reg>=0) return reg; + //reg=get_reg(regs[t+1].regmap_entry,r); + //if(reg>=0) return reg; + } + } + } + return hr; +} + + +// Allocate every register, preserving source/target regs +static void alloc_all(struct regstat *cur,int i) +{ + int hr; + + for(hr=0;hrregmap[hr]&63)!=rs1[i])&&((cur->regmap[hr]&63)!=rs2[i])&& + ((cur->regmap[hr]&63)!=rt1[i])&&((cur->regmap[hr]&63)!=rt2[i])) + { + cur->regmap[hr]=-1; + cur->dirty&=~(1<regmap[hr]&63)==0) + { + cur->regmap[hr]=-1; + cur->dirty&=~(1<>32) + // ,(int)reg[LOREG],(int)(reg[LOREG]>>32)); +} +static void divu64(uint64_t dividend,uint64_t divisor) +{ + lo=dividend/divisor; + hi=dividend%divisor; + //DebugMessage(M64MSG_VERBOSE, "TRACE: ddivu %8x%8x %8x%8x",(int)reg[HIREG],(int)(reg[HIREG]>>32) + // ,(int)reg[LOREG],(int)(reg[LOREG]>>32)); +} + +static void mult64(int64_t m1,int64_t m2) +{ + unsigned long long int op1, op2, op3, op4; + unsigned long long int result1, result2, result3, result4; + unsigned long long int temp1, temp2, temp3, temp4; + int sign = 0; + + if (m1 < 0) + { + op2 = -m1; + sign = 1 - sign; + } + else op2 = m1; + if (m2 < 0) + { + op4 = -m2; + sign = 1 - sign; + } + else op4 = m2; + + op1 = op2 & 0xFFFFFFFF; + op2 = (op2 >> 32) & 0xFFFFFFFF; + op3 = op4 & 0xFFFFFFFF; + op4 = (op4 >> 32) & 0xFFFFFFFF; + + temp1 = op1 * op3; + temp2 = (temp1 >> 32) + op1 * op4; + temp3 = op2 * op3; + temp4 = (temp3 >> 32) + op2 * op4; + + result1 = temp1 & 0xFFFFFFFF; + result2 = temp2 + (temp3 & 0xFFFFFFFF); + result3 = (result2 >> 32) + temp4; + result4 = (result3 >> 32); + + lo = result1 | (result2 << 32); + hi = (result3 & 0xFFFFFFFF) | (result4 << 32); + if (sign) + { + hi = ~hi; + if (!lo) hi++; + else lo = ~lo + 1; + } +} + +#if NEW_DYNAREC == NEW_DYNAREC_ARM +static void multu64(uint64_t m1,uint64_t m2) +{ + unsigned long long int op1, op2, op3, op4; + unsigned long long int result1, result2, result3, result4; + unsigned long long int temp1, temp2, temp3, temp4; + + op1 = m1 & 0xFFFFFFFF; + op2 = (m1 >> 32) & 0xFFFFFFFF; + op3 = m2 & 0xFFFFFFFF; + op4 = (m2 >> 32) & 0xFFFFFFFF; + + temp1 = op1 * op3; + temp2 = (temp1 >> 32) + op1 * op4; + temp3 = op2 * op3; + temp4 = (temp3 >> 32) + op2 * op4; + + result1 = temp1 & 0xFFFFFFFF; + result2 = temp2 + (temp3 & 0xFFFFFFFF); + result3 = (result2 >> 32) + temp4; + result4 = (result3 >> 32); + + lo = result1 | (result2 << 32); + hi = (result3 & 0xFFFFFFFF) | (result4 << 32); + + //DebugMessage(M64MSG_VERBOSE, "TRACE: dmultu %8x%8x %8x%8x",(int)reg[HIREG],(int)(reg[HIREG]>>32) + // ,(int)reg[LOREG],(int)(reg[LOREG]>>32)); +} +#endif + +static uint64_t ldl_merge(uint64_t original,uint64_t loaded,u_int bits) +{ + if(bits) { + original<<=64-bits; + original>>=64-bits; + loaded<<=bits; + original|=loaded; + } + else original=loaded; + return original; +} +static uint64_t ldr_merge(uint64_t original,uint64_t loaded,u_int bits) +{ + if(bits^56) { + original>>=64-(bits^56); + original<<=64-(bits^56); + loaded>>=bits^56; + original|=loaded; + } + else original=loaded; + return original; +} + +#if NEW_DYNAREC == NEW_DYNAREC_X86 +#include "assem_x86.c" +#elif NEW_DYNAREC == NEW_DYNAREC_ARM +#include "assem_arm.c" +#else +#error Unsupported dynarec architecture +#endif + +// Add virtual address mapping to linked list +static void ll_add(struct ll_entry **head,int vaddr,void *addr) +{ + struct ll_entry *new_entry; + new_entry=(struct ll_entry *)malloc(sizeof(struct ll_entry)); + assert(new_entry!=NULL); + new_entry->vaddr=vaddr; + new_entry->reg32=0; + new_entry->addr=addr; + new_entry->next=*head; + *head=new_entry; +} + +// Add virtual address mapping for 32-bit compiled block +static void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr) +{ + struct ll_entry *new_entry; + new_entry=(struct ll_entry *)malloc(sizeof(struct ll_entry)); + assert(new_entry!=NULL); + new_entry->vaddr=vaddr; + new_entry->reg32=reg32; + new_entry->addr=addr; + new_entry->next=*head; + *head=new_entry; +} + +// Check if an address is already compiled +// but don't return addresses which are about to expire from the cache +static void *check_addr(u_int vaddr) +{ + u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==vaddr) { + if(((ht_bin[1]-MAX_OUTPUT_BLOCK_SIZE-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) + if(isclean(ht_bin[1])) return (void *)ht_bin[1]; + } + if(ht_bin[2]==vaddr) { + if(((ht_bin[3]-MAX_OUTPUT_BLOCK_SIZE-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) + if(isclean(ht_bin[3])) return (void *)ht_bin[3]; + } + u_int page=(vaddr^0x80000000)>>12; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + struct ll_entry *head; + head=jump_in[page]; + while(head!=NULL) { + if(head->vaddr==vaddr&&head->reg32==0) { + if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { + // Update existing entry with current address + if(ht_bin[0]==vaddr) { + ht_bin[1]=(int)head->addr; + return head->addr; + } + if(ht_bin[2]==vaddr) { + ht_bin[3]=(int)head->addr; + return head->addr; + } + // Insert into hash table with low priority. + // Don't evict existing entries, as they are probably + // addresses that are being accessed frequently. + if(ht_bin[0]==-1) { + ht_bin[1]=(int)head->addr; + ht_bin[0]=vaddr; + }else if(ht_bin[2]==-1) { + ht_bin[3]=(int)head->addr; + ht_bin[2]=vaddr; + } + return head->addr; + } + } + head=head->next; + } + return 0; +} + +static void remove_hash(int vaddr) +{ + //DebugMessage(M64MSG_VERBOSE, "remove hash: %x",vaddr); + u_int *ht_bin=hash_table[(((vaddr)>>16)^vaddr)&0xFFFF]; + if(ht_bin[2]==vaddr) { + ht_bin[2]=ht_bin[3]=-1; + } + if(ht_bin[0]==vaddr) { + ht_bin[0]=ht_bin[2]; + ht_bin[1]=ht_bin[3]; + ht_bin[2]=ht_bin[3]=-1; + } +} + +static void ll_remove_matching_addrs(struct ll_entry **head,int addr,int shift) +{ + struct ll_entry *next; + while(*head) { + if((((u_int)((*head)->addr)-(u_int)base_addr)>>shift)==((addr-(u_int)base_addr)>>shift) || + (((u_int)((*head)->addr)-(u_int)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((addr-(u_int)base_addr)>>shift)) + { + inv_debug("EXP: Remove pointer to %x (%x)\n",(int)(*head)->addr,(*head)->vaddr); + remove_hash((*head)->vaddr); + next=(*head)->next; + free(*head); + *head=next; + } + else + { + head=&((*head)->next); + } + } +} + +// Remove all entries from linked list +static void ll_clear(struct ll_entry **head) +{ + struct ll_entry *cur; + struct ll_entry *next; + if((cur=*head)) { + *head=0; + while(cur) { + next=cur->next; + free(cur); + cur=next; + } + } +} + +// Dereference the pointers and remove if it matches +static void ll_kill_pointers(struct ll_entry *head,int addr,int shift) +{ + while(head) { + u_int ptr=get_pointer(head->addr); + inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(int)ptr,(int)head->addr,head->vaddr); + if((((ptr-(u_int)base_addr)>>shift)==((addr-(u_int)base_addr)>>shift)) || + (((ptr-(u_int)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((addr-(u_int)base_addr)>>shift))) + { + inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr); + u_int host_addr=(int)kill_pointer(head->addr); + #if NEW_DYNAREC == NEW_DYNAREC_ARM + needs_clear_cache[(host_addr-(u_int)base_addr)>>17]|=1<<(((host_addr-(u_int)base_addr)>>12)&31); + #endif + } + head=head->next; + } +} + +// This is called when we write to a compiled block (see do_invstub) +static void invalidate_page(u_int page) +{ + struct ll_entry *head; + struct ll_entry *next; + head=jump_in[page]; + jump_in[page]=0; + while(head!=NULL) { + inv_debug("INVALIDATE: %x\n",head->vaddr); + remove_hash(head->vaddr); + next=head->next; + free(head); + head=next; + } + head=jump_out[page]; + jump_out[page]=0; + while(head!=NULL) { + inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr); + u_int host_addr=(int)kill_pointer(head->addr); + #if NEW_DYNAREC == NEW_DYNAREC_ARM + needs_clear_cache[(host_addr-(u_int)base_addr)>>17]|=1<<(((host_addr-(u_int)base_addr)>>12)&31); + #endif + next=head->next; + free(head); + head=next; + } +} +void invalidate_block(u_int block) +{ + u_int page,vpage; + page=vpage=block^0x80000; + if(page>262143&&tlb_LUT_r[block]) page=(tlb_LUT_r[block]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + if(vpage>262143&&tlb_LUT_r[block]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead + if(vpage>2048) vpage=2048+(vpage&2047); + inv_debug("INVALIDATE: %x (%d)\n",block<<12,page); + //inv_debug("invalid_code[block]=%d\n",invalid_code[block]); + u_int first,last; + first=last=page; + struct ll_entry *head; + head=jump_dirty[vpage]; + //DebugMessage(M64MSG_VERBOSE, "page=%d vpage=%d",page,vpage); + while(head!=NULL) { + u_int start,end; + if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision + get_bounds((int)head->addr,&start,&end); + //DebugMessage(M64MSG_VERBOSE, "start: %x end: %x",start,end); + if(page<2048&&start>=0x80000000&&end<0x80800000) { + if(((start-(u_int)g_rdram)>>12)<=page&&((end-1-(u_int)g_rdram)>>12)>=page) { + if((((start-(u_int)g_rdram)>>12)&2047)>12)&2047; + if((((end-1-(u_int)g_rdram)>>12)&2047)>last) last=((end-1-(u_int)g_rdram)>>12)&2047; + } + } + if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) { + if(((start+memory_map[start>>12]-(u_int)g_rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)g_rdram)>>12)>=page) { + if((((start+memory_map[start>>12]-(u_int)g_rdram)>>12)&2047)>12]-(u_int)g_rdram)>>12)&2047; + if((((end-1+memory_map[(end-1)>>12]-(u_int)g_rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)g_rdram)>>12)&2047; + } + } + } + head=head->next; + } + //DebugMessage(M64MSG_VERBOSE, "first=%d last=%d",first,last); + invalidate_page(page); + assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages) + assert(last>2; + u_int real_block=tlb_LUT_w[block]>>12; + invalid_code[real_block]=1; + if(real_block>=0x80000&&real_block<0x80800) memory_map[real_block]=((u_int)g_rdram-0x80000000)>>2; + } + else if(block>=0x80000&&block<0x80800) memory_map[block]=((u_int)g_rdram-0x80000000)>>2; + #ifdef USE_MINI_HT + memset(mini_ht,-1,sizeof(mini_ht)); + #endif +} + +#if NEW_DYNAREC == NEW_DYNAREC_ARM +static void invalidate_addr(u_int addr) +{ + invalidate_block(addr>>12); +} +#endif + +// This is called when loading a save state. +// Anything could have changed, so invalidate everything. +void invalidate_all_pages() +{ + u_int page; + for(page=0;page<4096;page++) + invalidate_page(page); + for(page=0;page<1048576;page++) + if(!invalid_code[page]) { + restore_candidate[(page&2047)>>3]|=1<<(page&7); + restore_candidate[((page&2047)>>3)+256]|=1<<(page&7); + } + #if NEW_DYNAREC == NEW_DYNAREC_ARM + __clear_cache((void *)base_addr,(void *)base_addr+(1<>2; + if(!tlb_LUT_w[page]||!invalid_code[page]) + memory_map[page]|=0x40000000; // Write protect + } + else memory_map[page]=-1; + if(page==0x80000) page=0xC0000; + } + tlb_hacks(); +} + +// Add an entry to jump_out after making a link +void add_link(u_int vaddr,void *src) +{ + u_int page=(vaddr^0x80000000)>>12; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12; + if(page>4095) page=2048+(page&2047); + inv_debug("add_link: %x -> %x (%d)\n",(int)src,vaddr,page); + ll_add(jump_out+page,vaddr,src); + //int ptr=get_pointer(src); + //inv_debug("add_link: Pointer is to %x\n",(int)ptr); +} + +// If a code block was found to be unmodified (bit was set in +// restore_candidate) and it remains unmodified (bit is clear +// in invalid_code) then move the entries for that 4K page from +// the dirty list to the clean list. +void clean_blocks(u_int page) +{ + struct ll_entry *head; + inv_debug("INV: clean_blocks page=%d\n",page); + head=jump_dirty[page]; + while(head!=NULL) { + if(!invalid_code[head->vaddr>>12]) { + // Don't restore blocks which are about to expire from the cache + if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { + u_int start,end; + if(verify_dirty(head->addr)) { + //DebugMessage(M64MSG_VERBOSE, "Possibly Restore %x (%x)",head->vaddr, (int)head->addr); + u_int i; + u_int inv=0; + get_bounds((int)head->addr,&start,&end); + if(start-(u_int)g_rdram<0x800000) { + for(i=(start-(u_int)g_rdram+0x80000000)>>12;i<=(end-1-(u_int)g_rdram+0x80000000)>>12;i++) { + inv|=invalid_code[i]; + } + } + if((signed int)head->vaddr>=(signed int)0xC0000000) { + u_int addr = (head->vaddr+(memory_map[head->vaddr>>12]<<2)); + //DebugMessage(M64MSG_VERBOSE, "addr=%x start=%x end=%x",addr,start,end); + if(addr=end) inv=1; + } + else if((signed int)head->vaddr>=(signed int)0x80800000) { + inv=1; + } + if(!inv) { + void * clean_addr=(void *)get_clean_addr((int)head->addr); + if((((u_int)clean_addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { + u_int ppage=page; + if(page<2048&&tlb_LUT_r[head->vaddr>>12]) ppage=(tlb_LUT_r[head->vaddr>>12]^0x80000000)>>12; + inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr); + //DebugMessage(M64MSG_VERBOSE, "page=%x, addr=%x",page,head->vaddr); + //assert(head->vaddr>>12==(page|0x80000)); + ll_add_32(jump_in+ppage,head->vaddr,head->reg32,clean_addr); + u_int *ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF]; + if(!head->reg32) { + if(ht_bin[0]==head->vaddr) { + ht_bin[1]=(int)clean_addr; // Replace existing entry + } + if(ht_bin[2]==head->vaddr) { + ht_bin[3]=(int)clean_addr; // Replace existing entry + } + } + } + } + } + } + } + head=head->next; + } +} + + +static void mov_alloc(struct regstat *current,int i) +{ + // Note: Don't need to actually alloc the source registers + if((~current->is32>>rs1[i])&1) { + //alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rt1[i]); + current->is32&=~(1LL<is32|=(1LL<is32|=1LL<=0x38&&opcode2[i]<=0x3b) // DSLL/DSRL/DSRA + { + if(rt1[i]) { + if(rs1[i]) alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rt1[i]); + current->is32&=~(1LL<is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<is32&=~(1LL<=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU + if(rt1[i]) { + if(rs1[i]&&rs2[i]) { + alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,rs2[i]); + } + else { + if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg(current,i,rs2[i]); + } + alloc_reg(current,i,rt1[i]); + } + current->is32|=1LL<is32>>rs1[i])&(current->is32>>rs2[i])&1)) + { + alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rs2[i]); + alloc_reg(current,i,rt1[i]); + } else { + alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,rs2[i]); + alloc_reg(current,i,rt1[i]); + } + } + current->is32|=1LL<=0x24&&opcode2[i]<=0x27) { // AND/OR/XOR/NOR + if(rt1[i]) { + if(rs1[i]&&rs2[i]) { + alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,rs2[i]); + } + else + { + if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg(current,i,rs2[i]); + } + alloc_reg(current,i,rt1[i]); + if(!((current->is32>>rs1[i])&(current->is32>>rs2[i])&1)) + { + if(!((current->uu>>rt1[i])&1)) { + alloc_reg64(current,i,rt1[i]); + } + if(get_reg(current->regmap,rt1[i]|64)>=0) { + if(rs1[i]&&rs2[i]) { + alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rs2[i]); + } + else + { + // Is is really worth it to keep 64-bit values in registers? + #ifdef NATIVE_64BIT + if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg64(current,i,rs1[i]); + if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg64(current,i,rs2[i]); + #endif + } + } + current->is32&=~(1LL<is32|=1LL<=0x2c&&opcode2[i]<=0x2f) { // DADD/DADDU/DSUB/DSUBU + if(rt1[i]) { + if(rs1[i]&&rs2[i]) { + if(!((current->uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { + alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rs2[i]); + alloc_reg64(current,i,rt1[i]); + } else { + alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,rs2[i]); + alloc_reg(current,i,rt1[i]); + } + } + else { + alloc_reg(current,i,rt1[i]); + if(!((current->uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { + // DADD used as move, or zeroing + // If we have a 64-bit source, then make the target 64 bits too + if(rs1[i]&&!((current->is32>>rs1[i])&1)) { + if(get_reg(current->regmap,rs1[i])>=0) alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rt1[i]); + } else if(rs2[i]&&!((current->is32>>rs2[i])&1)) { + if(get_reg(current->regmap,rs2[i])>=0) alloc_reg64(current,i,rs2[i]); + alloc_reg64(current,i,rt1[i]); + } + if(opcode2[i]>=0x2e&&rs2[i]) { + // DSUB used as negation - 64-bit result + // If we have a 32-bit register, extend it to 64 bits + if(get_reg(current->regmap,rs2[i])>=0) alloc_reg64(current,i,rs2[i]); + alloc_reg64(current,i,rt1[i]); + } + } + } + if(rs1[i]&&rs2[i]) { + current->is32&=~(1LL<is32&=~(1LL<is32>>rs1[i])&1) + current->is32|=1LL<is32&=~(1LL<is32>>rs2[i])&1) + current->is32|=1LL<is32|=1LL<is32&=~(1LL<uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { + // TODO: Could preserve the 32-bit flag if the immediate is zero + alloc_reg64(current,i,rt1[i]); + alloc_reg64(current,i,rs1[i]); + } + clear_const(current,rs1[i]); + clear_const(current,rt1[i]); + } + else if(opcode[i]==0x0a||opcode[i]==0x0b) { // SLTI/SLTIU + if((~current->is32>>rs1[i])&1) alloc_reg64(current,i,rs1[i]); + current->is32|=1LL<=0x0c&&opcode[i]<=0x0e) { // ANDI/ORI/XORI + if(((~current->is32>>rs1[i])&1)&&opcode[i]>0x0c) { + if(rs1[i]!=rt1[i]) { + if(needed_again(rs1[i],i)) alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rt1[i]); + current->is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<u&=~1LL; // Allow allocating r0 if it's the source register + if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + if(rt1[i]&&!((current->u>>rt1[i])&1)) { + alloc_reg(current,i,rt1[i]); + assert(get_reg(current->regmap,rt1[i])>=0); + if(opcode[i]==0x27||opcode[i]==0x37) // LWU/LD + { + current->is32&=~(1LL<is32&=~(1LL<is32|=1LL<u&=~1LL; // Allow allocating r0 if necessary + if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,rs2[i]); + if(opcode[i]==0x2c||opcode[i]==0x2d||opcode[i]==0x3f) { // 64-bit SDL/SDR/SD + alloc_reg64(current,i,rs2[i]); + if(rs2[i]) alloc_reg(current,i,FTEMP); + } + // If using TLB, need a register for pointer to the mapping table + if(using_tlb) alloc_reg(current,i,TLREG); + #if defined(HOST_IMM8) + // On CPUs without 32-bit immediates we need a pointer to invalid_code + else alloc_reg(current,i,INVCP); + #endif + if(opcode[i]==0x2c||opcode[i]==0x2d) { // 64-bit SDL/SDR + alloc_reg(current,i,FTEMP); + } + // We need a temporary register for address generation + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} + +static void c1ls_alloc(struct regstat *current,int i) +{ + //clear_const(current,rs1[i]); // FIXME + clear_const(current,rt1[i]); + if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,CSREG); // Status + alloc_reg(current,i,FTEMP); + if(opcode[i]==0x35||opcode[i]==0x3d) { // 64-bit LDC1/SDC1 + alloc_reg64(current,i,FTEMP); + } + // If using TLB, need a register for pointer to the mapping table + if(using_tlb) alloc_reg(current,i,TLREG); + #if defined(HOST_IMM8) + // On CPUs without 32-bit immediates we need a pointer to invalid_code + else if((opcode[i]&0x3b)==0x39) // SWC1/SDC1 + alloc_reg(current,i,INVCP); + #endif + // We need a temporary register for address generation + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} + +#ifndef multdiv_alloc +void multdiv_alloc(struct regstat *current,int i) +{ + // case 0x18: MULT + // case 0x19: MULTU + // case 0x1A: DIV + // case 0x1B: DIVU + // case 0x1C: DMULT + // case 0x1D: DMULTU + // case 0x1E: DDIV + // case 0x1F: DDIVU + clear_const(current,rs1[i]); + clear_const(current,rs2[i]); + if(rs1[i]&&rs2[i]) + { + if((opcode2[i]&4)==0) // 32-bit + { + current->u&=~(1LL<u&=~(1LL<is32|=1LL<is32|=1LL<u&=~(1LL<u&=~(1LL<uu&=~(1LL<uu&=~(1LL<10) alloc_reg64(current,i,LOREG); + alloc_reg64(current,i,rs1[i]); + alloc_reg64(current,i,rs2[i]); + alloc_all(current,i); + current->is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<u&=~1LL; + alloc_reg(current,i,0); + } + } + else + { + // TLBR/TLBWI/TLBWR/TLBP/ERET + assert(opcode2[i]==0x10); + alloc_all(current,i); + } + minimum_free_regs[i]=HOST_REGS; +} + +static void cop1_alloc(struct regstat *current,int i) +{ + alloc_reg(current,i,CSREG); // Load status + if(opcode2[i]<3) // MFC1/DMFC1/CFC1 + { + assert(rt1[i]); + clear_const(current,rt1[i]); + if(opcode2[i]==1) { + alloc_reg64(current,i,rt1[i]); // DMFC1 + current->is32&=~(1LL<is32|=1LL<3) // MTC1/DMTC1/CTC1 + { + if(rs1[i]){ + clear_const(current,rs1[i]); + if(opcode2[i]==5) + alloc_reg64(current,i,rs1[i]); // DMTC1 + else + alloc_reg(current,i,rs1[i]); // MTC1/CTC1 + alloc_reg_temp(current,i,-1); + } + else { + current->u&=~1LL; + alloc_reg(current,i,0); + alloc_reg_temp(current,i,-1); + } + } + minimum_free_regs[i]=1; +} +static void fconv_alloc(struct regstat *current,int i) +{ + alloc_reg(current,i,CSREG); // Load status + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} +static void float_alloc(struct regstat *current,int i) +{ + alloc_reg(current,i,CSREG); // Load status + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} +static void fcomp_alloc(struct regstat *current,int i) +{ + alloc_reg(current,i,CSREG); // Load status + alloc_reg(current,i,FSREG); // Load flags + dirty_reg(current,FSREG); // Flag will be modified + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} + +static void syscall_alloc(struct regstat *current,int i) +{ + alloc_cc(current,i); + dirty_reg(current,CCREG); + alloc_all(current,i); + minimum_free_regs[i]=HOST_REGS; + current->isconst=0; +} + +static void delayslot_alloc(struct regstat *current,int i) +{ + switch(itype[i]) { + case UJUMP: + case CJUMP: + case SJUMP: + case RJUMP: + case FJUMP: + case SYSCALL: + case SPAN: + assem_debug("jump in the delay slot. this shouldn't happen.");//exit(1); + DebugMessage(M64MSG_VERBOSE, "Disabled speculative precompilation"); + stop_after_jal=1; + break; + case IMM16: + imm16_alloc(current,i); + break; + case LOAD: + case LOADLR: + load_alloc(current,i); + break; + case STORE: + case STORELR: + store_alloc(current,i); + break; + case ALU: + alu_alloc(current,i); + break; + case SHIFT: + shift_alloc(current,i); + break; + case MULTDIV: + multdiv_alloc(current,i); + break; + case SHIFTIMM: + shiftimm_alloc(current,i); + break; + case MOV: + mov_alloc(current,i); + break; + case COP0: + cop0_alloc(current,i); + break; + case COP1: + cop1_alloc(current,i); + break; + case C1LS: + c1ls_alloc(current,i); + break; + case FCONV: + fconv_alloc(current,i); + break; + case FLOAT: + float_alloc(current,i); + break; + case FCOMP: + fcomp_alloc(current,i); + break; + } +} + +// Special case where a branch and delay slot span two pages in virtual memory +static void pagespan_alloc(struct regstat *current,int i) +{ + current->isconst=0; + current->wasconst=0; + regs[i].wasconst=0; + minimum_free_regs[i]=HOST_REGS; + alloc_all(current,i); + alloc_cc(current,i); + dirty_reg(current,CCREG); + if(opcode[i]==3) // JAL + { + alloc_reg(current,i,31); + dirty_reg(current,31); + } + if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR + { + alloc_reg(current,i,rs1[i]); + if (rt1[i]!=0) { + alloc_reg(current,i,rt1[i]); + dirty_reg(current,rt1[i]); + } + } + if((opcode[i]&0x2E)==4) // BEQ/BNE/BEQL/BNEL + { + if(rs1[i]) alloc_reg(current,i,rs1[i]); + if(rs2[i]) alloc_reg(current,i,rs2[i]); + if(!((current->is32>>rs1[i])&(current->is32>>rs2[i])&1)) + { + if(rs1[i]) alloc_reg64(current,i,rs1[i]); + if(rs2[i]) alloc_reg64(current,i,rs2[i]); + } + } + else + if((opcode[i]&0x2E)==6) // BLEZ/BGTZ/BLEZL/BGTZL + { + if(rs1[i]) alloc_reg(current,i,rs1[i]); + if(!((current->is32>>rs1[i])&1)) + { + if(rs1[i]) alloc_reg64(current,i,rs1[i]); + } + } + else + if(opcode[i]==0x11) // BC1 + { + alloc_reg(current,i,FSREG); + alloc_reg(current,i,CSREG); + } + //else ... +} + +static void add_stub(int type,int addr,int retaddr,int a,int b,int c,int d,int e) +{ + stubs[stubcount][0]=type; + stubs[stubcount][1]=addr; + stubs[stubcount][2]=retaddr; + stubs[stubcount][3]=a; + stubs[stubcount][4]=b; + stubs[stubcount][5]=c; + stubs[stubcount][6]=d; + stubs[stubcount][7]=e; + stubcount++; +} + +// Write out a single register +static void wb_register(signed char r,signed char regmap[],uint64_t dirty,uint64_t is32) +{ + int hr; + for(hr=0;hr>hr)&1) { + if(regmap[hr]<64) { + emit_storereg(r,hr); + if((is32>>regmap[hr])&1) { + emit_sarimm(hr,31,hr); + emit_storereg(r|64,hr); + } + }else{ + emit_storereg(r|64,hr); + } + } + } + } + } +} +#if 0 +static int mchecksum() +{ + //if(!tracedebug) return 0; + int i; + int sum=0; + for(i=0;i<2097152;i++) { + unsigned int temp=sum; + sum<<=1; + sum|=(~temp)>>31; + sum^=((u_int *)g_rdram)[i]; + } + return sum; +} + +static int rchecksum() +{ + int i; + int sum=0; + for(i=0;i<64;i++) + sum^=((u_int *)reg)[i]; + return sum; +} + +static void rlist() +{ + int i; + DebugMessage(M64MSG_VERBOSE, "TRACE: "); + for(i=0;i<32;i++) + DebugMessage(M64MSG_VERBOSE, "r%d:%8x%8x ",i,((int *)(reg+i))[1],((int *)(reg+i))[0]); + DebugMessage(M64MSG_VERBOSE, "TRACE: "); + for(i=0;i<32;i++) + DebugMessage(M64MSG_VERBOSE, "f%d:%8x%8x ",i,((int*)reg_cop1_simple[i])[1],*((int*)reg_cop1_simple[i])); +} + +static void enabletrace() +{ + tracedebug=1; +} + + +static void memdebug(int i) +{ + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (checksum %x) lo=%8x%8x",g_cp0_regs[CP0_COUNT_REG],next_interupt,mchecksum(),(int)(reg[LOREG]>>32),(int)reg[LOREG]); + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (rchecksum %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,rchecksum()); + //rlist(); + //if(tracedebug) { + //if(g_cp0_regs[CP0_COUNT_REG]>=-2084597794) { + if((signed int)g_cp0_regs[CP0_COUNT_REG]>=-2084597794&&(signed int)g_cp0_regs[CP0_COUNT_REG]<0) { + //if(0) { + DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (checksum %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,mchecksum()); + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (checksum %x) Status=%x",g_cp0_regs[CP0_COUNT_REG],next_interupt,mchecksum(),g_cp0_regs[CP0_STATUS_REG]); + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (checksum %x) hi=%8x%8x",g_cp0_regs[CP0_COUNT_REG],next_interupt,mchecksum(),(int)(reg[HIREG]>>32),(int)reg[HIREG]); + rlist(); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + DebugMessage(M64MSG_VERBOSE, "TRACE: %x",(&i)[-1]); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + int j; + DebugMessage(M64MSG_VERBOSE, "TRACE: %x ",(&j)[10]); + DebugMessage(M64MSG_VERBOSE, "TRACE: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",(&j)[1],(&j)[2],(&j)[3],(&j)[4],(&j)[5],(&j)[6],(&j)[7],(&j)[8],(&j)[9],(&j)[10],(&j)[11],(&j)[12],(&j)[13],(&j)[14],(&j)[15],(&j)[16],(&j)[17],(&j)[18],(&j)[19],(&j)[20]); + #endif + //fflush(stdout); + } + //DebugMessage(M64MSG_VERBOSE, "TRACE: %x",(&i)[-1]); +} +#endif + +/* Debug: +static void tlb_debug(u_int cause, u_int addr, u_int iaddr) +{ + DebugMessage(M64MSG_VERBOSE, "TLB Exception: instruction=%x addr=%x cause=%x",iaddr, addr, cause); +} +end debug */ + +static void alu_assemble(int i,struct regstat *i_regs) +{ + if(opcode2[i]>=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU + if(rt1[i]) { + signed char s1,s2,t; + t=get_reg(i_regs->regmap,rt1[i]); + if(t>=0) { + s1=get_reg(i_regs->regmap,rs1[i]); + s2=get_reg(i_regs->regmap,rs2[i]); + if(rs1[i]&&rs2[i]) { + assert(s1>=0); + assert(s2>=0); + if(opcode2[i]&2) emit_sub(s1,s2,t); + else emit_add(s1,s2,t); + } + else if(rs1[i]) { + if(s1>=0) emit_mov(s1,t); + else emit_loadreg(rs1[i],t); + } + else if(rs2[i]) { + if(s2>=0) { + if(opcode2[i]&2) emit_neg(s2,t); + else emit_mov(s2,t); + } + else { + emit_loadreg(rs2[i],t); + if(opcode2[i]&2) emit_neg(t,t); + } + } + else emit_zeroreg(t); + } + } + } + if(opcode2[i]>=0x2c&&opcode2[i]<=0x2f) { // DADD/DADDU/DSUB/DSUBU + if(rt1[i]) { + signed char s1l,s2l,s1h,s2h,tl,th; + tl=get_reg(i_regs->regmap,rt1[i]); + th=get_reg(i_regs->regmap,rt1[i]|64); + if(tl>=0) { + s1l=get_reg(i_regs->regmap,rs1[i]); + s2l=get_reg(i_regs->regmap,rs2[i]); + s1h=get_reg(i_regs->regmap,rs1[i]|64); + s2h=get_reg(i_regs->regmap,rs2[i]|64); + if(rs1[i]&&rs2[i]) { + assert(s1l>=0); + assert(s2l>=0); + if(th>=0) { + #ifdef INVERTED_CARRY + if(opcode2[i]&2) emit_sub64_32(s1l,s1h,s2l,s2h,tl,th); + #else + if(opcode2[i]&2) { + emit_subs(s1l,s2l,tl); + emit_sbc(s1h,s2h,th); + } + #endif + else { + emit_adds(s1l,s2l,tl); + emit_adc(s1h,s2h,th); + } + } + else { + if(opcode2[i]&2) emit_subs(s1l,s2l,tl); + else emit_adds(s1l,s2l,tl); + } + } + else if(rs1[i]) { + if(s1l>=0) emit_mov(s1l,tl); + else emit_loadreg(rs1[i],tl); + if(th>=0) { + if(s1h>=0) emit_mov(s1h,th); + else emit_loadreg(rs1[i]|64,th); + } + } + else if(rs2[i]) { + if(s2l>=0) { + if(opcode2[i]&2) emit_negs(s2l,tl); + else emit_mov(s2l,tl); + } + else { + emit_loadreg(rs2[i],tl); + if(opcode2[i]&2) emit_negs(tl,tl); + } + if(th>=0) { + #ifdef INVERTED_CARRY + if(s2h>=0) emit_mov(s2h,th); + else emit_loadreg(rs2[i]|64,th); + if(opcode2[i]&2) { + emit_adcimm(-1,th); // x86 has inverted carry flag + emit_not(th,th); + } + #else + if(opcode2[i]&2) { + if(s2h>=0) emit_rscimm(s2h,0,th); + else { + emit_loadreg(rs2[i]|64,th); + emit_rscimm(th,0,th); + } + }else{ + if(s2h>=0) emit_mov(s2h,th); + else emit_loadreg(rs2[i]|64,th); + } + #endif + } + } + else { + emit_zeroreg(tl); + if(th>=0) emit_zeroreg(th); + } + } + } + } + if(opcode2[i]==0x2a||opcode2[i]==0x2b) { // SLT/SLTU + if(rt1[i]) { + signed char s1l,s1h,s2l,s2h,t; + if(!((i_regs->was32>>rs1[i])&(i_regs->was32>>rs2[i])&1)) + { + t=get_reg(i_regs->regmap,rt1[i]); + //assert(t>=0); + if(t>=0) { + s1l=get_reg(i_regs->regmap,rs1[i]); + s1h=get_reg(i_regs->regmap,rs1[i]|64); + s2l=get_reg(i_regs->regmap,rs2[i]); + s2h=get_reg(i_regs->regmap,rs2[i]|64); + if(rs2[i]==0) // rx=0); + if(opcode2[i]==0x2a) // SLT + emit_shrimm(s1h,31,t); + else // SLTU (unsigned can not be less than zero) + emit_zeroreg(t); + } + else if(rs1[i]==0) // r0=0); + if(opcode2[i]==0x2a) // SLT + emit_set_gz64_32(s2h,s2l,t); + else // SLTU (set if not zero) + emit_set_nz64_32(s2h,s2l,t); + } + else { + assert(s1l>=0);assert(s1h>=0); + assert(s2l>=0);assert(s2h>=0); + if(opcode2[i]==0x2a) // SLT + emit_set_if_less64_32(s1h,s1l,s2h,s2l,t); + else // SLTU + emit_set_if_carry64_32(s1h,s1l,s2h,s2l,t); + } + } + } else { + t=get_reg(i_regs->regmap,rt1[i]); + //assert(t>=0); + if(t>=0) { + s1l=get_reg(i_regs->regmap,rs1[i]); + s2l=get_reg(i_regs->regmap,rs2[i]); + if(rs2[i]==0) // rx=0); + if(opcode2[i]==0x2a) // SLT + emit_shrimm(s1l,31,t); + else // SLTU (unsigned can not be less than zero) + emit_zeroreg(t); + } + else if(rs1[i]==0) // r0=0); + if(opcode2[i]==0x2a) // SLT + emit_set_gz32(s2l,t); + else // SLTU (set if not zero) + emit_set_nz32(s2l,t); + } + else{ + assert(s1l>=0);assert(s2l>=0); + if(opcode2[i]==0x2a) // SLT + emit_set_if_less32(s1l,s2l,t); + else // SLTU + emit_set_if_carry32(s1l,s2l,t); + } + } + } + } + } + if(opcode2[i]>=0x24&&opcode2[i]<=0x27) { // AND/OR/XOR/NOR + if(rt1[i]) { + signed char s1l,s1h,s2l,s2h,th,tl; + tl=get_reg(i_regs->regmap,rt1[i]); + th=get_reg(i_regs->regmap,rt1[i]|64); + if(!((i_regs->was32>>rs1[i])&(i_regs->was32>>rs2[i])&1)&&th>=0) + { + assert(tl>=0); + if(tl>=0) { + s1l=get_reg(i_regs->regmap,rs1[i]); + s1h=get_reg(i_regs->regmap,rs1[i]|64); + s2l=get_reg(i_regs->regmap,rs2[i]); + s2h=get_reg(i_regs->regmap,rs2[i]|64); + if(rs1[i]&&rs2[i]) { + assert(s1l>=0);assert(s1h>=0); + assert(s2l>=0);assert(s2h>=0); + if(opcode2[i]==0x24) { // AND + emit_and(s1l,s2l,tl); + emit_and(s1h,s2h,th); + } else + if(opcode2[i]==0x25) { // OR + emit_or(s1l,s2l,tl); + emit_or(s1h,s2h,th); + } else + if(opcode2[i]==0x26) { // XOR + emit_xor(s1l,s2l,tl); + emit_xor(s1h,s2h,th); + } else + if(opcode2[i]==0x27) { // NOR + emit_or(s1l,s2l,tl); + emit_or(s1h,s2h,th); + emit_not(tl,tl); + emit_not(th,th); + } + } + else + { + if(opcode2[i]==0x24) { // AND + emit_zeroreg(tl); + emit_zeroreg(th); + } else + if(opcode2[i]==0x25||opcode2[i]==0x26) { // OR/XOR + if(rs1[i]){ + if(s1l>=0) emit_mov(s1l,tl); + else emit_loadreg(rs1[i],tl); + if(s1h>=0) emit_mov(s1h,th); + else emit_loadreg(rs1[i]|64,th); + } + else + if(rs2[i]){ + if(s2l>=0) emit_mov(s2l,tl); + else emit_loadreg(rs2[i],tl); + if(s2h>=0) emit_mov(s2h,th); + else emit_loadreg(rs2[i]|64,th); + } + else{ + emit_zeroreg(tl); + emit_zeroreg(th); + } + } else + if(opcode2[i]==0x27) { // NOR + if(rs1[i]){ + if(s1l>=0) emit_not(s1l,tl); + else{ + emit_loadreg(rs1[i],tl); + emit_not(tl,tl); + } + if(s1h>=0) emit_not(s1h,th); + else{ + emit_loadreg(rs1[i]|64,th); + emit_not(th,th); + } + } + else + if(rs2[i]){ + if(s2l>=0) emit_not(s2l,tl); + else{ + emit_loadreg(rs2[i],tl); + emit_not(tl,tl); + } + if(s2h>=0) emit_not(s2h,th); + else{ + emit_loadreg(rs2[i]|64,th); + emit_not(th,th); + } + } + else { + emit_movimm(-1,tl); + emit_movimm(-1,th); + } + } + } + } + } + else + { + // 32 bit + if(tl>=0) { + s1l=get_reg(i_regs->regmap,rs1[i]); + s2l=get_reg(i_regs->regmap,rs2[i]); + if(rs1[i]&&rs2[i]) { + assert(s1l>=0); + assert(s2l>=0); + if(opcode2[i]==0x24) { // AND + emit_and(s1l,s2l,tl); + } else + if(opcode2[i]==0x25) { // OR + emit_or(s1l,s2l,tl); + } else + if(opcode2[i]==0x26) { // XOR + emit_xor(s1l,s2l,tl); + } else + if(opcode2[i]==0x27) { // NOR + emit_or(s1l,s2l,tl); + emit_not(tl,tl); + } + } + else + { + if(opcode2[i]==0x24) { // AND + emit_zeroreg(tl); + } else + if(opcode2[i]==0x25||opcode2[i]==0x26) { // OR/XOR + if(rs1[i]){ + if(s1l>=0) emit_mov(s1l,tl); + else emit_loadreg(rs1[i],tl); // CHECK: regmap_entry? + } + else + if(rs2[i]){ + if(s2l>=0) emit_mov(s2l,tl); + else emit_loadreg(rs2[i],tl); // CHECK: regmap_entry? + } + else emit_zeroreg(tl); + } else + if(opcode2[i]==0x27) { // NOR + if(rs1[i]){ + if(s1l>=0) emit_not(s1l,tl); + else { + emit_loadreg(rs1[i],tl); + emit_not(tl,tl); + } + } + else + if(rs2[i]){ + if(s2l>=0) emit_not(s2l,tl); + else { + emit_loadreg(rs2[i],tl); + emit_not(tl,tl); + } + } + else emit_movimm(-1,tl); + } + } + } + } + } + } +} + +static void imm16_assemble(int i,struct regstat *i_regs) +{ + if (opcode[i]==0x0f) { // LUI + if(rt1[i]) { + signed char t; + t=get_reg(i_regs->regmap,rt1[i]); + //assert(t>=0); + if(t>=0) { + if(!((i_regs->isconst>>t)&1)) + emit_movimm(imm[i]<<16,t); + } + } + } + if(opcode[i]==0x08||opcode[i]==0x09) { // ADDI/ADDIU + if(rt1[i]) { + signed char s,t; + t=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + if(rs1[i]) { + //assert(t>=0); + //assert(s>=0); + if(t>=0) { + if(!((i_regs->isconst>>t)&1)) { + if(s<0) { + if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); + emit_addimm(t,imm[i],t); + }else{ + if(!((i_regs->wasconst>>s)&1)) + emit_addimm(s,imm[i],t); + else + emit_movimm(constmap[i][s]+imm[i],t); + } + } + } + } else { + if(t>=0) { + if(!((i_regs->isconst>>t)&1)) + emit_movimm(imm[i],t); + } + } + } + } + if(opcode[i]==0x18||opcode[i]==0x19) { // DADDI/DADDIU + if(rt1[i]) { + signed char sh,sl,th,tl; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + if(tl>=0) { + if(rs1[i]) { + assert(sh>=0); + assert(sl>=0); + if(th>=0) { + emit_addimm64_32(sh,sl,imm[i],th,tl); + } + else { + emit_addimm(sl,imm[i],tl); + } + } else { + emit_movimm(imm[i],tl); + if(th>=0) emit_movimm(((signed int)imm[i])>>31,th); + } + } + } + } + else if(opcode[i]==0x0a||opcode[i]==0x0b) { // SLTI/SLTIU + if(rt1[i]) { + //assert(rs1[i]!=0); // r0 might be valid, but it's probably a bug + signed char sh,sl,t; + t=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + //assert(t>=0); + if(t>=0) { + if(rs1[i]>0) { + if(sh<0) assert((i_regs->was32>>rs1[i])&1); + if(sh<0||((i_regs->was32>>rs1[i])&1)) { + if(opcode[i]==0x0a) { // SLTI + if(sl<0) { + if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); + emit_slti32(t,imm[i],t); + }else{ + emit_slti32(sl,imm[i],t); + } + } + else { // SLTIU + if(sl<0) { + if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); + emit_sltiu32(t,imm[i],t); + }else{ + emit_sltiu32(sl,imm[i],t); + } + } + }else{ // 64-bit + assert(sl>=0); + if(opcode[i]==0x0a) // SLTI + emit_slti64_32(sh,sl,imm[i],t); + else // SLTIU + emit_sltiu64_32(sh,sl,imm[i],t); + } + }else{ + // SLTI(U) with r0 is just stupid, + // nonetheless examples can be found + if(opcode[i]==0x0a) // SLTI + if(0=0x0c&&opcode[i]<=0x0e) { // ANDI/ORI/XORI + if(rt1[i]) { + signed char sh,sl,th,tl; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + if(tl>=0 && !((i_regs->isconst>>tl)&1)) { + if(opcode[i]==0x0c) //ANDI + { + if(rs1[i]) { + if(sl<0) { + if(i_regs->regmap_entry[tl]!=rs1[i]) emit_loadreg(rs1[i],tl); + emit_andimm(tl,imm[i],tl); + }else{ + if(!((i_regs->wasconst>>sl)&1)) + emit_andimm(sl,imm[i],tl); + else + emit_movimm(constmap[i][sl]&imm[i],tl); + } + } + else + emit_zeroreg(tl); + if(th>=0) emit_zeroreg(th); + } + else + { + if(rs1[i]) { + if(sl<0) { + if(i_regs->regmap_entry[tl]!=rs1[i]) emit_loadreg(rs1[i],tl); + } + if(th>=0) { + if(sh<0) { + emit_loadreg(rs1[i]|64,th); + }else{ + emit_mov(sh,th); + } + } + if(opcode[i]==0x0d) { //ORI + if(sl<0) { + emit_orimm(tl,imm[i],tl); + }else{ + if(!((i_regs->wasconst>>sl)&1)) + emit_orimm(sl,imm[i],tl); + else + emit_movimm(constmap[i][sl]|imm[i],tl); + } + } + if(opcode[i]==0x0e) { //XORI + if(sl<0) { + emit_xorimm(tl,imm[i],tl); + }else{ + if(!((i_regs->wasconst>>sl)&1)) + emit_xorimm(sl,imm[i],tl); + else + emit_movimm(constmap[i][sl]^imm[i],tl); + } + } + } + else { + emit_movimm(imm[i],tl); + if(th>=0) emit_zeroreg(th); + } + } + } + } + } +} + +static void shiftimm_assemble(int i,struct regstat *i_regs) +{ + if(opcode2[i]<=0x3) // SLL/SRL/SRA + { + if(rt1[i]) { + signed char s,t; + t=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + //assert(t>=0); + if(t>=0){ + if(rs1[i]==0) + { + emit_zeroreg(t); + } + else + { + if(s<0&&i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); + if(imm[i]) { + if(opcode2[i]==0) // SLL + { + emit_shlimm(s<0?t:s,imm[i],t); + } + if(opcode2[i]==2) // SRL + { + emit_shrimm(s<0?t:s,imm[i],t); + } + if(opcode2[i]==3) // SRA + { + emit_sarimm(s<0?t:s,imm[i],t); + } + }else{ + // Shift by zero + if(s>=0 && s!=t) emit_mov(s,t); + } + } + } + //emit_storereg(rt1[i],t); //DEBUG + } + } + if(opcode2[i]>=0x38&&opcode2[i]<=0x3b) // DSLL/DSRL/DSRA + { + if(rt1[i]) { + signed char sh,sl,th,tl; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + if(tl>=0) { + if(rs1[i]==0) + { + emit_zeroreg(tl); + if(th>=0) emit_zeroreg(th); + } + else + { + assert(sl>=0); + assert(sh>=0); + if(imm[i]) { + if(opcode2[i]==0x38) // DSLL + { + if(th>=0) emit_shldimm(sh,sl,imm[i],th); + emit_shlimm(sl,imm[i],tl); + } + if(opcode2[i]==0x3a) // DSRL + { + emit_shrdimm(sl,sh,imm[i],tl); + if(th>=0) emit_shrimm(sh,imm[i],th); + } + if(opcode2[i]==0x3b) // DSRA + { + emit_shrdimm(sl,sh,imm[i],tl); + if(th>=0) emit_sarimm(sh,imm[i],th); + } + }else{ + // Shift by zero + if(sl!=tl) emit_mov(sl,tl); + if(th>=0&&sh!=th) emit_mov(sh,th); + } + } + } + } + } + if(opcode2[i]==0x3c) // DSLL32 + { + if(rt1[i]) { + signed char sl,tl,th; + tl=get_reg(i_regs->regmap,rt1[i]); + th=get_reg(i_regs->regmap,rt1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + if(th>=0||tl>=0){ + assert(tl>=0); + assert(th>=0); + assert(sl>=0); + emit_mov(sl,th); + emit_zeroreg(tl); + if(imm[i]>32) + { + emit_shlimm(th,imm[i]&31,th); + } + } + } + } + if(opcode2[i]==0x3e) // DSRL32 + { + if(rt1[i]) { + signed char sh,tl,th; + tl=get_reg(i_regs->regmap,rt1[i]); + th=get_reg(i_regs->regmap,rt1[i]|64); + sh=get_reg(i_regs->regmap,rs1[i]|64); + if(tl>=0){ + assert(sh>=0); + emit_mov(sh,tl); + if(th>=0) emit_zeroreg(th); + if(imm[i]>32) + { + emit_shrimm(tl,imm[i]&31,tl); + } + } + } + } + if(opcode2[i]==0x3f) // DSRA32 + { + if(rt1[i]) { + signed char sh,tl; + tl=get_reg(i_regs->regmap,rt1[i]); + sh=get_reg(i_regs->regmap,rs1[i]|64); + if(tl>=0){ + assert(sh>=0); + emit_mov(sh,tl); + if(imm[i]>32) + { + emit_sarimm(tl,imm[i]&31,tl); + } + } + } + } +} + +#ifndef shift_assemble +void shift_assemble(int i,struct regstat *i_regs) +{ + DebugMessage(M64MSG_ERROR, "Need shift_assemble for this architecture."); + exit(1); +} +#endif + +static void load_assemble(int i,struct regstat *i_regs) +{ + int s,th,tl,addr,map=-1,cache=-1; + int offset; + int jaddr=0; + int memtarget,c=0; + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + s=get_reg(i_regs->regmap,rs1[i]); + offset=imm[i]; + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { + c=(i_regs->wasconst>>s)&1; + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } + if(tl<0) tl=get_reg(i_regs->regmap,-1); + if(offset||s<0||c) addr=tl; + else addr=s; + //DebugMessage(M64MSG_VERBOSE, "load_assemble: c=%d",c); + //if(c) DebugMessage(M64MSG_VERBOSE, "load_assemble: const=%x",(int)constmap[i][s]+offset); + assert(tl>=0); // Even if the load is a NOP, we must check for pagefaults and I/O + reglist&=~(1<=0) reglist&=~(1<regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + #endif +//#define R29_HACK 1 + #ifdef R29_HACK + // Strmnnrmn's speed hack + if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + #endif + { + emit_cmpimm(addr,0x800000); + jaddr=(int)out; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + // Hint to branch predictor that the branch is unlikely to be taken + if(rs1[i]>=28) + emit_jno_unlikely(0); + else + #endif + emit_jno(0); + } + } + }else{ // using tlb + int x=0; + if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU + if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU + map=get_reg(i_regs->regmap,TLREG); + cache=get_reg(i_regs->regmap,MMREG); + assert(map>=0); + reglist&=~(1<regmap,rt1[i])); // ignore loads to r0 and unneeded reg + if (opcode[i]==0x20) { // LB + if(!c||memtarget) { + if(!dummy) { + #ifdef HOST_IMM_ADDR32 + if(c) + emit_movsbl_tlb((constmap[i][s]+offset)^3,map,tl); + else + #endif + { + //emit_xorimm(addr,3,tl); + //gen_tlb_addr_r(tl,map); + //emit_movsbl_indexed((int)g_rdram-0x80000000,tl,tl); + int x=0; + if(!c) emit_xorimm(addr,3,tl); + else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset); + emit_movsbl_indexed_tlb(x,tl,map,tl); + } + } + if(jaddr) + add_stub(LOADB_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADB_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x21) { // LH + if(!c||memtarget) { + if(!dummy) { + #ifdef HOST_IMM_ADDR32 + if(c) + emit_movswl_tlb((constmap[i][s]+offset)^2,map,tl); + else + #endif + { + int x=0; + if(!c) emit_xorimm(addr,2,tl); + else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset); + //#ifdef + //emit_movswl_indexed_tlb(x,tl,map,tl); + //else + if(map>=0) { + gen_tlb_addr_r(tl,map); + emit_movswl_indexed(x,tl,tl); + }else{ + #ifdef RAM_OFFSET + emit_movswl_indexed(x,tl,tl); + #else + emit_movswl_indexed((int)g_rdram-0x80000000+x,tl,tl); + #endif + } + } + } + if(jaddr) + add_stub(LOADH_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADH_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x23) { // LW + if(!c||memtarget) { + if(!dummy) { + //emit_readword_indexed((int)g_rdram-0x80000000,addr,tl); + #ifdef HOST_IMM_ADDR32 + if(c) + emit_readword_tlb(constmap[i][s]+offset,map,tl); + else + #endif + emit_readword_indexed_tlb(0,addr,map,tl); + } + if(jaddr) + add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x24) { // LBU + if(!c||memtarget) { + if(!dummy) { + #ifdef HOST_IMM_ADDR32 + if(c) + emit_movzbl_tlb((constmap[i][s]+offset)^3,map,tl); + else + #endif + { + //emit_xorimm(addr,3,tl); + //gen_tlb_addr_r(tl,map); + //emit_movzbl_indexed((int)g_rdram-0x80000000,tl,tl); + int x=0; + if(!c) emit_xorimm(addr,3,tl); + else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset); + emit_movzbl_indexed_tlb(x,tl,map,tl); + } + } + if(jaddr) + add_stub(LOADBU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADBU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x25) { // LHU + if(!c||memtarget) { + if(!dummy) { + #ifdef HOST_IMM_ADDR32 + if(c) + emit_movzwl_tlb((constmap[i][s]+offset)^2,map,tl); + else + #endif + { + int x=0; + if(!c) emit_xorimm(addr,2,tl); + else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset); + //#ifdef + //emit_movzwl_indexed_tlb(x,tl,map,tl); + //#else + if(map>=0) { + gen_tlb_addr_r(tl,map); + emit_movzwl_indexed(x,tl,tl); + }else{ + #ifdef RAM_OFFSET + emit_movzwl_indexed(x,tl,tl); + #else + emit_movzwl_indexed((int)g_rdram-0x80000000+x,tl,tl); + #endif + } + } + } + if(jaddr) + add_stub(LOADHU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADHU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x27) { // LWU + assert(th>=0); + if(!c||memtarget) { + if(!dummy) { + //emit_readword_indexed((int)g_rdram-0x80000000,addr,tl); + #ifdef HOST_IMM_ADDR32 + if(c) + emit_readword_tlb(constmap[i][s]+offset,map,tl); + else + #endif + emit_readword_indexed_tlb(0,addr,map,tl); + } + if(jaddr) + add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else { + inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + emit_zeroreg(th); + } + if (opcode[i]==0x37) { // LD + if(!c||memtarget) { + if(!dummy) { + //gen_tlb_addr_r(tl,map); + //if(th>=0) emit_readword_indexed((int)g_rdram-0x80000000,addr,th); + //emit_readword_indexed((int)g_rdram-0x7FFFFFFC,addr,tl); + #ifdef HOST_IMM_ADDR32 + if(c) + emit_readdword_tlb(constmap[i][s]+offset,map,th,tl); + else + #endif + emit_readdword_indexed_tlb(0,addr,map,th,tl); + } + if(jaddr) + add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else + inline_readstub(LOADD_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + //emit_storereg(rt1[i],tl); // DEBUG + //if(opcode[i]==0x23) + //if(opcode[i]==0x24) + //if(opcode[i]==0x23||opcode[i]==0x24) + /*if(opcode[i]==0x21||opcode[i]==0x23||opcode[i]==0x24) + { + //emit_pusha(); + save_regs(0x100f); + emit_readword((int)&last_count,ECX); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + if(get_reg(i_regs->regmap,CCREG)<0) + emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + if(get_reg(i_regs->regmap,CCREG)<0) + emit_loadreg(CCREG,0); + else + emit_mov(HOST_CCREG,0); + emit_add(0,ECX,0); + emit_addimm(0,2*ccadj[i],0); + emit_writeword(0,(int)&g_cp0_regs[CP0_COUNT_REG]); + #endif + emit_call((int)memdebug); + //emit_popa(); + restore_regs(0x100f); + }*/ +} + +#ifndef loadlr_assemble +static void loadlr_assemble(int i,struct regstat *i_regs) +{ + DebugMessage(M64MSG_ERROR, "Need loadlr_assemble for this architecture."); + exit(1); +} +#endif + +static void store_assemble(int i,struct regstat *i_regs) +{ + int s,th,tl,map=-1,cache=-1; + int addr,temp; + int offset; + int jaddr=0,jaddr2,type; + int memtarget,c=0; + int agr=AGEN1+(i&1); + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,rs2[i]|64); + tl=get_reg(i_regs->regmap,rs2[i]); + s=get_reg(i_regs->regmap,rs1[i]); + temp=get_reg(i_regs->regmap,agr); + if(temp<0) temp=get_reg(i_regs->regmap,-1); + offset=imm[i]; + if(s>=0) { + c=(i_regs->wasconst>>s)&1; + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } + assert(tl>=0); + assert(temp>=0); + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + #endif + if(!c) { + #ifdef R29_HACK + // Strmnnrmn's speed hack + memtarget=1; + if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + #endif + emit_cmpimm(addr,0x800000); + #ifdef DESTRUCTIVE_SHIFT + if(s==addr) emit_mov(s,temp); + #endif + #ifdef R29_HACK + if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + #endif + { + jaddr=(int)out; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + // Hint to branch predictor that the branch is unlikely to be taken + if(rs1[i]>=28) + emit_jno_unlikely(0); + else + #endif + emit_jno(0); + } + } + }else{ // using tlb + int x=0; + if (opcode[i]==0x28) x=3; // SB + if (opcode[i]==0x29) x=2; // SH + map=get_reg(i_regs->regmap,TLREG); + cache=get_reg(i_regs->regmap,MMREG); + assert(map>=0); + reglist&=~(1<=0) { + gen_tlb_addr_w(temp,map); + emit_writehword_indexed(tl,x,temp); + }else + emit_writehword_indexed(tl,(int)g_rdram-0x80000000+x,temp); + } + type=STOREH_STUB; + } + if (opcode[i]==0x2B) { // SW + if(!c||memtarget) + //emit_writeword_indexed(tl,(int)g_rdram-0x80000000,addr); + emit_writeword_indexed_tlb(tl,0,addr,map,temp); + type=STOREW_STUB; + } + if (opcode[i]==0x3F) { // SD + if(!c||memtarget) { + if(rs2[i]) { + assert(th>=0); + //emit_writeword_indexed(th,(int)g_rdram-0x80000000,addr); + //emit_writeword_indexed(tl,(int)g_rdram-0x7FFFFFFC,addr); + emit_writedword_indexed_tlb(th,tl,0,addr,map,temp); + }else{ + // Store zero + //emit_writeword_indexed(tl,(int)g_rdram-0x80000000,temp); + //emit_writeword_indexed(tl,(int)g_rdram-0x7FFFFFFC,temp); + emit_writedword_indexed_tlb(tl,tl,0,addr,map,temp); + } + } + type=STORED_STUB; + } + if(!using_tlb) { + if(!c||memtarget) { + #ifdef DESTRUCTIVE_SHIFT + // The x86 shift operation is 'destructive'; it overwrites the + // source register, so we need to make a copy first and use that. + addr=temp; + #endif + #if defined(HOST_IMM8) + int ir=get_reg(i_regs->regmap,INVCP); + assert(ir>=0); + emit_cmpmem_indexedsr12_reg(ir,addr,1); + #else + emit_cmpmem_indexedsr12_imm((int)invalid_code,addr,1); + #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[addr]); + #else + jaddr2=(int)out; + emit_jne(0); + add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<regmap,rs2[i],ccadj[i],reglist); + } + //if(opcode[i]==0x2B || opcode[i]==0x3F) + //if(opcode[i]==0x2B || opcode[i]==0x28) + //if(opcode[i]==0x2B || opcode[i]==0x29) + //if(opcode[i]==0x2B) + +// Uncomment for extra debug output: +/* + if(opcode[i]==0x2B || opcode[i]==0x28 || opcode[i]==0x29 || opcode[i]==0x3F) + { + #if NEW_DYNAREC == NEW_DYNAREC_X86 + emit_pusha(); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + save_regs(0x100f); + #endif + emit_readword((int)&last_count,ECX); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + if(get_reg(i_regs->regmap,CCREG)<0) + emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + if(get_reg(i_regs->regmap,CCREG)<0) + emit_loadreg(CCREG,0); + else + emit_mov(HOST_CCREG,0); + emit_add(0,ECX,0); + emit_addimm(0,2*ccadj[i],0); + emit_writeword(0,(int)&g_cp0_regs[CP0_COUNT_REG]); + #endif + emit_call((int)memdebug); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + emit_popa(); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + restore_regs(0x100f); + #endif + } +*/ +} + +static void storelr_assemble(int i,struct regstat *i_regs) +{ + int s,th,tl; + int temp; + int temp2; + int offset; + int jaddr=0,jaddr2; + int case1,case2,case3; + int done0,done1,done2; + int memtarget,c=0; + int agr=AGEN1+(i&1); + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,rs2[i]|64); + tl=get_reg(i_regs->regmap,rs2[i]); + s=get_reg(i_regs->regmap,rs1[i]); + temp=get_reg(i_regs->regmap,agr); + if(temp<0) temp=get_reg(i_regs->regmap,-1); + offset=imm[i]; + if(s>=0) { + c=(i_regs->isconst>>s)&1; + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } + assert(tl>=0); + for(hr=0;hrregmap[hr]>=0) reglist|=1<=0); + if(!using_tlb) { + if(!c) { + emit_cmpimm(s<0||offset?temp:s,0x800000); + if(!offset&&s!=temp) emit_mov(s,temp); + jaddr=(int)out; + emit_jno(0); + } + else + { + if(!memtarget||!rs1[i]) { + jaddr=(int)out; + emit_jmp(0); + } + } + #ifdef RAM_OFFSET + int map=get_reg(i_regs->regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + gen_tlb_addr_w(temp,map); + #else + if((u_int)g_rdram!=0x80000000) + emit_addimm_no_flags((u_int)g_rdram-(u_int)0x80000000,temp); + #endif + }else{ // using tlb + int map=get_reg(i_regs->regmap,TLREG); + int cache=get_reg(i_regs->regmap,MMREG); + assert(map>=0); + reglist&=~(1<=0) emit_mov(s,temp); + do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr); + if(!jaddr&&!memtarget) { + jaddr=(int)out; + emit_jmp(0); + } + gen_tlb_addr_w(temp,map); + } + + if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR + temp2=get_reg(i_regs->regmap,FTEMP); + if(!rs2[i]) temp2=th=tl; + } + + emit_testimm(temp,2); + case2=(int)out; + emit_jne(0); + emit_testimm(temp,1); + case1=(int)out; + emit_jne(0); + // 0 + if (opcode[i]==0x2A) { // SWL + emit_writeword_indexed(tl,0,temp); + } + if (opcode[i]==0x2E) { // SWR + emit_writebyte_indexed(tl,3,temp); + } + if (opcode[i]==0x2C) { // SDL + emit_writeword_indexed(th,0,temp); + if(rs2[i]) emit_mov(tl,temp2); + } + if (opcode[i]==0x2D) { // SDR + emit_writebyte_indexed(tl,3,temp); + if(rs2[i]) emit_shldimm(th,tl,24,temp2); + } + done0=(int)out; + emit_jmp(0); + // 1 + set_jump_target(case1,(int)out); + if (opcode[i]==0x2A) { // SWL + // Write 3 msb into three least significant bytes + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,16,tl); + emit_writebyte_indexed(tl,1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write two lsb into two most significant bytes + emit_writehword_indexed(tl,1,temp); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,8,temp2); + // Write 3 msb into three least significant bytes + if(rs2[i]) emit_rorimm(th,8,th); + emit_writehword_indexed(th,-1,temp); + if(rs2[i]) emit_rorimm(th,16,th); + emit_writebyte_indexed(th,1,temp); + if(rs2[i]) emit_rorimm(th,8,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_shldimm(th,tl,16,temp2); + // Write two lsb into two most significant bytes + emit_writehword_indexed(tl,1,temp); + } + done1=(int)out; + emit_jmp(0); + // 2 + set_jump_target(case2,(int)out); + emit_testimm(temp,1); + case3=(int)out; + emit_jne(0); + if (opcode[i]==0x2A) { // SWL + // Write two msb into two least significant bytes + if(rs2[i]) emit_rorimm(tl,16,tl); + emit_writehword_indexed(tl,-2,temp); + if(rs2[i]) emit_rorimm(tl,16,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write 3 lsb into three most significant bytes + emit_writebyte_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,0,temp); + if(rs2[i]) emit_rorimm(tl,24,tl); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,16,temp2); + // Write two msb into two least significant bytes + if(rs2[i]) emit_rorimm(th,16,th); + emit_writehword_indexed(th,-2,temp); + if(rs2[i]) emit_rorimm(th,16,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_shldimm(th,tl,8,temp2); + // Write 3 lsb into three most significant bytes + emit_writebyte_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,0,temp); + if(rs2[i]) emit_rorimm(tl,24,tl); + } + done2=(int)out; + emit_jmp(0); + // 3 + set_jump_target(case3,(int)out); + if (opcode[i]==0x2A) { // SWL + // Write msb into least significant byte + if(rs2[i]) emit_rorimm(tl,24,tl); + emit_writebyte_indexed(tl,-3,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write entire word + emit_writeword_indexed(tl,-3,temp); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,24,temp2); + // Write msb into least significant byte + if(rs2[i]) emit_rorimm(th,24,th); + emit_writebyte_indexed(th,-3,temp); + if(rs2[i]) emit_rorimm(th,8,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_mov(th,temp2); + // Write entire word + emit_writeword_indexed(tl,-3,temp); + } + set_jump_target(done0,(int)out); + set_jump_target(done1,(int)out); + set_jump_target(done2,(int)out); + if (opcode[i]==0x2C) { // SDL + emit_testimm(temp,4); + done0=(int)out; + emit_jne(0); + emit_andimm(temp,~3,temp); + emit_writeword_indexed(temp2,4,temp); + set_jump_target(done0,(int)out); + } + if (opcode[i]==0x2D) { // SDR + emit_testimm(temp,4); + done0=(int)out; + emit_jeq(0); + emit_andimm(temp,~3,temp); + emit_writeword_indexed(temp2,-4,temp); + set_jump_target(done0,(int)out); + } + if(!c||!memtarget) + add_stub(STORELR_STUB,jaddr,(int)out,0,(int)i_regs,rs2[i],ccadj[i],reglist); + if(!using_tlb) { + #ifdef RAM_OFFSET + int map=get_reg(i_regs->regmap,ROREG); + if(map<0) map=HOST_TEMPREG; + gen_orig_addr_w(temp,map); + #else + emit_addimm_no_flags((u_int)0x80000000-(u_int)g_rdram,temp); + #endif + #if defined(HOST_IMM8) + int ir=get_reg(i_regs->regmap,INVCP); + assert(ir>=0); + emit_cmpmem_indexedsr12_reg(ir,temp,1); + #else + emit_cmpmem_indexedsr12_imm((int)invalid_code,temp,1); + #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[temp]); + #else + jaddr2=(int)out; + emit_jne(0); + add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<regmap,CCREG)<0) + emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)memdebug); + emit_popa(); + //restore_regs(0x100f); + */ +} + +static void c1ls_assemble(int i,struct regstat *i_regs) +{ + int s,th,tl; + int temp,ar; + int map=-1; + int offset; + int c=0; + int jaddr,jaddr2=0,jaddr3,type; + int agr=AGEN1+(i&1); + u_int hr,reglist=0; + th=get_reg(i_regs->regmap,FTEMP|64); + tl=get_reg(i_regs->regmap,FTEMP); + s=get_reg(i_regs->regmap,rs1[i]); + temp=get_reg(i_regs->regmap,agr); + if(temp<0) temp=get_reg(i_regs->regmap,-1); + offset=imm[i]; + assert(tl>=0); + assert(rs1[i]>0); + assert(temp>=0); + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<wasconst>>s)&1; + if(s>=0) c=(i_regs->wasconst>>s)&1; + // Check cop1 unusable + if(!cop1_usable) { + signed char rs=get_reg(i_regs->regmap,CSREG); + assert(rs>=0); + emit_testimm(rs,0x20000000); + jaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); + cop1_usable=1; + } + if (opcode[i]==0x39) { // SWC1 (get float address) + emit_readword((int)®_cop1_simple[(source[i]>>16)&0x1f],tl); + } + if (opcode[i]==0x3D) { // SDC1 (get double address) + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],tl); + } + // Generate address + offset + if(!using_tlb) { + #ifdef RAM_OFFSET + if (!c||opcode[i]==0x39||opcode[i]==0x3D) // SWC1/SDC1 + { + map=get_reg(i_regs->regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + } + #endif + if(!c) + emit_cmpimm(offset||c||s<0?ar:s,0x800000); + } + else + { + map=get_reg(i_regs->regmap,TLREG); + int cache=get_reg(i_regs->regmap,MMREG); + assert(map>=0); + reglist&=~(1<>16)&0x1f],temp); + } + if (opcode[i]==0x35) { // LDC1 (get target address) + emit_readword((int)®_cop1_double[(source[i]>>16)&0x1f],temp); + } + if(!using_tlb) { + if(!c) { + jaddr2=(int)out; + emit_jno(0); + } + else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) { + jaddr2=(int)out; + emit_jmp(0); // inline_readstub/inline_writestub? Very rare case + } + #ifdef DESTRUCTIVE_SHIFT + if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1 + if(!offset&&!c&&s>=0) emit_mov(s,ar); + } + #endif + }else{ + if (opcode[i]==0x31||opcode[i]==0x35) { // LWC1/LDC1 + do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr2); + } + if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1 + do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr2); + } + } + if (opcode[i]==0x31) { // LWC1 + //if(s>=0&&!c&&!offset) emit_mov(s,tl); + //gen_tlb_addr_r(ar,map); + //emit_readword_indexed((int)g_rdram-0x80000000,tl,tl); + #ifdef HOST_IMM_ADDR32 + if(c) emit_readword_tlb(constmap[i][s]+offset,map,tl); + else + #endif + emit_readword_indexed_tlb(0,offset||c||s<0?tl:s,map,tl); + type=LOADW_STUB; + } + if (opcode[i]==0x35) { // LDC1 + assert(th>=0); + //if(s>=0&&!c&&!offset) emit_mov(s,tl); + //gen_tlb_addr_r(ar,map); + //emit_readword_indexed((int)g_rdram-0x80000000,tl,th); + //emit_readword_indexed((int)g_rdram-0x7FFFFFFC,tl,tl); + #ifdef HOST_IMM_ADDR32 + if(c) emit_readdword_tlb(constmap[i][s]+offset,map,th,tl); + else + #endif + emit_readdword_indexed_tlb(0,offset||c||s<0?tl:s,map,th,tl); + type=LOADD_STUB; + } + if (opcode[i]==0x39) { // SWC1 + //emit_writeword_indexed(tl,(int)g_rdram-0x80000000,temp); + emit_writeword_indexed_tlb(tl,0,offset||c||s<0?temp:s,map,temp); + type=STOREW_STUB; + } + if (opcode[i]==0x3D) { // SDC1 + assert(th>=0); + //emit_writeword_indexed(th,(int)g_rdram-0x80000000,temp); + //emit_writeword_indexed(tl,(int)g_rdram-0x7FFFFFFC,temp); + emit_writedword_indexed_tlb(th,tl,0,offset||c||s<0?temp:s,map,temp); + type=STORED_STUB; + } + if(!using_tlb) { + if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1 + #ifndef DESTRUCTIVE_SHIFT + temp=offset||c||s<0?ar:s; + #endif + #if defined(HOST_IMM8) + int ir=get_reg(i_regs->regmap,INVCP); + assert(ir>=0); + emit_cmpmem_indexedsr12_reg(ir,temp,1); + #else + emit_cmpmem_indexedsr12_imm((int)invalid_code,temp,1); + #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[temp]); + #else + jaddr3=(int)out; + emit_jne(0); + add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<regmap,CCREG)<0) + emit_loadreg(CCREG,HOST_CCREG); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_call((int)memdebug); + emit_popa(); + }*/ +} + +#ifndef multdiv_assemble +void multdiv_assemble(int i,struct regstat *i_regs) +{ + DebugMessage(M64MSG_ERROR, "Need multdiv_assemble for this architecture."); + exit(1); +} +#endif + +static void mov_assemble(int i,struct regstat *i_regs) +{ + //if(opcode2[i]==0x10||opcode2[i]==0x12) { // MFHI/MFLO + //if(opcode2[i]==0x11||opcode2[i]==0x13) { // MTHI/MTLO + if(rt1[i]) { + signed char sh,sl,th,tl; + th=get_reg(i_regs->regmap,rt1[i]|64); + tl=get_reg(i_regs->regmap,rt1[i]); + //assert(tl>=0); + if(tl>=0) { + sh=get_reg(i_regs->regmap,rs1[i]|64); + sl=get_reg(i_regs->regmap,rs1[i]); + if(sl>=0) emit_mov(sl,tl); + else emit_loadreg(rs1[i],tl); + if(th>=0) { + if(sh>=0) emit_mov(sh,th); + else emit_loadreg(rs1[i]|64,th); + } + } + } +} + +#ifndef fconv_assemble +void fconv_assemble(int i,struct regstat *i_regs) +{ + DebugMessage(M64MSG_ERROR, "Need fconv_assemble for this architecture."); + exit(1); +} +#endif + +#if 0 +static void float_assemble(int i,struct regstat *i_regs) +{ + DebugMessage(M64MSG_ERROR, "Need float_assemble for this architecture."); + exit(1); +} +#endif + +static void syscall_assemble(int i,struct regstat *i_regs) +{ + signed char ccreg=get_reg(i_regs->regmap,CCREG); + assert(ccreg==HOST_CCREG); + assert(!is_delayslot); + emit_movimm(start+i*4,EAX); // Get PC + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... + emit_jmp((int)jump_syscall); +} + +static void ds_assemble(int i,struct regstat *i_regs) +{ + is_delayslot=1; + switch(itype[i]) { + case ALU: + alu_assemble(i,i_regs);break; + case IMM16: + imm16_assemble(i,i_regs);break; + case SHIFT: + shift_assemble(i,i_regs);break; + case SHIFTIMM: + shiftimm_assemble(i,i_regs);break; + case LOAD: + load_assemble(i,i_regs);break; + case LOADLR: + loadlr_assemble(i,i_regs);break; + case STORE: + store_assemble(i,i_regs);break; + case STORELR: + storelr_assemble(i,i_regs);break; + case COP0: + cop0_assemble(i,i_regs);break; + case COP1: + cop1_assemble(i,i_regs);break; + case C1LS: + c1ls_assemble(i,i_regs);break; + case FCONV: + fconv_assemble(i,i_regs);break; + case FLOAT: + float_assemble(i,i_regs);break; + case FCOMP: + fcomp_assemble(i,i_regs);break; + case MULTDIV: + multdiv_assemble(i,i_regs);break; + case MOV: + mov_assemble(i,i_regs);break; + case SYSCALL: + case SPAN: + case UJUMP: + case RJUMP: + case CJUMP: + case SJUMP: + case FJUMP: + DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); + } + is_delayslot=0; +} + +// Is the branch target a valid internal jump? +static int internal_branch(uint64_t i_is32,int addr) +{ + if(addr&1) return 0; // Indirect (register) jump + if((u_int)addr>=start && (u_int)addr>2; + // Delay slots are not valid branch targets + //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0; + // 64 -> 32 bit transition requires a recompile + /*if(is32[t]&~unneeded_reg_upper[t]&~i_is32) + { + if(requires_32bit[t]&~i_is32) DebugMessage(M64MSG_VERBOSE, "optimizable: no"); + else DebugMessage(M64MSG_VERBOSE, "optimizable: yes"); + }*/ + //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; + if(requires_32bit[t]&~i_is32) return 0; + else return 1; + } + return 0; +} + +#ifndef wb_invalidate +static void wb_invalidate(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32, + uint64_t u,uint64_t uu) +{ + int hr; + for(hr=0;hr=0) { + if((dirty>>hr)&1) { + if(get_reg(entry,pre[hr])<0) { + if(pre[hr]<64) { + if(!((u>>pre[hr])&1)) { + emit_storereg(pre[hr],hr); + if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { + emit_sarimm(hr,31,hr); + emit_storereg(pre[hr]|64,hr); + } + } + }else{ + if(!((uu>>(pre[hr]&63))&1) && !((is32>>(pre[hr]&63))&1)) { + emit_storereg(pre[hr],hr); + } + } + } + } + } + } + } + } + // Move from one register to another (no writeback) + for(hr=0;hr=0&&(pre[hr]&63)=0) { + emit_mov(hr,nr); + } + } + } + } + } +} +#endif + +// Load the specified registers +// This only loads the registers given as arguments because +// we don't want to load things that will be overwritten +static void load_regs(signed char entry[],signed char regmap[],int is32,int rs1,int rs2) +{ + int hr; + // Load 32-bit regs + for(hr=0;hr=0) { + if(entry[hr]!=regmap[hr]) { + if(regmap[hr]==rs1||regmap[hr]==rs2) + { + if(regmap[hr]==0) { + emit_zeroreg(hr); + } + else + { + emit_loadreg(regmap[hr],hr); + } + } + } + } + } + //Load 64-bit regs + for(hr=0;hr=0) { + if(entry[hr]!=regmap[hr]) { + if(regmap[hr]-64==rs1||regmap[hr]-64==rs2) + { + assert(regmap[hr]!=64); + if((is32>>(regmap[hr]&63))&1) { + int lr=get_reg(regmap,regmap[hr]-64); + if(lr>=0) + emit_sarimm(lr,31,hr); + else + emit_loadreg(regmap[hr],hr); + } + else + { + emit_loadreg(regmap[hr],hr); + } + } + } + } + } +} + +// Load registers prior to the start of a loop +// so that they are not loaded within the loop +static void loop_preload(signed char pre[],signed char entry[]) +{ + int hr; + for(hr=0;hr=0) { + if(get_reg(pre,entry[hr])<0) { + assem_debug("loop preload:"); + //DebugMessage(M64MSG_VERBOSE, "loop preload: %d",hr); + if(entry[hr]==0) { + emit_zeroreg(hr); + } + else if(entry[hr]regmap,rt1[i]); + if(ra<0) ra=get_reg(i_regs->regmap,-1); + assert(ra>=0); + } + if(itype[i]==LOADLR) { + ra=get_reg(i_regs->regmap,FTEMP); + } + if(itype[i]==STORE||itype[i]==STORELR) { + ra=get_reg(i_regs->regmap,agr); + if(ra<0) ra=get_reg(i_regs->regmap,-1); + } + if(itype[i]==C1LS) { + if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1 + ra=get_reg(i_regs->regmap,FTEMP); + else { // SWC1/SDC1 + ra=get_reg(i_regs->regmap,agr); + if(ra<0) ra=get_reg(i_regs->regmap,-1); + } + } + int rs=get_reg(i_regs->regmap,rs1[i]); + int rm=get_reg(i_regs->regmap,TLREG); + if(ra>=0) { + int offset=imm[i]; + int c=(i_regs->wasconst>>rs)&1; + if(rs1[i]==0) { + // Using r0 as a base address + /*if(rm>=0) { + if(!entry||entry[rm]!=mgr) { + generate_map_const(offset,rm); + } // else did it in the previous cycle + }*/ + if(!entry||entry[ra]!=agr) { + if (opcode[i]==0x22||opcode[i]==0x26) { + emit_movimm(offset&0xFFFFFFFC,ra); // LWL/LWR + }else if (opcode[i]==0x1a||opcode[i]==0x1b) { + emit_movimm(offset&0xFFFFFFF8,ra); // LDL/LDR + }else{ + emit_movimm(offset,ra); + } + } // else did it in the previous cycle + } + else if(rs<0) { + if(!entry||entry[ra]!=rs1[i]) + emit_loadreg(rs1[i],ra); + //if(!entry||entry[ra]!=rs1[i]) + // DebugMessage(M64MSG_VERBOSE, "poor load scheduling!"); + } + else if(c) { + if(rm>=0) { + if(!entry||entry[rm]!=mgr) { + if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) { + // Stores to memory go thru the mapper to detect self-modifying + // code, loads don't. + if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 || + (unsigned int)(constmap[i][rs]+offset)<0x80800000 ) + generate_map_const(constmap[i][rs]+offset,rm); + }else{ + if((signed int)(constmap[i][rs]+offset)>=(signed int)0xC0000000) + generate_map_const(constmap[i][rs]+offset,rm); + } + } + } + if(rs1[i]!=rt1[i]||itype[i]!=LOAD) { + if(!entry||entry[ra]!=agr) { + if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR + #ifdef RAM_OFFSET + if((signed int)constmap[i][rs]+offset<(signed int)0x80800000) + emit_movimm(((constmap[i][rs]+offset)&0xFFFFFFFC)+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm((constmap[i][rs]+offset)&0xFFFFFFFC,ra); + }else if (opcode[i]==0x1a||opcode[i]==0x1b) { // LDL/LDR + #ifdef RAM_OFFSET + if((signed int)constmap[i][rs]+offset<(signed int)0x80800000) + emit_movimm(((constmap[i][rs]+offset)&0xFFFFFFF8)+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm((constmap[i][rs]+offset)&0xFFFFFFF8,ra); + }else{ + #ifdef HOST_IMM_ADDR32 + if((itype[i]!=LOAD&&opcode[i]!=0x31&&opcode[i]!=0x35) || + (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000)) + #endif + #ifdef RAM_OFFSET + if((itype[i]==LOAD||opcode[i]==0x31||opcode[i]==0x35)&&(signed int)constmap[i][rs]+offset<(signed int)0x80800000) + emit_movimm(constmap[i][rs]+offset+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm(constmap[i][rs]+offset,ra); + } + } // else did it in the previous cycle + } // else load_consts already did it + } + if(offset&&!c&&rs1[i]) { + if(rs>=0) { + emit_addimm(rs,offset,ra); + }else{ + emit_addimm(ra,offset,ra); + } + } + } + } + // Preload constants for next instruction + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { + int agr,ra; + #ifndef HOST_IMM_ADDR32 + // Mapper entry + agr=MGEN1+((i+1)&1); + ra=get_reg(i_regs->regmap,agr); + if(ra>=0) { + int rs=get_reg(regs[i+1].regmap,rs1[i+1]); + int offset=imm[i+1]; + int c=(regs[i+1].wasconst>>rs)&1; + if(c) { + if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { + // Stores to memory go thru the mapper to detect self-modifying + // code, loads don't. + if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 || + (unsigned int)(constmap[i+1][rs]+offset)<0x80800000 ) + generate_map_const(constmap[i+1][rs]+offset,ra); + }else{ + if((signed int)(constmap[i+1][rs]+offset)>=(signed int)0xC0000000) + generate_map_const(constmap[i+1][rs]+offset,ra); + } + } + /*else if(rs1[i]==0) { + generate_map_const(offset,ra); + }*/ + } + #endif + // Actual address + agr=AGEN1+((i+1)&1); + ra=get_reg(i_regs->regmap,agr); + if(ra>=0) { + int rs=get_reg(regs[i+1].regmap,rs1[i+1]); + int offset=imm[i+1]; + int c=(regs[i+1].wasconst>>rs)&1; + if(c&&(rs1[i+1]!=rt1[i+1]||itype[i+1]!=LOAD)) { + if (opcode[i+1]==0x22||opcode[i+1]==0x26) { // LWL/LWR + #ifdef RAM_OFFSET + if((signed int)constmap[i+1][rs]+offset<(signed int)0x80800000) + emit_movimm(((constmap[i+1][rs]+offset)&0xFFFFFFFC)+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFFC,ra); + }else if (opcode[i+1]==0x1a||opcode[i+1]==0x1b) { // LDL/LDR + #ifdef RAM_OFFSET + if((signed int)constmap[i+1][rs]+offset<(signed int)0x80800000) + emit_movimm(((constmap[i+1][rs]+offset)&0xFFFFFFF8)+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFF8,ra); + }else{ + #ifdef HOST_IMM_ADDR32 + if((itype[i+1]!=LOAD&&opcode[i+1]!=0x31&&opcode[i+1]!=0x35) || + (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000)) + #endif + #ifdef RAM_OFFSET + if((itype[i+1]==LOAD||opcode[i+1]==0x31||opcode[i+1]==0x35)&&(signed int)constmap[i+1][rs]+offset<(signed int)0x80800000) + emit_movimm(constmap[i+1][rs]+offset+(int)g_rdram-0x80000000,ra); + else + #endif + emit_movimm(constmap[i+1][rs]+offset,ra); + } + } + else if(rs1[i+1]==0) { + // Using r0 as a base address + if (opcode[i+1]==0x22||opcode[i+1]==0x26) { + emit_movimm(offset&0xFFFFFFFC,ra); // LWL/LWR + }else if (opcode[i+1]==0x1a||opcode[i+1]==0x1b) { + emit_movimm(offset&0xFFFFFFF8,ra); // LDL/LDR + }else{ + emit_movimm(offset,ra); + } + } + } + } +} + +static int get_final_value(int hr, int i, int *value) +{ + int reg=regs[i].regmap[hr]; + while(i>hr)&1)) break; + if(bt[i+1]) break; + i++; + } + if(i>hr)&1)) + { + #ifdef HOST_IMM_ADDR32 + if(!using_tlb||((signed int)constmap[i][hr]+imm[i+2])<(signed int)0xC0000000) return 0; + #endif + #ifdef RAM_OFFSET + if((signed int)constmap[i][hr]+imm[i+2]<(signed int)0x80800000) + *value=constmap[i][hr]+imm[i+2]+(int)g_rdram-0x80000000; + else + #endif + // Precompute load address + *value=constmap[i][hr]+imm[i+2]; + return 1; + } + } + if(itype[i+1]==LOAD&&rs1[i+1]==reg&&rt1[i+1]==reg) + { + #ifdef HOST_IMM_ADDR32 + if(!using_tlb||((signed int)constmap[i][hr]+imm[i+1])<(signed int)0xC0000000) return 0; + #endif + #ifdef RAM_OFFSET + if((signed int)constmap[i][hr]+imm[i+1]<(signed int)0x80800000) + *value=constmap[i][hr]+imm[i+1]+(int)g_rdram-0x80000000; + else + #endif + // Precompute load address + *value=constmap[i][hr]+imm[i+1]; + //DebugMessage(M64MSG_VERBOSE, "c=%x imm=%x",(int)constmap[i][hr],imm[i+1]); + return 1; + } + } + } + *value=constmap[i][hr]; + //DebugMessage(M64MSG_VERBOSE, "c=%x",(int)constmap[i][hr]); + if(i==slen-1) return 1; + if(reg<64) { + return !((unneeded_reg[i+1]>>reg)&1); + }else{ + return !((unneeded_reg_upper[i+1]>>reg)&1); + } +} + +// Load registers with known constants +static void load_consts(signed char pre[],signed char regmap[],int is32,int i) +{ + int hr; + // Load 32-bit regs + for(hr=0;hr=0) { + //if(entry[hr]!=regmap[hr]) { + if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { + if(((regs[i].isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) { + int value; + if(get_final_value(hr,i,&value)) { + if(value==0) { + emit_zeroreg(hr); + } + else { + emit_movimm(value,hr); + } + } + } + } + } + } + // Load 64-bit regs + for(hr=0;hr=0) { + //if(entry[hr]!=regmap[hr]) { + if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { + if(((regs[i].isconst>>hr)&1)&®map[hr]>64) { + if((is32>>(regmap[hr]&63))&1) { + int lr=get_reg(regmap,regmap[hr]-64); + assert(lr>=0); + emit_sarimm(lr,31,hr); + } + else + { + int value; + if(get_final_value(hr,i,&value)) { + if(value==0) { + emit_zeroreg(hr); + } + else { + emit_movimm(value,hr); + } + } + } + } + } + } + } +} +static void load_all_consts(signed char regmap[],int is32,u_int dirty,int i) +{ + int hr; + // Load 32-bit regs + for(hr=0;hr=0&&((dirty>>hr)&1)) { + if(((regs[i].isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) { + int value=constmap[i][hr]; + if(value==0) { + emit_zeroreg(hr); + } + else { + emit_movimm(value,hr); + } + } + } + } + // Load 64-bit regs + for(hr=0;hr=0&&((dirty>>hr)&1)) { + if(((regs[i].isconst>>hr)&1)&®map[hr]>64) { + if((is32>>(regmap[hr]&63))&1) { + int lr=get_reg(regmap,regmap[hr]-64); + assert(lr>=0); + emit_sarimm(lr,31,hr); + } + else + { + int value=constmap[i][hr]; + if(value==0) { + emit_zeroreg(hr); + } + else { + emit_movimm(value,hr); + } + } + } + } + } +} + +// Write out all dirty registers (except cycle count) +static void wb_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty) +{ + int hr; + for(hr=0;hr0) { + if(i_regmap[hr]!=CCREG) { + if((i_dirty>>hr)&1) { + if(i_regmap[hr]<64) { + emit_storereg(i_regmap[hr],hr); + if( ((i_is32>>i_regmap[hr])&1) ) { + #ifdef DESTRUCTIVE_WRITEBACK + emit_sarimm(hr,31,hr); + emit_storereg(i_regmap[hr]|64,hr); + #else + emit_sarimm(hr,31,HOST_TEMPREG); + emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); + #endif + } + }else{ + if( !((i_is32>>(i_regmap[hr]&63))&1) ) { + emit_storereg(i_regmap[hr],hr); + } + } + } + } + } + } + } +} +// Write out dirty registers that we need to reload (pair with load_needed_regs) +// This writes the registers not written by store_regs_bt +static void wb_needed_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) +{ + int hr; + int t=(addr-start)>>2; + for(hr=0;hr0) { + if(i_regmap[hr]!=CCREG) { + if(i_regmap[hr]==regs[t].regmap_entry[hr] && ((regs[t].dirty>>hr)&1) && !(((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { + if((i_dirty>>hr)&1) { + if(i_regmap[hr]<64) { + emit_storereg(i_regmap[hr],hr); + if( ((i_is32>>i_regmap[hr])&1) ) { + #ifdef DESTRUCTIVE_WRITEBACK + emit_sarimm(hr,31,hr); + emit_storereg(i_regmap[hr]|64,hr); + #else + emit_sarimm(hr,31,HOST_TEMPREG); + emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); + #endif + } + }else{ + if( !((i_is32>>(i_regmap[hr]&63))&1) ) { + emit_storereg(i_regmap[hr],hr); + } + } + } + } + } + } + } + } +} + +// Load all registers (except cycle count) +static void load_all_regs(signed char i_regmap[]) +{ + int hr; + for(hr=0;hr0 && (i_regmap[hr]&63)=0) { + if(i_regmap[hr]==0) { + emit_zeroreg(hr); + } + else + if(i_regmap[hr]>0 && (i_regmap[hr]&63)=0&®s[t].regmap_entry[hr]=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { + int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); + if(lr<0) { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + else + { + emit_sarimm(lr,31,hr); + } + } + else + { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + } + } +} + +// Store dirty registers prior to branch +static void store_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) +{ + if(internal_branch(i_is32,addr)) + { + int t=(addr-start)>>2; + int hr; + for(hr=0;hr0 && i_regmap[hr]!=CCREG) { + if(i_regmap[hr]!=regs[t].regmap_entry[hr] || !((regs[t].dirty>>hr)&1) || (((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { + if((i_dirty>>hr)&1) { + if(i_regmap[hr]<64) { + if(!((unneeded_reg[t]>>i_regmap[hr])&1)) { + emit_storereg(i_regmap[hr],hr); + if( ((i_is32>>i_regmap[hr])&1) && !((unneeded_reg_upper[t]>>i_regmap[hr])&1) ) { + #ifdef DESTRUCTIVE_WRITEBACK + emit_sarimm(hr,31,hr); + emit_storereg(i_regmap[hr]|64,hr); + #else + emit_sarimm(hr,31,HOST_TEMPREG); + emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); + #endif + } + } + }else{ + if( !((i_is32>>(i_regmap[hr]&63))&1) && !((unneeded_reg_upper[t]>>(i_regmap[hr]&63))&1) ) { + emit_storereg(i_regmap[hr],hr); + } + } + } + } + } + } + } + } + else + { + // Branch out of this block, write out all dirty regs + wb_dirtys(i_regmap,i_is32,i_dirty); + } +} + +// Load all needed registers for branch target +static void load_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) +{ + //if(addr>=start && addr<(start+slen*4)) + if(internal_branch(i_is32,addr)) + { + int t=(addr-start)>>2; + int hr; + // Store the cycle count before loading something else + if(i_regmap[HOST_CCREG]!=CCREG) { + assert(i_regmap[HOST_CCREG]==-1); + } + if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) { + emit_storereg(CCREG,HOST_CCREG); + } + // Load 32-bit regs + for(hr=0;hr=0&®s[t].regmap_entry[hr]>hr)&1) && ((i_dirty>>hr)&1) && (((i_is32&~unneeded_reg_upper[t])>>i_regmap[hr])&1) ) || (((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { + #else + if(i_regmap[hr]!=regs[t].regmap_entry[hr] ) { + #endif + if(regs[t].regmap_entry[hr]==0) { + emit_zeroreg(hr); + } + else if(regs[t].regmap_entry[hr]!=CCREG) + { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + } + } + } + //Load 64-bit regs + for(hr=0;hr=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { + int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); + if(lr<0) { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + else + { + emit_sarimm(lr,31,hr); + } + } + else + { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + } + else if((i_is32>>(regs[t].regmap_entry[hr]&63))&1) { + int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); + if(lr<0) { + emit_loadreg(regs[t].regmap_entry[hr],hr); + } + else + { + emit_sarimm(lr,31,hr); + } + } + } + } + } +} + +static int match_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) +{ + if((u_int)addr>=start && (u_int)addr>2; + int hr; + if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) return 0; + for(hr=0;hr=0&&(regs[t].regmap_entry[hr]|64)>hr)&1) + { + if(i_regmap[hr]>i_regmap[hr])&1)) + return 0; + } + else if(i_regmap[hr]>=64&&i_regmap[hr]>(i_regmap[hr]&63))&1)) + return 0; + } + } + } + else // Same register but is it 32-bit or dirty? + if(i_regmap[hr]>=0) + { + if(!((regs[t].dirty>>hr)&1)) + { + if((i_dirty>>hr)&1) + { + if(!((unneeded_reg[t]>>i_regmap[hr])&1)) + { + //DebugMessage(M64MSG_VERBOSE, "%x: dirty no match",addr); + return 0; + } + } + } + if((((regs[t].was32^i_is32)&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1) + { + //DebugMessage(M64MSG_VERBOSE, "%x: is32 no match",addr); + return 0; + } + } + } + } + //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; + if(requires_32bit[t]&~i_is32) return 0; + // Delay slots are not valid branch targets + //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0; + // Delay slots require additional processing, so do not match + if(is_ds[t]) return 0; + } + else + { + int hr; + for(hr=0;hr=0) + { + if(hr!=HOST_CCREG||i_regmap[hr]!=CCREG) + { + if((i_dirty>>hr)&1) + { + return 0; + } + } + } + } + } + } + return 1; +} + +// Used when a branch jumps into the delay slot of another branch +static void ds_assemble_entry(int i) +{ + int t=(ba[i]-start)>>2; + if(!instr_addr[t]) instr_addr[t]=(u_int)out; + assem_debug("Assemble delay slot at %x",ba[i]); + assem_debug("<->"); + if(regs[t].regmap_entry[HOST_CCREG]==CCREG&®s[t].regmap[HOST_CCREG]!=CCREG) + wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32); + load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]); + address_generation(t,®s[t],regs[t].regmap_entry); + if(itype[t]==LOAD||itype[t]==LOADLR||itype[t]==STORE||itype[t]==STORELR||itype[t]==C1LS) + load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,MMREG,ROREG); + if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39) + load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP); + cop1_usable=0; + is_delayslot=0; + switch(itype[t]) { + case ALU: + alu_assemble(t,®s[t]);break; + case IMM16: + imm16_assemble(t,®s[t]);break; + case SHIFT: + shift_assemble(t,®s[t]);break; + case SHIFTIMM: + shiftimm_assemble(t,®s[t]);break; + case LOAD: + load_assemble(t,®s[t]);break; + case LOADLR: + loadlr_assemble(t,®s[t]);break; + case STORE: + store_assemble(t,®s[t]);break; + case STORELR: + storelr_assemble(t,®s[t]);break; + case COP0: + cop0_assemble(t,®s[t]);break; + case COP1: + cop1_assemble(t,®s[t]);break; + case C1LS: + c1ls_assemble(t,®s[t]);break; + case FCONV: + fconv_assemble(t,®s[t]);break; + case FLOAT: + float_assemble(t,®s[t]);break; + case FCOMP: + fcomp_assemble(t,®s[t]);break; + case MULTDIV: + multdiv_assemble(t,®s[t]);break; + case MOV: + mov_assemble(t,®s[t]);break; + case SYSCALL: + case SPAN: + case UJUMP: + case RJUMP: + case CJUMP: + case SJUMP: + case FJUMP: + DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); + } + store_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); + load_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); + if(internal_branch(regs[t].is32,ba[i]+4)) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + assert(internal_branch(regs[t].is32,ba[i]+4)); + add_to_linker((int)out,ba[i]+4,internal_branch(regs[t].is32,ba[i]+4)); + emit_jmp(0); +} + +static void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) +{ + int count; + int jaddr; + int idle=0; + if(itype[i]==RJUMP) + { + *adj=0; + } + //if(ba[i]>=start && ba[i]<(start+slen*4)) + if(internal_branch(branch_regs[i].is32,ba[i])) + { + int t=(ba[i]-start)>>2; + if(is_ds[t]) *adj=-1; // Branch into delay slot adds an extra cycle + else *adj=ccadj[t]; + } + else + { + *adj=0; + } + count=ccadj[i]; + if(taken==TAKEN && i==(ba[i]-start)>>2 && source[i+1]==0) { + // Idle loop + if(count&1) emit_addimm_and_set_flags(2*(count+2),HOST_CCREG); + idle=(int)out; + //emit_subfrommem(&idlecount,HOST_CCREG); // Count idle cycles + emit_andimm(HOST_CCREG,3,HOST_CCREG); + jaddr=(int)out; + emit_jmp(0); + } + else if(*adj==0||invert) { + emit_addimm_and_set_flags(CLOCK_DIVIDER*(count+2),HOST_CCREG); + jaddr=(int)out; + emit_jns(0); + } + else + { + emit_cmpimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(count+2)); + jaddr=(int)out; + emit_jns(0); + } + add_stub(CC_STUB,jaddr,idle?idle:(int)out,(*adj==0||invert||idle)?0:(count+2),i,addr,taken,0); +} + +static void do_ccstub(int n) +{ + literal_pool(256); + assem_debug("do_ccstub %x",start+stubs[n][4]*4); + set_jump_target(stubs[n][1],(int)out); + int i=stubs[n][4]; + if(stubs[n][6]==NULLDS) { + // Delay slot instruction is nullified ("likely" branch) + wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); + } + else if(stubs[n][6]!=TAKEN) { + wb_dirtys(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty); + } + else { + if(internal_branch(branch_regs[i].is32,ba[i])) + wb_needed_dirtys(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + } + if(stubs[n][5]!=-1) + { + // Save PC as return address + emit_movimm(stubs[n][5],EAX); + emit_writeword(EAX,(int)&pcaddr); + } + else + { + // Return address depends on which way the branch goes + if(itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + int s1l=get_reg(branch_regs[i].regmap,rs1[i]); + int s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); + int s2l=get_reg(branch_regs[i].regmap,rs2[i]); + int s2h=get_reg(branch_regs[i].regmap,rs2[i]|64); + if(rs1[i]==0) + { + s1l=s2l;s1h=s2h; + s2l=s2h=-1; + } + else if(rs2[i]==0) + { + s2l=s2h=-1; + } + if((branch_regs[i].is32>>rs1[i])&(branch_regs[i].is32>>rs2[i])&1) { + s1h=s2h=-1; + } + assert(s1l>=0); + #ifdef DESTRUCTIVE_WRITEBACK + if(rs1[i]) { + if((branch_regs[i].dirty>>s1l)&(branch_regs[i].is32>>rs1[i])&1) + emit_loadreg(rs1[i],s1l); + } + else { + if((branch_regs[i].dirty>>s1l)&(branch_regs[i].is32>>rs2[i])&1) + emit_loadreg(rs2[i],s1l); + } + if(s2l>=0) + if((branch_regs[i].dirty>>s2l)&(branch_regs[i].is32>>rs2[i])&1) + emit_loadreg(rs2[i],s2l); + #endif + int hr=0; + int addr,alt,ntaddr; + while(hr=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmov2imm_e_ne_compact(ba[i],start+i*4+8,addr); + } + else + #endif + { + emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmovne_reg(alt,addr); + } + } + if((opcode[i]&0x2f)==5) // BNE + { + #ifdef HAVE_CMOV_IMM + if(s1h<0) { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmov2imm_e_ne_compact(start+i*4+8,ba[i],addr); + } + else + #endif + { + emit_mov2imm_compact(start+i*4+8,addr,ba[i],alt); + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmovne_reg(alt,addr); + } + } + if((opcode[i]&0x2f)==6) // BLEZ + { + //emit_movimm(ba[i],alt); + //emit_movimm(start+i*4+8,addr); + emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); + emit_cmpimm(s1l,1); + if(s1h>=0) emit_mov(addr,ntaddr); + emit_cmovl_reg(alt,addr); + if(s1h>=0) { + emit_test(s1h,s1h); + emit_cmovne_reg(ntaddr,addr); + emit_cmovs_reg(alt,addr); + } + } + if((opcode[i]&0x2f)==7) // BGTZ + { + //emit_movimm(ba[i],addr); + //emit_movimm(start+i*4+8,ntaddr); + emit_mov2imm_compact(ba[i],addr,start+i*4+8,ntaddr); + emit_cmpimm(s1l,1); + if(s1h>=0) emit_mov(addr,alt); + emit_cmovl_reg(ntaddr,addr); + if(s1h>=0) { + emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + emit_cmovs_reg(ntaddr,addr); + } + } + if((opcode[i]==1)&&(opcode2[i]&0x2D)==0) // BLTZ + { + //emit_movimm(ba[i],alt); + //emit_movimm(start+i*4+8,addr); + emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); + if(s1h>=0) emit_test(s1h,s1h); + else emit_test(s1l,s1l); + emit_cmovs_reg(alt,addr); + } + if((opcode[i]==1)&&(opcode2[i]&0x2D)==1) // BGEZ + { + //emit_movimm(ba[i],addr); + //emit_movimm(start+i*4+8,alt); + emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); + if(s1h>=0) emit_test(s1h,s1h); + else emit_test(s1l,s1l); + emit_cmovs_reg(alt,addr); + } + if(opcode[i]==0x11 && opcode2[i]==0x08 ) { + if(source[i]&0x10000) // BC1T + { + //emit_movimm(ba[i],alt); + //emit_movimm(start+i*4+8,addr); + emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); + emit_testimm(s1l,0x800000); + emit_cmovne_reg(alt,addr); + } + else // BC1F + { + //emit_movimm(ba[i],addr); + //emit_movimm(start+i*4+8,alt); + emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); + emit_testimm(s1l,0x800000); + emit_cmovne_reg(alt,addr); + } + } + emit_writeword(addr,(int)&pcaddr); + } + else + if(itype[i]==RJUMP) + { + int r=get_reg(branch_regs[i].regmap,rs1[i]); + if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) { + r=get_reg(branch_regs[i].regmap,RTEMP); + } + emit_writeword(r,(int)&pcaddr); + } + else {DebugMessage(M64MSG_ERROR, "Unknown branch type in do_ccstub");exit(1);} + } + // Update cycle count + assert(branch_regs[i].regmap[HOST_CCREG]==CCREG||branch_regs[i].regmap[HOST_CCREG]==-1); + if(stubs[n][3]) emit_addimm(HOST_CCREG,CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); + emit_call((int)cc_interrupt); + if(stubs[n][3]) emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); + if(stubs[n][6]==TAKEN) { + if(internal_branch(branch_regs[i].is32,ba[i])) + load_needed_regs(branch_regs[i].regmap,regs[(ba[i]-start)>>2].regmap_entry); + else if(itype[i]==RJUMP) { + if(get_reg(branch_regs[i].regmap,RTEMP)>=0) + emit_readword((int)&pcaddr,get_reg(branch_regs[i].regmap,RTEMP)); + else + emit_loadreg(rs1[i],get_reg(branch_regs[i].regmap,rs1[i])); + } + }else if(stubs[n][6]==NOTTAKEN) { + if(iregmap; + #endif + if(i==(ba[i]-start)>>2) assem_debug("idle loop"); + address_generation(i+1,i_regs,regs[i].regmap_entry); + #ifdef REG_PREFETCH + int temp=get_reg(branch_regs[i].regmap,PTEMP); + if(rt1[i]==31&&temp>=0) + { + int return_address=start+i*4+8; + if(get_reg(branch_regs[i].regmap,31)>0) + if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + #endif + ds_assemble(i+1,i_regs); + uint64_t bc_unneeded=branch_regs[i].u; + uint64_t bc_unneeded_upper=branch_regs[i].uu; + bc_unneeded|=1|(1LL<=0); + return_address=start+i*4+8; + if(rt>=0) { + #ifdef USE_MINI_HT + if(internal_branch(branch_regs[i].is32,return_address)) { + int temp=rt+1; + if(temp==EXCLUDE_REG||temp>=HOST_REGS|| + branch_regs[i].regmap[temp]>=0) + { + temp=get_reg(branch_regs[i].regmap,-1); + } + #ifdef HOST_TEMPREG + if(temp<0) temp=HOST_TEMPREG; + #endif + if(temp>=0) do_miniht_insert(return_address,rt,temp); + else emit_movimm(return_address,rt); + } + else + #endif + { + #ifdef REG_PREFETCH + if(temp>=0) + { + if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + #endif + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif + } + } + } + int cc,adj; + cc=get_reg(branch_regs[i].regmap,CCREG); + assert(cc==HOST_CCREG); + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + #ifdef REG_PREFETCH + if(rt1[i]==31&&temp>=0) emit_prefetchreg(temp); + #endif + do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); + if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(internal_branch(branch_regs[i].is32,ba[i])) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(internal_branch(branch_regs[i].is32,ba[i])&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],internal_branch(branch_regs[i].is32,ba[i])); + emit_jmp(0); + } +} + +static void rjump_assemble(int i,struct regstat *i_regs) +{ + #ifdef REG_PREFETCH + signed char *i_regmap=i_regs->regmap; + #endif + int temp; + int rs,cc; + rs=get_reg(branch_regs[i].regmap,rs1[i]); + assert(rs>=0); + if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) { + // Delay slot abuse, make a copy of the branch address register + temp=get_reg(branch_regs[i].regmap,RTEMP); + assert(temp>=0); + assert(regs[i].regmap[temp]==RTEMP); + emit_mov(rs,temp); + rs=temp; + } + address_generation(i+1,i_regs,regs[i].regmap_entry); + #ifdef REG_PREFETCH + if(rt1[i]==31) + { + if((temp=get_reg(branch_regs[i].regmap,PTEMP))>=0) { + int return_address=start+i*4+8; + if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + } + #endif + #ifdef USE_MINI_HT + if(rs1[i]==31) { + int rh=get_reg(regs[i].regmap,RHASH); + if(rh>=0) do_preload_rhash(rh); + } + #endif + ds_assemble(i+1,i_regs); + uint64_t bc_unneeded=branch_regs[i].u; + uint64_t bc_unneeded_upper=branch_regs[i].uu; + bc_unneeded|=1|(1LL<=0); + return_address=start+i*4+8; + #ifdef REG_PREFETCH + if(temp>=0) + { + if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + #endif + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif + } + cc=get_reg(branch_regs[i].regmap,CCREG); + assert(cc==HOST_CCREG); + #ifdef USE_MINI_HT + int rh=get_reg(branch_regs[i].regmap,RHASH); + int ht=get_reg(branch_regs[i].regmap,RHTBL); + if(rs1[i]==31) { + if(regs[i].regmap[rh]!=RHASH) do_preload_rhash(rh); + do_preload_rhtbl(ht); + do_rhash(rs,rh); + } + #endif + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,-1); + #ifdef DESTRUCTIVE_WRITEBACK + if((branch_regs[i].dirty>>rs)&(branch_regs[i].is32>>rs1[i])&1) { + if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) { + emit_loadreg(rs1[i],rs); + } + } + #endif + #ifdef REG_PREFETCH + if(rt1[i]==31&&temp>=0) emit_prefetchreg(temp); + #endif + #ifdef USE_MINI_HT + if(rs1[i]==31) { + do_miniht_load(ht,rh); + } + #endif + //do_cc(i,branch_regs[i].regmap,&adj,-1,TAKEN); + //if(adj) emit_addimm(cc,2*(ccadj[i]+2-adj),cc); // ??? - Shouldn't happen + //assert(adj==0); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + add_stub(CC_STUB,(int)out,jump_vaddr_reg[rs],0,i,-1,TAKEN,0); + emit_jns(0); + //load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,-1); + #ifdef USE_MINI_HT + if(rs1[i]==31) { + do_miniht_jump(rs,rh,ht); + } + else + #endif + { + //if(rs!=EAX) emit_mov(rs,EAX); + //emit_jmp((int)jump_vaddr_eax); + emit_jmp(jump_vaddr_reg[rs]); + } + /* Check hash table + temp=!rs; + emit_mov(rs,temp); + emit_shrimm(rs,16,rs); + emit_xor(temp,rs,rs); + emit_movzwl_reg(rs,rs); + emit_shlimm(rs,4,rs); + emit_cmpmem_indexed((int)hash_table,rs,temp); + emit_jne((int)out+14); + emit_readword_indexed((int)hash_table+4,rs,rs); + emit_jmpreg(rs); + emit_cmpmem_indexed((int)hash_table+8,rs,temp); + emit_addimm_no_flags(8,rs); + emit_jeq((int)out-17); + // No hit on hash table, call compiler + emit_pushreg(temp); +//DEBUG > +#ifdef DEBUG_CYCLE_COUNT + emit_readword((int)&last_count,ECX); + emit_add(HOST_CCREG,ECX,HOST_CCREG); + emit_readword((int)&next_interupt,ECX); + emit_writeword(HOST_CCREG,(int)&g_cp0_regs[CP0_COUNT_REG]); + emit_sub(HOST_CCREG,ECX,HOST_CCREG); + emit_writeword(ECX,(int)&last_count); +#endif +//DEBUG < + emit_storereg(CCREG,HOST_CCREG); + emit_call((int)get_addr); + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm(ESP,4,ESP); + emit_jmpreg(EAX);*/ + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(rt1[i]!=31&&iregmap; + int cc; + int match; + match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + assem_debug("match=%d",match); + int s1h,s1l,s2h,s2l; + int prev_cop1_usable=cop1_usable; + int unconditional=0,nop=0; + int only32=0; + int invert=0; + int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); + if(i==(ba[i]-start)>>2) assem_debug("idle loop"); + if(!match) invert=1; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(i>(ba[i]-start)>>2) invert=1; + #endif + + if(ooo[i]) { + s1l=get_reg(branch_regs[i].regmap,rs1[i]); + s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); + s2l=get_reg(branch_regs[i].regmap,rs2[i]); + s2h=get_reg(branch_regs[i].regmap,rs2[i]|64); + } + else { + s1l=get_reg(i_regmap,rs1[i]); + s1h=get_reg(i_regmap,rs1[i]|64); + s2l=get_reg(i_regmap,rs2[i]); + s2h=get_reg(i_regmap,rs2[i]|64); + } + if(rs1[i]==0&&rs2[i]==0) + { + if(opcode[i]&1) nop=1; + else unconditional=1; + //assert(opcode[i]!=5); + //assert(opcode[i]!=7); + //assert(opcode[i]!=0x15); + //assert(opcode[i]!=0x17); + } + else if(rs1[i]==0) + { + s1l=s2l;s1h=s2h; + s2l=s2h=-1; + only32=(regs[i].was32>>rs2[i])&1; + } + else if(rs2[i]==0) + { + s2l=s2h=-1; + only32=(regs[i].was32>>rs1[i])&1; + } + else { + only32=(regs[i].was32>>rs1[i])&(regs[i].was32>>rs2[i])&1; + } + + if(ooo[i]) { + // Out of order execution (delay slot first) + //DebugMessage(M64MSG_VERBOSE, "OOOE"); + address_generation(i+1,i_regs,regs[i].regmap_entry); + ds_assemble(i+1,i_regs); + int adj; + uint64_t bc_unneeded=branch_regs[i].u; + uint64_t bc_unneeded_upper=branch_regs[i].uu; + bc_unneeded&=~((1LL<>2 || source[i+1]!=0) { + if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(branch_internal) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(branch_internal&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(((u_int)out)&7) emit_addnop(0); + #endif + } + } + else if(nop) { + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); + } + else { + int taken=0,nottaken=0,nottaken1=0; + do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); + if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(!only32) + { + assert(s1h>=0); + if(opcode[i]==4) // BEQ + { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + nottaken1=(int)out; + emit_jne(1); + } + if(opcode[i]==5) // BNE + { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + if(invert) taken=(int)out; + else add_to_linker((int)out,ba[i],branch_internal); + emit_jne(0); + } + if(opcode[i]==6) // BLEZ + { + emit_test(s1h,s1h); + if(invert) taken=(int)out; + else add_to_linker((int)out,ba[i],branch_internal); + emit_js(0); + nottaken1=(int)out; + emit_jne(1); + } + if(opcode[i]==7) // BGTZ + { + emit_test(s1h,s1h); + nottaken1=(int)out; + emit_js(1); + if(invert) taken=(int)out; + else add_to_linker((int)out,ba[i],branch_internal); + emit_jne(0); + } + } // if(!only32) + + //DebugMessage(M64MSG_VERBOSE, "branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); + assert(s1l>=0); + if(opcode[i]==4) // BEQ + { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + if(invert){ + nottaken=(int)out; + emit_jne(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jeq(0); + } + } + if(opcode[i]==5) // BNE + { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + if(invert){ + nottaken=(int)out; + emit_jeq(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jne(0); + } + } + if(opcode[i]==6) // BLEZ + { + emit_cmpimm(s1l,1); + if(invert){ + nottaken=(int)out; + if(only32) emit_jge(1); + else emit_jae(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + if(only32) emit_jl(0); + else emit_jb(0); + } + } + if(opcode[i]==7) // BGTZ + { + emit_cmpimm(s1l,1); + if(invert){ + nottaken=(int)out; + if(only32) emit_jl(1); + else emit_jb(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + if(only32) emit_jge(0); + else emit_jae(0); + } + } + if(invert) { + if(taken) set_jump_target(taken,(int)out); + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(match&&(!branch_internal||!is_ds[(ba[i]-start)>>2])) { + if(adj) { + emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + add_to_linker((int)out,ba[i],branch_internal); + }else{ + emit_addnop(13); + add_to_linker((int)out,ba[i],branch_internal*2); + } + emit_jmp(0); + }else + #endif + { + if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(branch_internal) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(branch_internal&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + } + set_jump_target(nottaken,(int)out); + } + + if(nottaken1) set_jump_target(nottaken1,(int)out); + if(adj) { + if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + } + } // (!unconditional) + } // if(ooo) + else + { + // In-order execution (branch first) + //if(likely[i]) DebugMessage(M64MSG_VERBOSE, "IOL"); + //else + //DebugMessage(M64MSG_VERBOSE, "IOE"); + int taken=0,nottaken=0,nottaken1=0; + if(!unconditional&&!nop) { + if(!only32) + { + assert(s1h>=0); + if((opcode[i]&0x2f)==4) // BEQ + { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + nottaken1=(int)out; + emit_jne(2); + } + if((opcode[i]&0x2f)==5) // BNE + { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + taken=(int)out; + emit_jne(1); + } + if((opcode[i]&0x2f)==6) // BLEZ + { + emit_test(s1h,s1h); + taken=(int)out; + emit_js(1); + nottaken1=(int)out; + emit_jne(2); + } + if((opcode[i]&0x2f)==7) // BGTZ + { + emit_test(s1h,s1h); + nottaken1=(int)out; + emit_js(2); + taken=(int)out; + emit_jne(1); + } + } // if(!only32) + + //DebugMessage(M64MSG_VERBOSE, "branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); + assert(s1l>=0); + if((opcode[i]&0x2f)==4) // BEQ + { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + nottaken=(int)out; + emit_jne(2); + } + if((opcode[i]&0x2f)==5) // BNE + { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + nottaken=(int)out; + emit_jeq(2); + } + if((opcode[i]&0x2f)==6) // BLEZ + { + emit_cmpimm(s1l,1); + nottaken=(int)out; + if(only32) emit_jge(2); + else emit_jae(2); + } + if((opcode[i]&0x2f)==7) // BGTZ + { + emit_cmpimm(s1l,1); + nottaken=(int)out; + if(only32) emit_jl(2); + else emit_jb(2); + } + } // if(!unconditional) + int adj; + uint64_t ds_unneeded=branch_regs[i].u; + uint64_t ds_unneeded_upper=branch_regs[i].uu; + ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + } + // branch not taken + cop1_usable=prev_cop1_usable; + if(!unconditional) { + if(nottaken1) set_jump_target(nottaken1,(int)out); + set_jump_target(nottaken,(int)out); + assem_debug("2:"); + if(!likely[i]) { + wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, + ds_unneeded,ds_unneeded_upper); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); + address_generation(i+1,&branch_regs[i],0); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); + ds_assemble(i+1,&branch_regs[i]); + } + cc=get_reg(branch_regs[i].regmap,CCREG); + if(cc==-1&&!likely[i]) { + // Cycle count isn't in a register, temporarily load it then write it out + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); + emit_storereg(CCREG,HOST_CCREG); + } + else{ + cc=get_reg(i_regmap,CCREG); + assert(cc==HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); + } + } + } +} + +static void sjump_assemble(int i,struct regstat *i_regs) +{ + signed char *i_regmap=i_regs->regmap; + int cc; + int match; + match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + assem_debug("smatch=%d",match); + int s1h,s1l; + int prev_cop1_usable=cop1_usable; + int unconditional=0,nevertaken=0; + int only32=0; + int invert=0; + int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); + if(i==(ba[i]-start)>>2) assem_debug("idle loop"); + if(!match) invert=1; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(i>(ba[i]-start)>>2) invert=1; + #endif + + //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL) + assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL) + + if(ooo[i]) { + s1l=get_reg(branch_regs[i].regmap,rs1[i]); + s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); + } + else { + s1l=get_reg(i_regmap,rs1[i]); + s1h=get_reg(i_regmap,rs1[i]|64); + } + if(rs1[i]==0) + { + if(opcode2[i]&1) unconditional=1; + else nevertaken=1; + // These are never taken (r0 is never less than zero) + //assert(opcode2[i]!=0); + //assert(opcode2[i]!=2); + //assert(opcode2[i]!=0x10); + //assert(opcode2[i]!=0x12); + } + else { + only32=(regs[i].was32>>rs1[i])&1; + } + + if(ooo[i]) { + // Out of order execution (delay slot first) + //DebugMessage(M64MSG_VERBOSE, "OOOE"); + address_generation(i+1,i_regs,regs[i].regmap_entry); + ds_assemble(i+1,i_regs); + int adj; + uint64_t bc_unneeded=branch_regs[i].u; + uint64_t bc_unneeded_upper=branch_regs[i].uu; + bc_unneeded&=~((1LL<=0) { + // Save the PC even if the branch is not taken + return_address=start+i*4+8; + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + if(!nevertaken) emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif + } + } + cc=get_reg(branch_regs[i].regmap,CCREG); + assert(cc==HOST_CCREG); + if(unconditional) + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + //do_cc(i,branch_regs[i].regmap,&adj,unconditional?ba[i]:-1,unconditional); + assem_debug("cycle count (adj)"); + if(unconditional) { + do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); + if(i!=(ba[i]-start)>>2 || source[i+1]!=0) { + if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(branch_internal) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(branch_internal&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(((u_int)out)&7) emit_addnop(0); + #endif + } + } + else if(nevertaken) { + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); + } + else { + int nottaken=0; + do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); + if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(!only32) + { + assert(s1h>=0); + if(opcode2[i]==0) // BLTZ + { + emit_test(s1h,s1h); + if(invert){ + nottaken=(int)out; + emit_jns(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_js(0); + } + } + if(opcode2[i]==1) // BGEZ + { + emit_test(s1h,s1h); + if(invert){ + nottaken=(int)out; + emit_js(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jns(0); + } + } + } // if(!only32) + else + { + assert(s1l>=0); + if(opcode2[i]==0) // BLTZ + { + emit_test(s1l,s1l); + if(invert){ + nottaken=(int)out; + emit_jns(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_js(0); + } + } + if(opcode2[i]==1) // BGEZ + { + emit_test(s1l,s1l); + if(invert){ + nottaken=(int)out; + emit_js(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jns(0); + } + } + } // if(!only32) + + if(invert) { + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(match&&(!branch_internal||!is_ds[(ba[i]-start)>>2])) { + if(adj) { + emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + add_to_linker((int)out,ba[i],branch_internal); + }else{ + emit_addnop(13); + add_to_linker((int)out,ba[i],branch_internal*2); + } + emit_jmp(0); + }else + #endif + { + if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(branch_internal) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(branch_internal&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + } + set_jump_target(nottaken,(int)out); + } + + if(adj) { + if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + } + } // (!unconditional) + } // if(ooo) + else + { + // In-order execution (branch first) + //DebugMessage(M64MSG_VERBOSE, "IOE"); + int nottaken=0; + if(!unconditional) { + //DebugMessage(M64MSG_VERBOSE, "branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); + if(!only32) + { + assert(s1h>=0); + if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL + { + emit_test(s1h,s1h); + nottaken=(int)out; + emit_jns(1); + } + if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL + { + emit_test(s1h,s1h); + nottaken=(int)out; + emit_js(1); + } + } // if(!only32) + else + { + assert(s1l>=0); + if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL + { + emit_test(s1l,s1l); + nottaken=(int)out; + emit_jns(1); + } + if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL + { + emit_test(s1l,s1l); + nottaken=(int)out; + emit_js(1); + } + } + } // if(!unconditional) + int adj; + uint64_t ds_unneeded=branch_regs[i].u; + uint64_t ds_unneeded_upper=branch_regs[i].uu; + ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + } + // branch not taken + cop1_usable=prev_cop1_usable; + if(!unconditional) { + set_jump_target(nottaken,(int)out); + assem_debug("1:"); + if(!likely[i]) { + wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, + ds_unneeded,ds_unneeded_upper); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); + address_generation(i+1,&branch_regs[i],0); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); + ds_assemble(i+1,&branch_regs[i]); + } + cc=get_reg(branch_regs[i].regmap,CCREG); + if(cc==-1&&!likely[i]) { + // Cycle count isn't in a register, temporarily load it then write it out + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); + emit_storereg(CCREG,HOST_CCREG); + } + else{ + cc=get_reg(i_regmap,CCREG); + assert(cc==HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); + } + } + } +} + +static void fjump_assemble(int i,struct regstat *i_regs) +{ + signed char *i_regmap=i_regs->regmap; + int cc; + int match; + match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + assem_debug("fmatch=%d",match); + int fs,cs; + int eaddr; + int invert=0; + int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); + if(i==(ba[i]-start)>>2) assem_debug("idle loop"); + if(!match) invert=1; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + if(i>(ba[i]-start)>>2) invert=1; + #endif + + if(ooo[i]) { + fs=get_reg(branch_regs[i].regmap,FSREG); + address_generation(i+1,i_regs,regs[i].regmap_entry); // Is this okay? + } + else { + fs=get_reg(i_regmap,FSREG); + } + + // Check cop1 unusable + if(!cop1_usable) { + cs=get_reg(i_regmap,CSREG); + assert(cs>=0); + emit_testimm(cs,0x20000000); + eaddr=(int)out; + emit_jeq(0); + add_stub(FP_STUB,eaddr,(int)out,i,cs,(int)i_regs,0,0); + cop1_usable=1; + } + + if(ooo[i]) { + // Out of order execution (delay slot first) + //DebugMessage(M64MSG_VERBOSE, "OOOE"); + ds_assemble(i+1,i_regs); + int adj; + uint64_t bc_unneeded=branch_regs[i].u; + uint64_t bc_unneeded_upper=branch_regs[i].uu; + bc_unneeded&=~((1LL<=0); + emit_testimm(fs,0x800000); + if(source[i]&0x10000) // BC1T + { + if(invert){ + nottaken=(int)out; + emit_jeq(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jne(0); + } + } + else // BC1F + if(invert){ + nottaken=(int)out; + emit_jne(1); + }else{ + add_to_linker((int)out,ba[i],branch_internal); + emit_jeq(0); + } + { + } + } // if(!only32) + + if(invert) { + if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + else if(match) emit_addnop(13); + #endif + store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); + if(branch_internal) + assem_debug("branch: internal"); + else + assem_debug("branch: external"); + if(branch_internal&&is_ds[(ba[i]-start)>>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + set_jump_target(nottaken,(int)out); + } + + if(adj) { + if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + } + } // (!unconditional) + } // if(ooo) + else + { + // In-order execution (branch first) + //DebugMessage(M64MSG_VERBOSE, "IOE"); + int nottaken=0; + if(1) { + //DebugMessage(M64MSG_VERBOSE, "branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); + if(1) { + assert(fs>=0); + emit_testimm(fs,0x800000); + if(source[i]&0x10000) // BC1T + { + nottaken=(int)out; + emit_jeq(1); + } + else // BC1F + { + nottaken=(int)out; + emit_jne(1); + } + } + } // if(!unconditional) + int adj; + uint64_t ds_unneeded=branch_regs[i].u; + uint64_t ds_unneeded_upper=branch_regs[i].uu; + ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2]) { + ds_assemble_entry(i); + } + else { + add_to_linker((int)out,ba[i],branch_internal); + emit_jmp(0); + } + + // branch not taken + if(1) { // <- FIXME (don't need this) + set_jump_target(nottaken,(int)out); + assem_debug("1:"); + if(!likely[i]) { + wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, + ds_unneeded,ds_unneeded_upper); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); + address_generation(i+1,&branch_regs[i],0); + load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); + ds_assemble(i+1,&branch_regs[i]); + } + cc=get_reg(branch_regs[i].regmap,CCREG); + if(cc==-1&&!likely[i]) { + // Cycle count isn't in a register, temporarily load it then write it out + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); + emit_storereg(CCREG,HOST_CCREG); + } + else{ + cc=get_reg(i_regmap,CCREG); + assert(cc==HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + int jaddr=(int)out; + emit_jns(0); + add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); + } + } + } +} + +static void pagespan_assemble(int i,struct regstat *i_regs) +{ + int s1l=get_reg(i_regs->regmap,rs1[i]); + int s1h=get_reg(i_regs->regmap,rs1[i]|64); + int s2l=get_reg(i_regs->regmap,rs2[i]); + int s2h=get_reg(i_regs->regmap,rs2[i]|64); + int taken=0; + int nottaken=0; + int unconditional=0; + if(rs1[i]==0) + { + s1l=s2l;s1h=s2h; + s2l=s2h=-1; + } + else if(rs2[i]==0) + { + s2l=s2h=-1; + } + if((i_regs->is32>>rs1[i])&(i_regs->is32>>rs2[i])&1) { + s1h=s2h=-1; + } + int hr=0; + int addr,alt,ntaddr; + if(i_regs->regmap[HOST_BTREG]<0) {addr=HOST_BTREG;} + else { + while(hrregmap[hr]&63)!=rs1[i] && + (i_regs->regmap[hr]&63)!=rs2[i] ) + { + addr=hr++;break; + } + hr++; + } + } + while(hrregmap[hr]&63)!=rs1[i] && + (i_regs->regmap[hr]&63)!=rs2[i] ) + { + alt=hr++;break; + } + hr++; + } + if((opcode[i]&0x2E)==6) // BLEZ/BGTZ needs another register + { + while(hrregmap[hr]&63)!=rs1[i] && + (i_regs->regmap[hr]&63)!=rs2[i] ) + { + ntaddr=hr;break; + } + hr++; + } + } + assert(hrregmap,31); + emit_movimm(start+i*4+8,rt); + unconditional=1; + } + if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR + { + emit_mov(s1l,addr); + if(opcode2[i]==9) // JALR + { + int rt=get_reg(i_regs->regmap,rt1[i]); + emit_movimm(start+i*4+8,rt); + } + } + if((opcode[i]&0x3f)==4) // BEQ + { + if(rs1[i]==rs2[i]) + { + unconditional=1; + } + else + #ifdef HAVE_CMOV_IMM + if(s1h<0) { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmov2imm_e_ne_compact(ba[i],start+i*4+8,addr); + } + else + #endif + { + assert(s1l>=0); + emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmovne_reg(alt,addr); + } + } + if((opcode[i]&0x3f)==5) // BNE + { + #ifdef HAVE_CMOV_IMM + if(s1h<0) { + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmov2imm_e_ne_compact(start+i*4+8,ba[i],addr); + } + else + #endif + { + assert(s1l>=0); + emit_mov2imm_compact(start+i*4+8,addr,ba[i],alt); + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + emit_cmovne_reg(alt,addr); + } + } + if((opcode[i]&0x3f)==0x14) // BEQL + { + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + nottaken=(int)out; + emit_jne(0); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + if(nottaken) set_jump_target(nottaken,(int)out); + nottaken=(int)out; + emit_jne(0); + } + if((opcode[i]&0x3f)==0x15) // BNEL + { + if(s1h>=0) { + if(s2h>=0) emit_cmp(s1h,s2h); + else emit_test(s1h,s1h); + taken=(int)out; + emit_jne(0); + } + if(s2l>=0) emit_cmp(s1l,s2l); + else emit_test(s1l,s1l); + nottaken=(int)out; + emit_jeq(0); + if(taken) set_jump_target(taken,(int)out); + } + if((opcode[i]&0x3f)==6) // BLEZ + { + emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); + emit_cmpimm(s1l,1); + if(s1h>=0) emit_mov(addr,ntaddr); + emit_cmovl_reg(alt,addr); + if(s1h>=0) { + emit_test(s1h,s1h); + emit_cmovne_reg(ntaddr,addr); + emit_cmovs_reg(alt,addr); + } + } + if((opcode[i]&0x3f)==7) // BGTZ + { + emit_mov2imm_compact(ba[i],addr,start+i*4+8,ntaddr); + emit_cmpimm(s1l,1); + if(s1h>=0) emit_mov(addr,alt); + emit_cmovl_reg(ntaddr,addr); + if(s1h>=0) { + emit_test(s1h,s1h); + emit_cmovne_reg(alt,addr); + emit_cmovs_reg(ntaddr,addr); + } + } + if((opcode[i]&0x3f)==0x16) // BLEZL + { + assert((opcode[i]&0x3f)!=0x16); + } + if((opcode[i]&0x3f)==0x17) // BGTZL + { + assert((opcode[i]&0x3f)!=0x17); + } + assert(opcode[i]!=1); // BLTZ/BGEZ + + //FIXME: Check CSREG + if(opcode[i]==0x11 && opcode2[i]==0x08 ) { + if((source[i]&0x30000)==0) // BC1F + { + emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); + emit_testimm(s1l,0x800000); + emit_cmovne_reg(alt,addr); + } + if((source[i]&0x30000)==0x10000) // BC1T + { + emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); + emit_testimm(s1l,0x800000); + emit_cmovne_reg(alt,addr); + } + if((source[i]&0x30000)==0x20000) // BC1FL + { + emit_testimm(s1l,0x800000); + nottaken=(int)out; + emit_jne(0); + } + if((source[i]&0x30000)==0x30000) // BC1TL + { + emit_testimm(s1l,0x800000); + nottaken=(int)out; + emit_jeq(0); + } + } + + assert(i_regs->regmap[HOST_CCREG]==CCREG); + wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); + if(likely[i]||unconditional) + { + emit_movimm(ba[i],HOST_BTREG); + } + else if(addr!=HOST_BTREG) + { + emit_mov(addr,HOST_BTREG); + } + void *branch_addr=out; + emit_jmp(0); + int target_addr=start+i*4+5; + void *stub=out; + void *compiled_target_addr=check_addr(target_addr); + emit_extjump_ds((int)branch_addr,target_addr); + if(compiled_target_addr) { + set_jump_target((int)branch_addr,(int)compiled_target_addr); + add_link(target_addr,stub); + } + else set_jump_target((int)branch_addr,(int)stub); + if(likely[i]) { + // Not-taken path + set_jump_target((int)nottaken,(int)out); + wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); + void *branch_addr=out; + emit_jmp(0); + int target_addr=start+i*4+8; + void *stub=out; + void *compiled_target_addr=check_addr(target_addr); + emit_extjump_ds((int)branch_addr,target_addr); + if(compiled_target_addr) { + set_jump_target((int)branch_addr,(int)compiled_target_addr); + add_link(target_addr,stub); + } + else set_jump_target((int)branch_addr,(int)stub); + } +} + +// Assemble the delay slot for the above +static void pagespan_ds() +{ + assem_debug("initial delay slot:"); + u_int vaddr=start+1; + u_int page=(0x80000000^vaddr)>>12; + u_int vpage=page; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[page^0x80000]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + if(vpage>262143&&tlb_LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead + if(vpage>2048) vpage=2048+(vpage&2047); + ll_add(jump_dirty+vpage,vaddr,(void *)out); + do_dirty_stub_ds(); + ll_add(jump_in+page,vaddr,(void *)out); + assert(regs[0].regmap_entry[HOST_CCREG]==CCREG); + if(regs[0].regmap[HOST_CCREG]!=CCREG) + wb_register(CCREG,regs[0].regmap_entry,regs[0].wasdirty,regs[0].was32); + if(regs[0].regmap[HOST_BTREG]!=BTREG) + emit_writeword(HOST_BTREG,(int)&branch_target); + load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]); + address_generation(0,®s[0],regs[0].regmap_entry); + if(itype[0]==LOAD||itype[0]==LOADLR||itype[0]==STORE||itype[0]==STORELR||itype[0]==C1LS) + load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,MMREG,ROREG); + if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39) + load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP); + cop1_usable=0; + is_delayslot=0; + switch(itype[0]) { + case ALU: + alu_assemble(0,®s[0]);break; + case IMM16: + imm16_assemble(0,®s[0]);break; + case SHIFT: + shift_assemble(0,®s[0]);break; + case SHIFTIMM: + shiftimm_assemble(0,®s[0]);break; + case LOAD: + load_assemble(0,®s[0]);break; + case LOADLR: + loadlr_assemble(0,®s[0]);break; + case STORE: + store_assemble(0,®s[0]);break; + case STORELR: + storelr_assemble(0,®s[0]);break; + case COP0: + cop0_assemble(0,®s[0]);break; + case COP1: + cop1_assemble(0,®s[0]);break; + case C1LS: + c1ls_assemble(0,®s[0]);break; + case FCONV: + fconv_assemble(0,®s[0]);break; + case FLOAT: + float_assemble(0,®s[0]);break; + case FCOMP: + fcomp_assemble(0,®s[0]);break; + case MULTDIV: + multdiv_assemble(0,®s[0]);break; + case MOV: + mov_assemble(0,®s[0]);break; + case SYSCALL: + case SPAN: + case UJUMP: + case RJUMP: + case CJUMP: + case SJUMP: + case FJUMP: + DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); + } + int btaddr=get_reg(regs[0].regmap,BTREG); + if(btaddr<0) { + btaddr=get_reg(regs[0].regmap,-1); + emit_readword((int)&branch_target,btaddr); + } + assert(btaddr!=HOST_CCREG); + if(regs[0].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); +#ifdef HOST_IMM8 + emit_movimm(start+4,HOST_TEMPREG); + emit_cmp(btaddr,HOST_TEMPREG); +#else + emit_cmpimm(btaddr,start+4); +#endif + int branch=(int)out; + emit_jeq(0); + store_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,-1); + emit_jmp(jump_vaddr_reg[btaddr]); + set_jump_target(branch,(int)out); + store_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,start+4); + load_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,start+4); +} + +// Basic liveness analysis for MIPS registers +static void unneeded_registers(int istart,int iend,int r) +{ + int i; + uint64_t u,uu,b,bu; + uint64_t temp_u,temp_uu; + uint64_t tdep; + if(iend==slen-1) { + u=1;uu=1; + }else{ + u=unneeded_reg[iend+1]; + uu=unneeded_reg_upper[iend+1]; + u=1;uu=1; + } + for (i=iend;i>=istart;i--) + { + //DebugMessage(M64MSG_VERBOSE, "unneeded registers i=%d (%d,%d) r=%d",i,istart,iend,r); + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + // If subroutine call, flag return address as a possible branch target + if(rt1[i]==31 && i=(start+slen*4)) + { + // Branch out of this block, flush all regs + u=1; + uu=1; + /* Hexagon hack + if(itype[i]==UJUMP&&rt1[i]==31) + { + uu=u=0x300C00F; // Discard at, v0-v1, t6-t9 + } + if(itype[i]==RJUMP&&rs1[i]==31) + { + uu=u=0x300C0F3; // Discard at, a0-a3, t6-t9 + } + if(start>0x80000400&&start<0x80800000) { + if(itype[i]==UJUMP&&rt1[i]==31) + { + //uu=u=0x30300FF0FLL; // Discard at, v0-v1, t0-t9, lo, hi + uu=u=0x300FF0F; // Discard at, v0-v1, t0-t9 + } + if(itype[i]==RJUMP&&rs1[i]==31) + { + //uu=u=0x30300FFF3LL; // Discard at, a0-a3, t0-t9, lo, hi + uu=u=0x300FFF3; // Discard at, a0-a3, t0-t9 + } + }*/ + branch_unneeded_reg[i]=u; + branch_unneeded_reg_upper[i]=uu; + // Merge in delay slot + tdep=(~uu>>rt1[i+1])&1; + u|=(1LL<>2]=1; + if(ba[i]<=start+i*4) { + // Backward branch + if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) + { + // Unconditional branch + temp_u=1;temp_uu=1; + } else { + // Conditional branch (not taken case) + temp_u=unneeded_reg[i+2]; + temp_uu=unneeded_reg_upper[i+2]; + } + // Merge in delay slot + tdep=(~temp_uu>>rt1[i+1])&1; + temp_u|=(1LL<>rt1[i])&1; + temp_u|=(1LL<>2,i-1,r+1); + }else{ + unneeded_reg[(ba[i]-start)>>2]=1; + unneeded_reg_upper[(ba[i]-start)>>2]=1; + } + } /*else*/ if(1) { + if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) + { + // Unconditional branch + u=unneeded_reg[(ba[i]-start)>>2]; + uu=unneeded_reg_upper[(ba[i]-start)>>2]; + branch_unneeded_reg[i]=u; + branch_unneeded_reg_upper[i]=uu; + //u=1; + //uu=1; + //branch_unneeded_reg[i]=u; + //branch_unneeded_reg_upper[i]=uu; + // Merge in delay slot + tdep=(~uu>>rt1[i+1])&1; + u|=(1LL<>2]; + bu=unneeded_reg_upper[(ba[i]-start)>>2]; + branch_unneeded_reg[i]=b; + branch_unneeded_reg_upper[i]=bu; + //b=1; + //bu=1; + //branch_unneeded_reg[i]=b; + //branch_unneeded_reg_upper[i]=bu; + // Branch delay slot + tdep=(~uu>>rt1[i+1])&1; + b|=(1LL<>rt1[i])&1; + // Written registers are unneeded + u|=1LL<>r)&1) { + if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + DebugMessage(M64MSG_VERBOSE, " UU:"); + for(r=1;r<=CCREG;r++) { + if(((unneeded_reg_upper[i]&~unneeded_reg[i])>>r)&1) { + if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + }*/ + } +} + +// Identify registers which are likely to contain 32-bit values +// This is used to predict whether any branches will jump to a +// location with 64-bit values in registers. +static void provisional_32bit() +{ + int i,j; + uint64_t is32=1; + uint64_t lastbranch=1; + + for(i=0;i0) { + if(itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP) { + if(i>1) is32=lastbranch; + else is32=1; + } + } + if(i>1) + { + if(itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP) { + if(likely[i-2]) { + if(i>2) is32=lastbranch; + else is32=1; + } + } + if((opcode[i-2]&0x2f)==0x05) // BNE/BNEL + { + if(rs1[i-2]==0||rs2[i-2]==0) + { + if(rs1[i-2]) { + is32|=1LL<=0;j--) + { + if(ba[j]==start+i*4) + //temp_is32&=branch_regs[j].is32; + temp_is32&=p32[j]; + } + for(j=i;j>s1)&1LL)<>s1)&1LL); + is32&=~(1LL<=0x20&&op2<=0x23) { // ADD/ADDU/SUB/SUBU + is32|=1LL<=0x24&&op2<=0x27) { // AND/OR/XOR/NOR + uint64_t sr=((is32>>s1)&(is32>>s2)&1LL); + is32&=~(1LL<=0x2c&&op2<=0x2d) { // DADD/DADDU + if(s1==0&&s2==0) { + is32|=1LL<>s1)&1LL); + is32&=~(1LL<>s2)&1LL); + is32&=~(1LL<=0x2e&&op2<=0x2f) { // DSUB/DSUBU + if(s1==0&&s2==0) { + is32|=1LL<>s1)&1LL); + is32&=~(1LL<=0x1c&&op2<=0x1f) { // DMULT/DMULTU/DDIV/DDIVU + is32&=~((1LL<>s1)&1LL); + is32&=~(1LL<=0x14&&op2<=0x17) is32&=~(1LL<=0x38&&op2<0x3f) is32&=~(1LL<0) + { + if(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000) + { + if(rt1[i-1]==31) // JAL/JALR + { + // Subroutine call will return here, don't alloc any registers + is32=1; + } + else if(i+1=0;i--) + { + int hr; + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + if(ba[i]=(start+slen*4)) + { + // Branch out of this block, don't need anything + r32=0; + } + else + { + // Internal branch + // Need whatever matches the target + // (and doesn't get overwritten by the delay slot instruction) + r32=0; + int t=(ba[i]-start)>>2; + if(ba[i]>start+i*4) { + // Forward branch + //if(!(requires_32bit[t]&~regs[i].was32)) + // r32|=requires_32bit[t]&(~(1LL<>16)!=0x1000) + { + if(i0) + { + if((regs[i].was32>>us1[i+1])&1) r32|=1LL<0) + { + if((regs[i].was32>>us2[i+1])&1) r32|=1LL<>dep1[i+1])&1)) + { + if((regs[i].was32>>dep1[i+1])&1) r32|=1LL<>dep2[i+1])&1)) + { + if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<0) + { + if((regs[i].was32>>us1[i])&1) r32|=1LL<0) + { + if((regs[i].was32>>us2[i])&1) r32|=1LL<>dep1[i])&1)) + { + if((regs[i].was32>>dep1[i])&1) r32|=1LL<>dep2[i])&1)) + { + if((regs[i].was32>>dep2[i])&1) r32|=1LL<0&®s[i].regmap_entry[hr]<64) { + if((regs[i].was32>>regs[i].regmap_entry[hr])&(regs[i].wasdirty>>hr)&1) { + if(!((unneeded_reg_upper[i]>>regs[i].regmap_entry[hr])&1)) + pr32[i]|=1LL<=istart;i--) + { + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + if(ba[i]=(start+slen*4)) + { + // Branch out of this block, flush all regs + if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) + { + // Unconditional branch + will_dirty_i=0; + wont_dirty_i=0; + // Merge in delay slot (will dirty) + for(r=0;r33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<>16)==0x1000) + { + // Unconditional branch + temp_will_dirty=0; + temp_wont_dirty=0; + // Merge in delay slot (will dirty) + for(r=0;r33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<0 && (regmap_pre[i][r]&63)<34) { + temp_will_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>2,i-1,0); + }else{ + // Limit recursion. It can take an excessive amount + // of time if there are a lot of nested loops. + will_dirty[(ba[i]-start)>>2]=0; + wont_dirty[(ba[i]-start)>>2]=-1; + } + } + /*else*/ if(1) + { + if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) + { + // Unconditional branch + will_dirty_i=0; + wont_dirty_i=0; + //if(ba[i]>start+i*4) { // Disable recursion (for debugging) + for(r=0;r>2].regmap_entry[r]) { + will_dirty_i|=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<=0) { + will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<>2]>>(branch_regs[i].regmap[r]&63))&1)<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<start+i*4) { // Disable recursion (for debugging) + for(r=0;r>2].regmap_entry[r]) { + will_dirty_i&=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<=0) { + will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<>2]>>(target_reg&63))&1)<>2].regmap_entry[r]) { + will_dirty[i+1]&=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<istart) { + if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=FJUMP) + { + // Don't store a register immediately after writing it, + // may prevent dual-issue. + if((regs[i].regmap[r]&63)==rt1[i-1]) wont_dirty_i|=1<>r)&1) { + DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + }*/ + + //if(i==istart||(itype[i-1]!=RJUMP&&itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=FJUMP)) { + regs[i].dirty|=will_dirty_i; + #ifndef DESTRUCTIVE_WRITEBACK + regs[i].dirty&=wont_dirty_i; + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + if(i>16)!=0x1000) { + for(r=0;r>r)&1));*/} + } + } + } + } + else + { + if(i>r)&1));*/} + } + } + } + } + #endif + //} + } + // Deal with changed mappings + temp_will_dirty=will_dirty_i; + temp_wont_dirty=wont_dirty_i; + for(r=0;r=0) { + // Register moved to a different register + will_dirty_i&=~(1<>nr)&1)<>nr)&1)<0 && (regmap_pre[i][r]&63)<34) { + will_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>r)&1));*/ + } + } + } + } + } +} + +#ifdef ASSEM_DEBUG + /* disassembly */ +static void disassemble_inst(int i) +{ + if (bt[i]) DebugMessage(M64MSG_VERBOSE, "*"); else DebugMessage(M64MSG_VERBOSE, " "); + switch(itype[i]) { + case UJUMP: + printf (" %x: %s %8x",start+i*4,insn[i],ba[i]);break; + case CJUMP: + printf (" %x: %s r%d,r%d,%8x",start+i*4,insn[i],rs1[i],rs2[i],i?start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14):*ba);break; + case SJUMP: + printf (" %x: %s r%d,%8x",start+i*4,insn[i],rs1[i],start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14));break; + case FJUMP: + printf (" %x: %s %8x",start+i*4,insn[i],ba[i]);break; + case RJUMP: + if ((opcode2[i]&1)&&rt1[i]!=31) + printf (" %x: %s r%d,r%d",start+i*4,insn[i],rt1[i],rs1[i]); + else + printf (" %x: %s r%d",start+i*4,insn[i],rs1[i]); + break; + case SPAN: + printf (" %x: %s (pagespan) r%d,r%d,%8x",start+i*4,insn[i],rs1[i],rs2[i],ba[i]);break; + case IMM16: + if(opcode[i]==0xf) //LUI + printf (" %x: %s r%d,%4x0000",start+i*4,insn[i],rt1[i],imm[i]&0xffff); + else + printf (" %x: %s r%d,r%d,%d",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); + break; + case LOAD: + case LOADLR: + printf (" %x: %s r%d,r%d+%x",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); + break; + case STORE: + case STORELR: + printf (" %x: %s r%d,r%d+%x",start+i*4,insn[i],rs2[i],rs1[i],imm[i]); + break; + case ALU: + case SHIFT: + printf (" %x: %s r%d,r%d,r%d",start+i*4,insn[i],rt1[i],rs1[i],rs2[i]); + break; + case MULTDIV: + printf (" %x: %s r%d,r%d",start+i*4,insn[i],rs1[i],rs2[i]); + break; + case SHIFTIMM: + printf (" %x: %s r%d,r%d,%d",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); + break; + case MOV: + if((opcode2[i]&0x1d)==0x10) + printf (" %x: %s r%d",start+i*4,insn[i],rt1[i]); + else if((opcode2[i]&0x1d)==0x11) + printf (" %x: %s r%d",start+i*4,insn[i],rs1[i]); + else + printf (" %x: %s",start+i*4,insn[i]); + break; + case COP0: + if(opcode2[i]==0) + printf (" %x: %s r%d,cpr0[%d]",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC0 + else if(opcode2[i]==4) + printf (" %x: %s r%d,cpr0[%d]",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC0 + else printf (" %x: %s",start+i*4,insn[i]); + break; + case COP1: + if(opcode2[i]<3) + printf (" %x: %s r%d,cpr1[%d]",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC1 + else if(opcode2[i]>3) + printf (" %x: %s r%d,cpr1[%d]",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC1 + else printf (" %x: %s",start+i*4,insn[i]); + break; + case C1LS: + printf (" %x: %s cpr1[%d],r%d+%x",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); + break; + default: + //printf (" %s %8x",insn[i],source[i]); + printf (" %x: %s",start+i*4,insn[i]); + } +} +#endif + +void new_dynarec_init() +{ + DebugMessage(M64MSG_INFO, "Init new dynarec"); + +#if NEW_DYNAREC == NEW_DYNAREC_ARM + if ((base_addr = mmap ((u_char *)BASE_ADDR, 1<>2; + for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF + memory_map[n]=-1; + for(n=0;n<0x8000;n++) { // 0 .. 0x7FFFFFFF + writemem[n] = write_nomem_new; + writememb[n] = write_nomemb_new; + writememh[n] = write_nomemh_new; + writememd[n] = write_nomemd_new; + readmem[n] = read_nomem_new; + readmemb[n] = read_nomemb_new; + readmemh[n] = read_nomemh_new; + readmemd[n] = read_nomemd_new; + } + for(n=0x8000;n<0x8080;n++) { // 0x80000000 .. 0x807FFFFF + writemem[n] = write_rdram_new; + writememb[n] = write_rdramb_new; + writememh[n] = write_rdramh_new; + writememd[n] = write_rdramd_new; + } + for(n=0xC000;n<0x10000;n++) { // 0xC0000000 .. 0xFFFFFFFF + writemem[n] = write_nomem_new; + writememb[n] = write_nomemb_new; + writememh[n] = write_nomemh_new; + writememd[n] = write_nomemd_new; + readmem[n] = read_nomem_new; + readmemb[n] = read_nomemb_new; + readmemh[n] = read_nomemh_new; + readmemd[n] = read_nomemd_new; + } + tlb_hacks(); + arch_init(); +} + +void new_dynarec_cleanup() +{ + int n; +#if defined(_MSC_VER) + VirtualFree(base_addr, 0, MEM_RELEASE); +#else + if (munmap (base_addr, 1< %x", (int)addr, (int)out); +#if defined (COUNT_NOTCOMPILEDS ) + notcompiledCount++; + log_message( "notcompiledCount=%i", notcompiledCount ); +#endif + //DebugMessage(M64MSG_VERBOSE, "NOTCOMPILED: addr = %x -> %x", (int)addr, (int)out); + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (compile %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,addr); + //if(debug) + //DebugMessage(M64MSG_VERBOSE, "TRACE: count=%d next=%d (checksum %x)",g_cp0_regs[CP0_COUNT_REG],next_interupt,mchecksum()); + //DebugMessage(M64MSG_VERBOSE, "fpu mapping=%x enabled=%x",(g_cp0_regs[CP0_STATUS_REG] & 0x04000000)>>26,(g_cp0_regs[CP0_STATUS_REG] & 0x20000000)>>29); + /*if(g_cp0_regs[CP0_COUNT_REG]>=312978186) { + rlist(); + }*/ + //rlist(); + start = (u_int)addr&~3; + //assert(((u_int)addr&1)==0); + if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) { + source = (u_int *)((u_int)g_sp.mem+start-0xa4000000); + pagelimit = 0xa4001000; + } + else if ((int)addr >= 0x80000000 && (int)addr < 0x80800000) { + source = (u_int *)((u_int)g_rdram+start-0x80000000); + pagelimit = 0x80800000; + } + else if ((signed int)addr >= (signed int)0xC0000000) { + //DebugMessage(M64MSG_VERBOSE, "addr=%x mm=%x",(u_int)addr,(memory_map[start>>12]<<2)); + //if(tlb_LUT_r[start>>12]) + //source = (u_int *)(((int)g_rdram)+(tlb_LUT_r[start>>12]&0xFFFFF000)+(((int)addr)&0xFFF)-0x80000000); + if((signed int)memory_map[start>>12]>=0) { + source = (u_int *)((u_int)(start+(memory_map[start>>12]<<2))); + pagelimit=(start+4096)&0xFFFFF000; + int map=memory_map[start>>12]; + int i; + for(i=0;i<5;i++) { + //DebugMessage(M64MSG_VERBOSE, "start: %x next: %x",map,memory_map[pagelimit>>12]); + if((map&0xBFFFFFFF)==(memory_map[pagelimit>>12]&0xBFFFFFFF)) pagelimit+=4096; + } + assem_debug("pagelimit=%x",pagelimit); + assem_debug("mapping=%x (%x)",memory_map[start>>12],(memory_map[start>>12]<<2)+start); + } + else { + assem_debug("Compile at unmapped memory address: %x ", (int)addr); + //assem_debug("start: %x next: %x",memory_map[start>>12],memory_map[(start+4096)>>12]); + return 1; // Caller will invoke exception handler + } + //DebugMessage(M64MSG_VERBOSE, "source= %x",(int)source); + } + else { + //DebugMessage(M64MSG_VERBOSE, "Compile at bogus memory address: %x ", (int)addr); + log_message("Compile at bogus memory address: %x", (int)addr); + exit(1); + } + + /* Pass 1: disassemble */ + /* Pass 2: register dependencies, branch targets */ + /* Pass 3: register allocation */ + /* Pass 4: branch dependencies */ + /* Pass 5: pre-alloc */ + /* Pass 6: optimize clean/dirty state */ + /* Pass 7: flag 32-bit registers */ + /* Pass 8: assembly */ + /* Pass 9: linker */ + /* Pass 10: garbage collection / free memory */ + + int i,j; + int done=0; + unsigned int type,op,op2; + + //DebugMessage(M64MSG_VERBOSE, "addr = %x source = %x %x", addr,source,source[0]); + + /* Pass 1 disassembly */ + + for(i=0;!done;i++) { + bt[i]=0;likely[i]=0;ooo[i]=0;op2=0; + minimum_free_regs[i]=0; + opcode[i]=op=source[i]>>26; + switch(op) + { + case 0x00: strcpy(insn[i],"special"); type=NI; + op2=source[i]&0x3f; + switch(op2) + { + case 0x00: strcpy(insn[i],"SLL"); type=SHIFTIMM; break; + case 0x02: strcpy(insn[i],"SRL"); type=SHIFTIMM; break; + case 0x03: strcpy(insn[i],"SRA"); type=SHIFTIMM; break; + case 0x04: strcpy(insn[i],"SLLV"); type=SHIFT; break; + case 0x06: strcpy(insn[i],"SRLV"); type=SHIFT; break; + case 0x07: strcpy(insn[i],"SRAV"); type=SHIFT; break; + case 0x08: strcpy(insn[i],"JR"); type=RJUMP; break; + case 0x09: strcpy(insn[i],"JALR"); type=RJUMP; break; + case 0x0C: strcpy(insn[i],"SYSCALL"); type=SYSCALL; break; + case 0x0D: strcpy(insn[i],"BREAK"); type=OTHER; break; + case 0x0F: strcpy(insn[i],"SYNC"); type=OTHER; break; + case 0x10: strcpy(insn[i],"MFHI"); type=MOV; break; + case 0x11: strcpy(insn[i],"MTHI"); type=MOV; break; + case 0x12: strcpy(insn[i],"MFLO"); type=MOV; break; + case 0x13: strcpy(insn[i],"MTLO"); type=MOV; break; + case 0x14: strcpy(insn[i],"DSLLV"); type=SHIFT; break; + case 0x16: strcpy(insn[i],"DSRLV"); type=SHIFT; break; + case 0x17: strcpy(insn[i],"DSRAV"); type=SHIFT; break; + case 0x18: strcpy(insn[i],"MULT"); type=MULTDIV; break; + case 0x19: strcpy(insn[i],"MULTU"); type=MULTDIV; break; + case 0x1A: strcpy(insn[i],"DIV"); type=MULTDIV; break; + case 0x1B: strcpy(insn[i],"DIVU"); type=MULTDIV; break; + case 0x1C: strcpy(insn[i],"DMULT"); type=MULTDIV; break; + case 0x1D: strcpy(insn[i],"DMULTU"); type=MULTDIV; break; + case 0x1E: strcpy(insn[i],"DDIV"); type=MULTDIV; break; + case 0x1F: strcpy(insn[i],"DDIVU"); type=MULTDIV; break; + case 0x20: strcpy(insn[i],"ADD"); type=ALU; break; + case 0x21: strcpy(insn[i],"ADDU"); type=ALU; break; + case 0x22: strcpy(insn[i],"SUB"); type=ALU; break; + case 0x23: strcpy(insn[i],"SUBU"); type=ALU; break; + case 0x24: strcpy(insn[i],"AND"); type=ALU; break; + case 0x25: strcpy(insn[i],"OR"); type=ALU; break; + case 0x26: strcpy(insn[i],"XOR"); type=ALU; break; + case 0x27: strcpy(insn[i],"NOR"); type=ALU; break; + case 0x2A: strcpy(insn[i],"SLT"); type=ALU; break; + case 0x2B: strcpy(insn[i],"SLTU"); type=ALU; break; + case 0x2C: strcpy(insn[i],"DADD"); type=ALU; break; + case 0x2D: strcpy(insn[i],"DADDU"); type=ALU; break; + case 0x2E: strcpy(insn[i],"DSUB"); type=ALU; break; + case 0x2F: strcpy(insn[i],"DSUBU"); type=ALU; break; + case 0x30: strcpy(insn[i],"TGE"); type=NI; break; + case 0x31: strcpy(insn[i],"TGEU"); type=NI; break; + case 0x32: strcpy(insn[i],"TLT"); type=NI; break; + case 0x33: strcpy(insn[i],"TLTU"); type=NI; break; + case 0x34: strcpy(insn[i],"TEQ"); type=NI; break; + case 0x36: strcpy(insn[i],"TNE"); type=NI; break; + case 0x38: strcpy(insn[i],"DSLL"); type=SHIFTIMM; break; + case 0x3A: strcpy(insn[i],"DSRL"); type=SHIFTIMM; break; + case 0x3B: strcpy(insn[i],"DSRA"); type=SHIFTIMM; break; + case 0x3C: strcpy(insn[i],"DSLL32"); type=SHIFTIMM; break; + case 0x3E: strcpy(insn[i],"DSRL32"); type=SHIFTIMM; break; + case 0x3F: strcpy(insn[i],"DSRA32"); type=SHIFTIMM; break; + } + break; + case 0x01: strcpy(insn[i],"regimm"); type=NI; + op2=(source[i]>>16)&0x1f; + switch(op2) + { + case 0x00: strcpy(insn[i],"BLTZ"); type=SJUMP; break; + case 0x01: strcpy(insn[i],"BGEZ"); type=SJUMP; break; + case 0x02: strcpy(insn[i],"BLTZL"); type=SJUMP; break; + case 0x03: strcpy(insn[i],"BGEZL"); type=SJUMP; break; + case 0x08: strcpy(insn[i],"TGEI"); type=NI; break; + case 0x09: strcpy(insn[i],"TGEIU"); type=NI; break; + case 0x0A: strcpy(insn[i],"TLTI"); type=NI; break; + case 0x0B: strcpy(insn[i],"TLTIU"); type=NI; break; + case 0x0C: strcpy(insn[i],"TEQI"); type=NI; break; + case 0x0E: strcpy(insn[i],"TNEI"); type=NI; break; + case 0x10: strcpy(insn[i],"BLTZAL"); type=SJUMP; break; + case 0x11: strcpy(insn[i],"BGEZAL"); type=SJUMP; break; + case 0x12: strcpy(insn[i],"BLTZALL"); type=SJUMP; break; + case 0x13: strcpy(insn[i],"BGEZALL"); type=SJUMP; break; + } + break; + case 0x02: strcpy(insn[i],"J"); type=UJUMP; break; + case 0x03: strcpy(insn[i],"JAL"); type=UJUMP; break; + case 0x04: strcpy(insn[i],"BEQ"); type=CJUMP; break; + case 0x05: strcpy(insn[i],"BNE"); type=CJUMP; break; + case 0x06: strcpy(insn[i],"BLEZ"); type=CJUMP; break; + case 0x07: strcpy(insn[i],"BGTZ"); type=CJUMP; break; + case 0x08: strcpy(insn[i],"ADDI"); type=IMM16; break; + case 0x09: strcpy(insn[i],"ADDIU"); type=IMM16; break; + case 0x0A: strcpy(insn[i],"SLTI"); type=IMM16; break; + case 0x0B: strcpy(insn[i],"SLTIU"); type=IMM16; break; + case 0x0C: strcpy(insn[i],"ANDI"); type=IMM16; break; + case 0x0D: strcpy(insn[i],"ORI"); type=IMM16; break; + case 0x0E: strcpy(insn[i],"XORI"); type=IMM16; break; + case 0x0F: strcpy(insn[i],"LUI"); type=IMM16; break; + case 0x10: strcpy(insn[i],"cop0"); type=NI; + op2=(source[i]>>21)&0x1f; + switch(op2) + { + case 0x00: strcpy(insn[i],"MFC0"); type=COP0; break; + case 0x04: strcpy(insn[i],"MTC0"); type=COP0; break; + case 0x10: strcpy(insn[i],"tlb"); type=NI; + switch(source[i]&0x3f) + { + case 0x01: strcpy(insn[i],"TLBR"); type=COP0; break; + case 0x02: strcpy(insn[i],"TLBWI"); type=COP0; break; + case 0x06: strcpy(insn[i],"TLBWR"); type=COP0; break; + case 0x08: strcpy(insn[i],"TLBP"); type=COP0; break; + case 0x18: strcpy(insn[i],"ERET"); type=COP0; break; + } + } + break; + case 0x11: strcpy(insn[i],"cop1"); type=NI; + op2=(source[i]>>21)&0x1f; + switch(op2) + { + case 0x00: strcpy(insn[i],"MFC1"); type=COP1; break; + case 0x01: strcpy(insn[i],"DMFC1"); type=COP1; break; + case 0x02: strcpy(insn[i],"CFC1"); type=COP1; break; + case 0x04: strcpy(insn[i],"MTC1"); type=COP1; break; + case 0x05: strcpy(insn[i],"DMTC1"); type=COP1; break; + case 0x06: strcpy(insn[i],"CTC1"); type=COP1; break; + case 0x08: strcpy(insn[i],"BC1"); type=FJUMP; + switch((source[i]>>16)&0x3) + { + case 0x00: strcpy(insn[i],"BC1F"); break; + case 0x01: strcpy(insn[i],"BC1T"); break; + case 0x02: strcpy(insn[i],"BC1FL"); break; + case 0x03: strcpy(insn[i],"BC1TL"); break; + } + break; + case 0x10: strcpy(insn[i],"C1.S"); type=NI; + switch(source[i]&0x3f) + { + case 0x00: strcpy(insn[i],"ADD.S"); type=FLOAT; break; + case 0x01: strcpy(insn[i],"SUB.S"); type=FLOAT; break; + case 0x02: strcpy(insn[i],"MUL.S"); type=FLOAT; break; + case 0x03: strcpy(insn[i],"DIV.S"); type=FLOAT; break; + case 0x04: strcpy(insn[i],"SQRT.S"); type=FLOAT; break; + case 0x05: strcpy(insn[i],"ABS.S"); type=FLOAT; break; + case 0x06: strcpy(insn[i],"MOV.S"); type=FLOAT; break; + case 0x07: strcpy(insn[i],"NEG.S"); type=FLOAT; break; + case 0x08: strcpy(insn[i],"ROUND.L.S"); type=FCONV; break; + case 0x09: strcpy(insn[i],"TRUNC.L.S"); type=FCONV; break; + case 0x0A: strcpy(insn[i],"CEIL.L.S"); type=FCONV; break; + case 0x0B: strcpy(insn[i],"FLOOR.L.S"); type=FCONV; break; + case 0x0C: strcpy(insn[i],"ROUND.W.S"); type=FCONV; break; + case 0x0D: strcpy(insn[i],"TRUNC.W.S"); type=FCONV; break; + case 0x0E: strcpy(insn[i],"CEIL.W.S"); type=FCONV; break; + case 0x0F: strcpy(insn[i],"FLOOR.W.S"); type=FCONV; break; + case 0x21: strcpy(insn[i],"CVT.D.S"); type=FCONV; break; + case 0x24: strcpy(insn[i],"CVT.W.S"); type=FCONV; break; + case 0x25: strcpy(insn[i],"CVT.L.S"); type=FCONV; break; + case 0x30: strcpy(insn[i],"C.F.S"); type=FCOMP; break; + case 0x31: strcpy(insn[i],"C.UN.S"); type=FCOMP; break; + case 0x32: strcpy(insn[i],"C.EQ.S"); type=FCOMP; break; + case 0x33: strcpy(insn[i],"C.UEQ.S"); type=FCOMP; break; + case 0x34: strcpy(insn[i],"C.OLT.S"); type=FCOMP; break; + case 0x35: strcpy(insn[i],"C.ULT.S"); type=FCOMP; break; + case 0x36: strcpy(insn[i],"C.OLE.S"); type=FCOMP; break; + case 0x37: strcpy(insn[i],"C.ULE.S"); type=FCOMP; break; + case 0x38: strcpy(insn[i],"C.SF.S"); type=FCOMP; break; + case 0x39: strcpy(insn[i],"C.NGLE.S"); type=FCOMP; break; + case 0x3A: strcpy(insn[i],"C.SEQ.S"); type=FCOMP; break; + case 0x3B: strcpy(insn[i],"C.NGL.S"); type=FCOMP; break; + case 0x3C: strcpy(insn[i],"C.LT.S"); type=FCOMP; break; + case 0x3D: strcpy(insn[i],"C.NGE.S"); type=FCOMP; break; + case 0x3E: strcpy(insn[i],"C.LE.S"); type=FCOMP; break; + case 0x3F: strcpy(insn[i],"C.NGT.S"); type=FCOMP; break; + } + break; + case 0x11: strcpy(insn[i],"C1.D"); type=NI; + switch(source[i]&0x3f) + { + case 0x00: strcpy(insn[i],"ADD.D"); type=FLOAT; break; + case 0x01: strcpy(insn[i],"SUB.D"); type=FLOAT; break; + case 0x02: strcpy(insn[i],"MUL.D"); type=FLOAT; break; + case 0x03: strcpy(insn[i],"DIV.D"); type=FLOAT; break; + case 0x04: strcpy(insn[i],"SQRT.D"); type=FLOAT; break; + case 0x05: strcpy(insn[i],"ABS.D"); type=FLOAT; break; + case 0x06: strcpy(insn[i],"MOV.D"); type=FLOAT; break; + case 0x07: strcpy(insn[i],"NEG.D"); type=FLOAT; break; + case 0x08: strcpy(insn[i],"ROUND.L.D"); type=FCONV; break; + case 0x09: strcpy(insn[i],"TRUNC.L.D"); type=FCONV; break; + case 0x0A: strcpy(insn[i],"CEIL.L.D"); type=FCONV; break; + case 0x0B: strcpy(insn[i],"FLOOR.L.D"); type=FCONV; break; + case 0x0C: strcpy(insn[i],"ROUND.W.D"); type=FCONV; break; + case 0x0D: strcpy(insn[i],"TRUNC.W.D"); type=FCONV; break; + case 0x0E: strcpy(insn[i],"CEIL.W.D"); type=FCONV; break; + case 0x0F: strcpy(insn[i],"FLOOR.W.D"); type=FCONV; break; + case 0x20: strcpy(insn[i],"CVT.S.D"); type=FCONV; break; + case 0x24: strcpy(insn[i],"CVT.W.D"); type=FCONV; break; + case 0x25: strcpy(insn[i],"CVT.L.D"); type=FCONV; break; + case 0x30: strcpy(insn[i],"C.F.D"); type=FCOMP; break; + case 0x31: strcpy(insn[i],"C.UN.D"); type=FCOMP; break; + case 0x32: strcpy(insn[i],"C.EQ.D"); type=FCOMP; break; + case 0x33: strcpy(insn[i],"C.UEQ.D"); type=FCOMP; break; + case 0x34: strcpy(insn[i],"C.OLT.D"); type=FCOMP; break; + case 0x35: strcpy(insn[i],"C.ULT.D"); type=FCOMP; break; + case 0x36: strcpy(insn[i],"C.OLE.D"); type=FCOMP; break; + case 0x37: strcpy(insn[i],"C.ULE.D"); type=FCOMP; break; + case 0x38: strcpy(insn[i],"C.SF.D"); type=FCOMP; break; + case 0x39: strcpy(insn[i],"C.NGLE.D"); type=FCOMP; break; + case 0x3A: strcpy(insn[i],"C.SEQ.D"); type=FCOMP; break; + case 0x3B: strcpy(insn[i],"C.NGL.D"); type=FCOMP; break; + case 0x3C: strcpy(insn[i],"C.LT.D"); type=FCOMP; break; + case 0x3D: strcpy(insn[i],"C.NGE.D"); type=FCOMP; break; + case 0x3E: strcpy(insn[i],"C.LE.D"); type=FCOMP; break; + case 0x3F: strcpy(insn[i],"C.NGT.D"); type=FCOMP; break; + } + break; + case 0x14: strcpy(insn[i],"C1.W"); type=NI; + switch(source[i]&0x3f) + { + case 0x20: strcpy(insn[i],"CVT.S.W"); type=FCONV; break; + case 0x21: strcpy(insn[i],"CVT.D.W"); type=FCONV; break; + } + break; + case 0x15: strcpy(insn[i],"C1.L"); type=NI; + switch(source[i]&0x3f) + { + case 0x20: strcpy(insn[i],"CVT.S.L"); type=FCONV; break; + case 0x21: strcpy(insn[i],"CVT.D.L"); type=FCONV; break; + } + break; + } + break; + case 0x14: strcpy(insn[i],"BEQL"); type=CJUMP; break; + case 0x15: strcpy(insn[i],"BNEL"); type=CJUMP; break; + case 0x16: strcpy(insn[i],"BLEZL"); type=CJUMP; break; + case 0x17: strcpy(insn[i],"BGTZL"); type=CJUMP; break; + case 0x18: strcpy(insn[i],"DADDI"); type=IMM16; break; + case 0x19: strcpy(insn[i],"DADDIU"); type=IMM16; break; + case 0x1A: strcpy(insn[i],"LDL"); type=LOADLR; break; + case 0x1B: strcpy(insn[i],"LDR"); type=LOADLR; break; + case 0x20: strcpy(insn[i],"LB"); type=LOAD; break; + case 0x21: strcpy(insn[i],"LH"); type=LOAD; break; + case 0x22: strcpy(insn[i],"LWL"); type=LOADLR; break; + case 0x23: strcpy(insn[i],"LW"); type=LOAD; break; + case 0x24: strcpy(insn[i],"LBU"); type=LOAD; break; + case 0x25: strcpy(insn[i],"LHU"); type=LOAD; break; + case 0x26: strcpy(insn[i],"LWR"); type=LOADLR; break; + case 0x27: strcpy(insn[i],"LWU"); type=LOAD; break; + case 0x28: strcpy(insn[i],"SB"); type=STORE; break; + case 0x29: strcpy(insn[i],"SH"); type=STORE; break; + case 0x2A: strcpy(insn[i],"SWL"); type=STORELR; break; + case 0x2B: strcpy(insn[i],"SW"); type=STORE; break; + case 0x2C: strcpy(insn[i],"SDL"); type=STORELR; break; + case 0x2D: strcpy(insn[i],"SDR"); type=STORELR; break; + case 0x2E: strcpy(insn[i],"SWR"); type=STORELR; break; + case 0x2F: strcpy(insn[i],"CACHE"); type=NOP; break; + case 0x30: strcpy(insn[i],"LL"); type=NI; break; + case 0x31: strcpy(insn[i],"LWC1"); type=C1LS; break; + case 0x34: strcpy(insn[i],"LLD"); type=NI; break; + case 0x35: strcpy(insn[i],"LDC1"); type=C1LS; break; + case 0x37: strcpy(insn[i],"LD"); type=LOAD; break; + case 0x38: strcpy(insn[i],"SC"); type=NI; break; + case 0x39: strcpy(insn[i],"SWC1"); type=C1LS; break; + case 0x3C: strcpy(insn[i],"SCD"); type=NI; break; + case 0x3D: strcpy(insn[i],"SDC1"); type=C1LS; break; + case 0x3F: strcpy(insn[i],"SD"); type=STORE; break; + default: strcpy(insn[i],"???"); type=NI; break; + } + itype[i]=type; + opcode2[i]=op2; + /* Get registers/immediates */ + lt1[i]=0; + us1[i]=0; + us2[i]=0; + dep1[i]=0; + dep2[i]=0; + switch(type) { + case LOAD: + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=0; + rt1[i]=(source[i]>>16)&0x1f; + rt2[i]=0; + imm[i]=(short)source[i]; + break; + case STORE: + case STORELR: + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=(source[i]>>16)&0x1f; + rt1[i]=0; + rt2[i]=0; + imm[i]=(short)source[i]; + if(op==0x2c||op==0x2d||op==0x3f) us1[i]=rs2[i]; // 64-bit SDL/SDR/SD + break; + case LOADLR: + // LWL/LWR only load part of the register, + // therefore the target register must be treated as a source too + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=(source[i]>>16)&0x1f; + rt1[i]=(source[i]>>16)&0x1f; + rt2[i]=0; + imm[i]=(short)source[i]; + if(op==0x1a||op==0x1b) us1[i]=rs2[i]; // LDR/LDL + if(op==0x26) dep1[i]=rt1[i]; // LWR + break; + case IMM16: + if (op==0x0f) rs1[i]=0; // LUI instruction has no source register + else rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=0; + rt1[i]=(source[i]>>16)&0x1f; + rt2[i]=0; + if(op>=0x0c&&op<=0x0e) { // ANDI/ORI/XORI + imm[i]=(unsigned short)source[i]; + }else{ + imm[i]=(short)source[i]; + } + if(op==0x18||op==0x19) us1[i]=rs1[i]; // DADDI/DADDIU + if(op==0x0a||op==0x0b) us1[i]=rs1[i]; // SLTI/SLTIU + if(op==0x0d||op==0x0e) dep1[i]=rs1[i]; // ORI/XORI + break; + case UJUMP: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + // The JAL instruction writes to r31. + if (op&1) { + rt1[i]=31; + } + rs2[i]=CCREG; + break; + case RJUMP: + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + // The JALR instruction writes to rd. + if (op2&1) { + rt1[i]=(source[i]>>11)&0x1f; + } + rs2[i]=CCREG; + break; + case CJUMP: + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=(source[i]>>16)&0x1f; + rt1[i]=0; + rt2[i]=0; + if(op&2) { // BGTZ/BLEZ + rs2[i]=0; + } + us1[i]=rs1[i]; + us2[i]=rs2[i]; + likely[i]=op>>4; + break; + case SJUMP: + rs1[i]=(source[i]>>21)&0x1f; + rs2[i]=CCREG; + rt1[i]=0; + rt2[i]=0; + us1[i]=rs1[i]; + if(op2&0x10) { // BxxAL + rt1[i]=31; + // NOTE: If the branch is not taken, r31 is still overwritten + } + likely[i]=(op2&2)>>1; + break; + case FJUMP: + rs1[i]=FSREG; + rs2[i]=CSREG; + rt1[i]=0; + rt2[i]=0; + likely[i]=((source[i])>>17)&1; + break; + case ALU: + rs1[i]=(source[i]>>21)&0x1f; // source + rs2[i]=(source[i]>>16)&0x1f; // subtract amount + rt1[i]=(source[i]>>11)&0x1f; // destination + rt2[i]=0; + if(op2==0x2a||op2==0x2b) { // SLT/SLTU + us1[i]=rs1[i];us2[i]=rs2[i]; + } + else if(op2>=0x24&&op2<=0x27) { // AND/OR/XOR/NOR + dep1[i]=rs1[i];dep2[i]=rs2[i]; + } + else if(op2>=0x2c&&op2<=0x2f) { // DADD/DSUB + dep1[i]=rs1[i];dep2[i]=rs2[i]; + } + break; + case MULTDIV: + rs1[i]=(source[i]>>21)&0x1f; // source + rs2[i]=(source[i]>>16)&0x1f; // divisor + rt1[i]=HIREG; + rt2[i]=LOREG; + if (op2>=0x1c&&op2<=0x1f) { // DMULT/DMULTU/DDIV/DDIVU + us1[i]=rs1[i];us2[i]=rs2[i]; + } + break; + case MOV: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + if(op2==0x10) rs1[i]=HIREG; // MFHI + if(op2==0x11) rt1[i]=HIREG; // MTHI + if(op2==0x12) rs1[i]=LOREG; // MFLO + if(op2==0x13) rt1[i]=LOREG; // MTLO + if((op2&0x1d)==0x10) rt1[i]=(source[i]>>11)&0x1f; // MFxx + if((op2&0x1d)==0x11) rs1[i]=(source[i]>>21)&0x1f; // MTxx + dep1[i]=rs1[i]; + break; + case SHIFT: + rs1[i]=(source[i]>>16)&0x1f; // target of shift + rs2[i]=(source[i]>>21)&0x1f; // shift amount + rt1[i]=(source[i]>>11)&0x1f; // destination + rt2[i]=0; + // DSLLV/DSRLV/DSRAV are 64-bit + if(op2>=0x14&&op2<=0x17) us1[i]=rs1[i]; + break; + case SHIFTIMM: + rs1[i]=(source[i]>>16)&0x1f; + rs2[i]=0; + rt1[i]=(source[i]>>11)&0x1f; + rt2[i]=0; + imm[i]=(source[i]>>6)&0x1f; + // DSxx32 instructions + if(op2>=0x3c) imm[i]|=0x20; + // DSLL/DSRL/DSRA/DSRA32/DSRL32 but not DSLL32 require 64-bit source + if(op2>=0x38&&op2!=0x3c) us1[i]=rs1[i]; + break; + case COP0: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + if(op2==0) rt1[i]=(source[i]>>16)&0x1F; // MFC0 + if(op2==4) rs1[i]=(source[i]>>16)&0x1F; // MTC0 + if(op2==4&&((source[i]>>11)&0x1f)==12) rt2[i]=CSREG; // Status + if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET + break; + case COP1: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + if(op2<3) rt1[i]=(source[i]>>16)&0x1F; // MFC1/DMFC1/CFC1 + if(op2>3) rs1[i]=(source[i]>>16)&0x1F; // MTC1/DMTC1/CTC1 + if(op2==5) us1[i]=rs1[i]; // DMTC1 + rs2[i]=CSREG; + break; + case C1LS: + rs1[i]=(source[i]>>21)&0x1F; + rs2[i]=CSREG; + rt1[i]=0; + rt2[i]=0; + imm[i]=(short)source[i]; + break; + case FLOAT: + case FCONV: + rs1[i]=0; + rs2[i]=CSREG; + rt1[i]=0; + rt2[i]=0; + break; + case FCOMP: + rs1[i]=FSREG; + rs2[i]=CSREG; + rt1[i]=FSREG; + rt2[i]=0; + break; + case SYSCALL: + rs1[i]=CCREG; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + break; + default: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + } + /* Calculate branch target addresses */ + if(type==UJUMP) + ba[i]=((start+i*4+4)&0xF0000000)|(((unsigned int)source[i]<<6)>>4); + else if(type==CJUMP&&rs1[i]==rs2[i]&&(op&1)) + ba[i]=start+i*4+8; // Ignore never taken branch + else if(type==SJUMP&&rs1[i]==0&&!(op2&1)) + ba[i]=start+i*4+8; // Ignore never taken branch + else if(type==CJUMP||type==SJUMP||type==FJUMP) + ba[i]=start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14); + else ba[i]=-1; + /* Is this the end of the block? */ + if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) { + if(rt1[i-1]==0) { // Continue past subroutine call (JAL) + done=1; + // Does the block continue due to a branch? + for(j=i-1;j>=0;j--) + { + if(ba[j]==start+i*4) done=j=0; // Branch into delay slot + if(ba[j]==start+i*4+4) done=j=0; + if(ba[j]==start+i*4+8) done=j=0; + } + } + else { + if(stop_after_jal) done=1; + // Stop on BREAK + if((source[i+1]&0xfc00003f)==0x0d) done=1; + } + // Don't recompile stuff that's already compiled + if(check_addr(start+i*4+4)) done=1; + // Don't get too close to the limit + if(i>MAXBLOCK/2) done=1; + } + if(i>0&&itype[i-1]==SYSCALL&&stop_after_jal) done=1; + assert(i0); + + /* Pass 2 - Register dependencies and branch targets */ + + unneeded_registers(0,slen-1,0); + + /* Pass 3 - Register allocation */ + + struct regstat current; // Current register allocations/status + current.is32=1; + current.dirty=0; + current.u=unneeded_reg[0]; + current.uu=unneeded_reg_upper[0]; + clear_all_regs(current.regmap); + alloc_reg(¤t,0,CCREG); + dirty_reg(¤t,CCREG); + current.isconst=0; + current.wasconst=0; + int ds=0; + int cc=0; + int hr; + + provisional_32bit(); + + if((u_int)addr&1) { + // First instruction is delay slot + cc=-1; + bt[1]=1; + ds=1; + unneeded_reg[0]=1; + unneeded_reg_upper[0]=1; + current.regmap[HOST_BTREG]=BTREG; + } + + for(i=0;i1) + { + if((opcode[i-2]&0x2f)==0x05) // BNE/BNEL + { + if(rs1[i-2]==0||rs2[i-2]==0) + { + if(rs1[i-2]) { + current.is32|=1LL<=0) current.regmap[hr]=-1; + } + if(rs2[i-2]) { + current.is32|=1LL<=0) current.regmap[hr]=-1; + } + } + } + } + // If something jumps here with 64-bit values + // then promote those registers to 64 bits + if(bt[i]) + { + uint64_t temp_is32=current.is32; + for(j=i-1;j>=0;j--) + { + if(ba[j]==start+i*4) + temp_is32&=branch_regs[j].is32; + } + for(j=i;j0&&r<64) + { + if((current.dirty>>hr)&((current.is32&~temp_is32)>>r)&1) { + temp_is32|=1LL<=0;j--) + { + if(ba[j]==start+i*4+4) + temp_is32&=branch_regs[j].is32; + } + for(j=i;j0) + { + if((current.dirty>>hr)&((current.is32&~temp_is32)>>(r&63))&1) { + if(itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=RJUMP&&itype[i]!=FJUMP) + { + if(rs1[i]!=(r&63)&&rs2[i]!=(r&63)) + { + //DebugMessage(M64MSG_VERBOSE, "dump %d/r%d",hr,r); + current.regmap[hr]=-1; + if(get_reg(current.regmap,r|64)>=0) + current.regmap[get_reg(current.regmap,r|64)]=-1; + } + } + } + } + } + } + } + else if(i>16)!=0x1000&&(itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP)) + { + uint64_t temp_is32=current.is32; + for(j=i-1;j>=0;j--) + { + if(ba[j]==start+i*4+8) + temp_is32&=branch_regs[j].is32; + } + for(j=i;j0) + { + if((current.dirty>>hr)&((current.is32&~temp_is32)>>(r&63))&1) { + if(rs1[i]!=(r&63)&&rs2[i]!=(r&63)&&rs1[i+1]!=(r&63)&&rs2[i+1]!=(r&63)) + { + //DebugMessage(M64MSG_VERBOSE, "dump %d/r%d",hr,r); + current.regmap[hr]=-1; + if(get_reg(current.regmap,r|64)>=0) + current.regmap[get_reg(current.regmap,r|64)]=-1; + } + } + } + } + } + } + #endif + if(itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=RJUMP&&itype[i]!=FJUMP) { + if(i+1>rt1[i])&1) current.uu&=~((1LL<>rt1[i+1])&1) current.uu&=~((1LL<>rt1[i])&1) current.uu&=~((1LL<=0) { + if(r!=regmap_pre[i][hr]) { + regs[i].regmap_entry[hr]=-1; + } + else + { + if(r<64){ + if((current.u>>r)&1) { + regs[i].regmap_entry[hr]=-1; + regs[i].regmap[hr]=-1; + //Don't clear regs in the delay slot as the branch might need them + //current.regmap[hr]=-1; + }else + regs[i].regmap_entry[hr]=r; + } + else { + if((current.uu>>(r&63))&1) { + regs[i].regmap_entry[hr]=-1; + regs[i].regmap[hr]=-1; + //Don't clear regs in the delay slot as the branch might need them + //current.regmap[hr]=-1; + }else + regs[i].regmap_entry[hr]=r; + } + } + } else { + // First instruction expects CCREG to be allocated + if(i==0&&hr==HOST_CCREG) + regs[i].regmap_entry[hr]=CCREG; + else + regs[i].regmap_entry[hr]=-1; + } + } + } + else { // Not delay slot + switch(itype[i]) { + case UJUMP: + //current.isconst=0; // DEBUG + //current.wasconst=0; // DEBUG + //regs[i].wasconst=0; // DEBUG + clear_const(¤t,rt1[i]); + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + if (rt1[i]==31) { + alloc_reg(¤t,i,31); + dirty_reg(¤t,31); + assert(rs1[i+1]!=31&&rs2[i+1]!=31); + #ifdef REG_PREFETCH + alloc_reg(¤t,i,PTEMP); + #endif + //current.is32|=1LL<>rs1[i])&(current.is32>>rs2[i])&1)) + { + if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); + if(rs2[i]) alloc_reg64(¤t,i,rs2[i]); + } + if((rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))|| + (rs2[i]&&(rs2[i]==rt1[i+1]||rs2[i]==rt2[i+1]))) { + // The delay slot overwrites one of our conditions. + // Allocate the branch condition registers instead. + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + if(rs1[i]) alloc_reg(¤t,i,rs1[i]); + if(rs2[i]) alloc_reg(¤t,i,rs2[i]); + if(!((current.is32>>rs1[i])&(current.is32>>rs2[i])&1)) + { + if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); + if(rs2[i]) alloc_reg64(¤t,i,rs2[i]); + } + } + else + { + ooo[i]=1; + delayslot_alloc(¤t,i+1); + } + } + else + if((opcode[i]&0x3E)==6) // BLEZ/BGTZ + { + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,rs1[i]); + if(!(current.is32>>rs1[i]&1)) + { + alloc_reg64(¤t,i,rs1[i]); + } + if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) { + // The delay slot overwrites one of our conditions. + // Allocate the branch condition registers instead. + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + if(rs1[i]) alloc_reg(¤t,i,rs1[i]); + if(!((current.is32>>rs1[i])&1)) + { + if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); + } + } + else + { + ooo[i]=1; + delayslot_alloc(¤t,i+1); + } + } + else + // Don't alloc the delay slot yet because we might not execute it + if((opcode[i]&0x3E)==0x14) // BEQL/BNEL + { + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,rs1[i]); + alloc_reg(¤t,i,rs2[i]); + if(!((current.is32>>rs1[i])&(current.is32>>rs2[i])&1)) + { + alloc_reg64(¤t,i,rs1[i]); + alloc_reg64(¤t,i,rs2[i]); + } + } + else + if((opcode[i]&0x3E)==0x16) // BLEZL/BGTZL + { + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,rs1[i]); + if(!(current.is32>>rs1[i]&1)) + { + alloc_reg64(¤t,i,rs1[i]); + } + } + ds=1; + //current.isconst=0; + break; + case SJUMP: + //current.isconst=0; + //current.wasconst=0; + //regs[i].wasconst=0; + clear_const(¤t,rs1[i]); + clear_const(¤t,rt1[i]); + //if((opcode2[i]&0x1E)==0x0) // BLTZ/BGEZ + if((opcode2[i]&0x0E)==0x0) // BLTZ/BGEZ + { + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,rs1[i]); + if(!(current.is32>>rs1[i]&1)) + { + alloc_reg64(¤t,i,rs1[i]); + } + if (rt1[i]==31) { // BLTZAL/BGEZAL + alloc_reg(¤t,i,31); + dirty_reg(¤t,31); + assert(rs1[i+1]!=31&&rs2[i+1]!=31); + //#ifdef REG_PREFETCH + //alloc_reg(¤t,i,PTEMP); + //#endif + //current.is32|=1LL<>rs1[i])&1)) + { + if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); + } + } + else + { + ooo[i]=1; + delayslot_alloc(¤t,i+1); + } + } + else + // Don't alloc the delay slot yet because we might not execute it + if((opcode2[i]&0x1E)==0x2) // BLTZL/BGEZL + { + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,rs1[i]); + if(!(current.is32>>rs1[i]&1)) + { + alloc_reg64(¤t,i,rs1[i]); + } + } + ds=1; + //current.isconst=0; + break; + case FJUMP: + current.isconst=0; + current.wasconst=0; + regs[i].wasconst=0; + if(likely[i]==0) // BC1F/BC1T + { + // TODO: Theoretically we can run out of registers here on x86. + // The delay slot can allocate up to six, and we need to check + // CSREG before executing the delay slot. Possibly we can drop + // the cycle count and then reload it after checking that the + // FPU is in a usable state, or don't do out-of-order execution. + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,FSREG); + alloc_reg(¤t,i,CSREG); + if(itype[i+1]==FCOMP) { + // The delay slot overwrites the branch condition. + // Allocate the branch condition registers instead. + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,CSREG); + alloc_reg(¤t,i,FSREG); + } + else { + ooo[i]=1; + delayslot_alloc(¤t,i+1); + alloc_reg(¤t,i+1,CSREG); + } + } + else + // Don't alloc the delay slot yet because we might not execute it + if(likely[i]) // BC1FL/BC1TL + { + alloc_cc(¤t,i); + dirty_reg(¤t,CCREG); + alloc_reg(¤t,i,CSREG); + alloc_reg(¤t,i,FSREG); + } + ds=1; + current.isconst=0; + break; + case IMM16: + imm16_alloc(¤t,i); + break; + case LOAD: + case LOADLR: + load_alloc(¤t,i); + break; + case STORE: + case STORELR: + store_alloc(¤t,i); + break; + case ALU: + alu_alloc(¤t,i); + break; + case SHIFT: + shift_alloc(¤t,i); + break; + case MULTDIV: + multdiv_alloc(¤t,i); + break; + case SHIFTIMM: + shiftimm_alloc(¤t,i); + break; + case MOV: + mov_alloc(¤t,i); + break; + case COP0: + cop0_alloc(¤t,i); + break; + case COP1: + cop1_alloc(¤t,i); + break; + case C1LS: + c1ls_alloc(¤t,i); + break; + case FCONV: + fconv_alloc(¤t,i); + break; + case FLOAT: + float_alloc(¤t,i); + break; + case FCOMP: + fcomp_alloc(¤t,i); + break; + case SYSCALL: + syscall_alloc(¤t,i); + break; + case SPAN: + pagespan_alloc(¤t,i); + break; + } + + // Drop the upper half of registers that have become 32-bit + current.uu|=current.is32&((1LL<>rt1[i])&1) current.uu&=~((1LL<>rt1[i+1])&1) current.uu&=~((1LL<=0) { + if(r!=regmap_pre[i][hr]) { + // TODO: delay slot (?) + or=get_reg(regmap_pre[i],r); // Get old mapping for this register + if(or<0||(r&63)>=TEMPREG){ + regs[i].regmap_entry[hr]=-1; + } + else + { + // Just move it to a different register + regs[i].regmap_entry[hr]=r; + // If it was dirty before, it's still dirty + if((regs[i].wasdirty>>or)&1) dirty_reg(¤t,r&63); + } + } + else + { + // Unneeded + if(r==0){ + regs[i].regmap_entry[hr]=0; + } + else + if(r<64){ + if((current.u>>r)&1) { + regs[i].regmap_entry[hr]=-1; + //regs[i].regmap[hr]=-1; + current.regmap[hr]=-1; + }else + regs[i].regmap_entry[hr]=r; + } + else { + if((current.uu>>(r&63))&1) { + regs[i].regmap_entry[hr]=-1; + //regs[i].regmap[hr]=-1; + current.regmap[hr]=-1; + }else + regs[i].regmap_entry[hr]=r; + } + } + } else { + // Branches expect CCREG to be allocated at the target + if(regmap_pre[i][hr]==CCREG) + regs[i].regmap_entry[hr]=CCREG; + else + regs[i].regmap_entry[hr]=-1; + } + } + memcpy(regs[i].regmap,current.regmap,sizeof(current.regmap)); + } + /* Branch post-alloc */ + if(i>0) + { + current.was32=current.is32; + current.wasdirty=current.dirty; + switch(itype[i-1]) { + case UJUMP: + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].isconst=0; + branch_regs[i-1].wasconst=0; + branch_regs[i-1].u=branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1])&(current.is32>>rs2[i-1])&1)) + { + if(rs1[i-1]) alloc_reg64(¤t,i-1,rs1[i-1]); + if(rs2[i-1]) alloc_reg64(¤t,i-1,rs2[i-1]); + } + } + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].isconst=0; + branch_regs[i-1].wasconst=0; + memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + } + else + if((opcode[i-1]&0x3E)==6) // BLEZ/BGTZ + { + alloc_cc(¤t,i-1); + dirty_reg(¤t,CCREG); + if(rs1[i-1]==rt1[i]||rs1[i-1]==rt2[i]) { + // The delay slot overwrote the branch condition + // Delay slot goes after the test (in order) + current.u=branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1]&1)) + { + alloc_reg64(¤t,i-1,rs1[i-1]); + } + } + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].isconst=0; + branch_regs[i-1].wasconst=0; + memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + } + else + // Alloc the delay slot in case the branch is taken + if((opcode[i-1]&0x3E)==0x14) // BEQL/BNEL + { + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].u=(branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1]&1)) + { + alloc_reg64(¤t,i-1,rs1[i-1]); + } + } + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].isconst=0; + branch_regs[i-1].wasconst=0; + memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + } + else + // Alloc the delay slot in case the branch is taken + if((opcode2[i-1]&0x1E)==2) // BLTZL/BGEZL + { + memcpy(&branch_regs[i-1],¤t,sizeof(current)); + branch_regs[i-1].u=(branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>16)==0x1000) + { + if(rt1[i-1]==31) // JAL/JALR + { + // Subroutine call will return here, don't alloc any registers + current.is32=1; + current.dirty=0; + clear_all_regs(current.regmap); + alloc_reg(¤t,i,CCREG); + dirty_reg(¤t,CCREG); + } + else if(i+1=0;j--) + { + if(ba[j]==start+i*4+4) { + memcpy(current.regmap,branch_regs[j].regmap,sizeof(current.regmap)); + current.is32=branch_regs[j].is32; + current.dirty=branch_regs[j].dirty; + break; + } + } + while(j>=0) { + if(ba[j]==start+i*4+4) { + for(hr=0;hr0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL)) + { + cc=0; + } + else + { + cc++; + } + + flush_dirty_uppers(¤t); + if(!is_ds[i]) { + regs[i].is32=current.is32; + regs[i].dirty=current.dirty; + regs[i].isconst=current.isconst; + memcpy(constmap[i],current.constmap,sizeof(current.constmap)); + } + for(hr=0;hr=0) { + if(regmap_pre[i][hr]!=regs[i].regmap[hr]) { + regs[i].wasconst&=~(1<=0;i--) + { + int hr=0; + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + if(ba[i]=(start+slen*4)) + { + // Branch out of this block, don't need anything + nr=0; + } + else + { + // Internal branch + // Need whatever matches the target + nr=0; + int t=(ba[i]-start)>>2; + for(hr=0;hr=0) { + if(regs[i].regmap_entry[hr]==regs[t].regmap_entry[hr]) nr|=(uint64_t)1<>16)!=0x1000) + { + if(i=0&&get_reg(regs[i+2].regmap_entry,regmap_pre[i+2][hr])<0) nr&=~(1<=0) if(!((nr>>hr)&1)) DebugMessage(M64MSG_VERBOSE, "%x-bogus(%d=%d)",start+i*4,hr,regmap_entry[i+2][hr]); + } + } + } + // Don't need stuff which is overwritten + if(regs[i].regmap[hr]!=regmap_pre[i][hr]) nr&=~(1<>dep1[i+1])&1)) { + if(dep1[i+1]==(regmap_pre[i][hr]&63)) nr|=(uint64_t)1<>dep2[i+1])&1)) { + if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=(uint64_t)1<=0&&get_reg(regs[i+1].regmap_entry,regmap_pre[i+1][hr])<0) nr&=~(1<>dep1[i])&1)) { + if(dep1[i]==(regmap_pre[i][hr]&63)) nr|=(uint64_t)1<>dep2[i])&1)) { + if(dep2[i]==(regmap_pre[i][hr]&63)) nr|=(uint64_t)1<0&&!bt[i]&&((regs[i].wasdirty>>hr)&1)) { + if((regmap_pre[i][hr]>0&®map_pre[i][hr]<64&&!((unneeded_reg[i]>>regmap_pre[i][hr])&1)) || + (regmap_pre[i][hr]>64&&!((unneeded_reg_upper[i]>>(regmap_pre[i][hr]&63))&1)) ) { + if(rt1[i-1]==(regmap_pre[i][hr]&63)) nr|=(uint64_t)1<0&®s[i].regmap_entry[hr]<64&&!((unneeded_reg[i]>>regs[i].regmap_entry[hr])&1)) || + (regs[i].regmap_entry[hr]>64&&!((unneeded_reg_upper[i]>>(regs[i].regmap_entry[hr]&63))&1)) ) { + if(rt1[i-1]==(regs[i].regmap_entry[hr]&63)) nr|=(uint64_t)1<>hr)&1)) { + if(regs[i].regmap_entry[hr]!=CCREG) regs[i].regmap_entry[hr]=-1; + if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] && + (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && + (regs[i].regmap[hr]&63)!=PTEMP && (regs[i].regmap[hr]&63)!=CCREG) + { + if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&(source[i]>>16)!=0x1000) + { + if(likely[i]) { + regs[i].regmap[hr]=-1; + regs[i].isconst&=~(1<=0||get_reg(branch_regs[i].regmap,rt1[i+1]|64)>=0) + { + d1=dep1[i+1]; + d2=dep2[i+1]; + } + if(using_tlb) { + if(itype[i+1]==LOAD || itype[i+1]==LOADLR || + itype[i+1]==STORE || itype[i+1]==STORELR || + itype[i+1]==C1LS ) + map=TLREG; + } else + if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) { + map=INVCP; + } + if(itype[i+1]==LOADLR || itype[i+1]==STORELR || + itype[i+1]==C1LS ) + temp=FTEMP; + if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] && + (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && + (regs[i].regmap[hr]&63)!=rt1[i+1] && (regs[i].regmap[hr]&63)!=rt2[i+1] && + (regs[i].regmap[hr]^64)!=us1[i+1] && (regs[i].regmap[hr]^64)!=us2[i+1] && + (regs[i].regmap[hr]^64)!=d1 && (regs[i].regmap[hr]^64)!=d2 && + regs[i].regmap[hr]!=rs1[i+1] && regs[i].regmap[hr]!=rs2[i+1] && + (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=PTEMP && + regs[i].regmap[hr]!=RHASH && regs[i].regmap[hr]!=RHTBL && + regs[i].regmap[hr]!=RTEMP && regs[i].regmap[hr]!=CCREG && + regs[i].regmap[hr]!=map ) + { + regs[i].regmap[hr]=-1; + regs[i].isconst&=~(1<>16)!=0x1000) + { + if(!likely[i]&&i0) + { + int d1=0,d2=0,map=-1,temp=-1; + if(get_reg(regs[i].regmap,rt1[i]|64)>=0) + { + d1=dep1[i]; + d2=dep2[i]; + } + if(using_tlb) { + if(itype[i]==LOAD || itype[i]==LOADLR || + itype[i]==STORE || itype[i]==STORELR || + itype[i]==C1LS ) + map=TLREG; + } else if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) { + map=INVCP; + } + if(itype[i]==LOADLR || itype[i]==STORELR || + itype[i]==C1LS ) + temp=FTEMP; + if((regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && + (regs[i].regmap[hr]^64)!=us1[i] && (regs[i].regmap[hr]^64)!=us2[i] && + (regs[i].regmap[hr]^64)!=d1 && (regs[i].regmap[hr]^64)!=d2 && + regs[i].regmap[hr]!=rs1[i] && regs[i].regmap[hr]!=rs2[i] && + (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=map && + (itype[i]!=SPAN||regs[i].regmap[hr]!=CCREG)) + { + if(i>(regs[i].regmap[hr]&63))&1)) + { + DebugMessage(M64MSG_VERBOSE, "fail: %x (%d %d!=%d)",start+i*4,hr,regmap_pre[i+1][hr],regs[i].regmap[hr]); + assert(regmap_pre[i+1][hr]==regs[i].regmap[hr]); + } + regmap_pre[i+1][hr]=-1; + if(regs[i+1].regmap_entry[hr]==CCREG) regs[i+1].regmap_entry[hr]=-1; + regs[i+1].wasconst&=~(1<=start && ba[i]<(start+i*4)) + if(itype[i+1]==NOP||itype[i+1]==MOV||itype[i+1]==ALU + ||itype[i+1]==SHIFTIMM||itype[i+1]==IMM16||itype[i+1]==LOAD + ||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS + ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT + ||itype[i+1]==FCOMP||itype[i+1]==FCONV) + { + int t=(ba[i]-start)>>2; + if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=CJUMP&&itype[t-1]!=SJUMP&&itype[t-1]!=FJUMP)) // loop_preload can't handle jumps into delay slots + if(t<2||(itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||rt1[t-2]!=31) // call/ret assumes no registers allocated + for(hr=0;hr64) { + if(!((regs[i].dirty>>hr)&1)) + f_regmap[hr]=regs[i].regmap[hr]; + else f_regmap[hr]=-1; + } + else if(regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;n64) { + if(!((branch_regs[i].dirty>>hr)&1)) + f_regmap[hr]=branch_regs[i].regmap[hr]; + else f_regmap[hr]=-1; + } + else if(branch_regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=branch_regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;nclean transition + #ifdef DESTRUCTIVE_WRITEBACK + if(t>0) if(get_reg(regmap_pre[t],f_regmap[hr])>=0) if((regs[t].wasdirty>>get_reg(regmap_pre[t],f_regmap[hr]))&1) f_regmap[hr]=-1; + #endif + // This check is only strictly required in the DESTRUCTIVE_WRITEBACK + // case above, however it's always a good idea. We can't hoist the + // load if the register was already allocated, so there's no point + // wasting time analyzing most of these cases. It only "succeeds" + // when the mapping was different and the load can be replaced with + // a mov, which is of negligible benefit. So such cases are + // skipped below. + if(f_regmap[hr]>0) { + if(regs[t].regmap[hr]==f_regmap[hr]||(regs[t].regmap_entry[hr]<0&&get_reg(regmap_pre[t],f_regmap[hr])<0)) { + int r=f_regmap[hr]; + for(j=t;j<=i;j++) + { + //DebugMessage(M64MSG_VERBOSE, "Test %x -> %x, %x %d/%d",start+i*4,ba[i],start+j*4,hr,r); + if(r<34&&((unneeded_reg[j]>>r)&1)) break; + if(r>63&&((unneeded_reg_upper[j]>>(r&63))&1)) break; + if(r>63) { + // NB This can exclude the case where the upper-half + // register is lower numbered than the lower-half + // register. Not sure if it's worth fixing... + if(get_reg(regs[j].regmap,r&63)<0) break; + if(get_reg(regs[j].regmap_entry,r&63)<0) break; + if(regs[j].is32&(1LL<<(r&63))) break; + } + if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63) %x, %x %d/%d",start+i*4,ba[i],start+j*4,hr,r); + int k; + if(regs[i].regmap[hr]==-1&&branch_regs[i].regmap[hr]==-1) { + if(get_reg(regs[i+2].regmap,f_regmap[hr])>=0) break; + if(r>63) { + if(get_reg(regs[i].regmap,r&63)<0) break; + if(get_reg(branch_regs[i].regmap,r&63)<0) break; + } + k=i; + while(k>1&®s[k-1].regmap[hr]==-1) { + if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { + //DebugMessage(M64MSG_VERBOSE, "no free regs for store %x",start+(k-1)*4); + break; + } + if(get_reg(regs[k-1].regmap,f_regmap[hr])>=0) { + //DebugMessage(M64MSG_VERBOSE, "no-match due to different register"); + break; + } + if(itype[k-2]==UJUMP||itype[k-2]==RJUMP||itype[k-2]==CJUMP||itype[k-2]==SJUMP||itype[k-2]==FJUMP) { + //DebugMessage(M64MSG_VERBOSE, "no-match due to branch"); + break; + } + // call/ret fast path assumes no registers allocated + if(k>2&&(itype[k-3]==UJUMP||itype[k-3]==RJUMP)&&rt1[k-3]==31) { + break; + } + if(r>63) { + // NB This can exclude the case where the upper-half + // register is lower numbered than the lower-half + // register. Not sure if it's worth fixing... + if(get_reg(regs[k-1].regmap,r&63)<0) break; + if(regs[k-1].is32&(1LL<<(r&63))) break; + } + k--; + } + if(i",hr,start+k*4); + while(k",hr,start+k*4); + break; + } + assert(regs[i-1].regmap[hr]==f_regmap[hr]); + if(regs[i-1].regmap[hr]==f_regmap[hr]&®map_pre[i][hr]==f_regmap[hr]) { + //DebugMessage(M64MSG_VERBOSE, "OK fill %x (r%d)",start+i*4,hr); + regs[i].regmap_entry[hr]=f_regmap[hr]; + regs[i].regmap[hr]=f_regmap[hr]; + regs[i].wasdirty&=~(1<>16)!=0x1000) { + regmap_pre[i+2][hr]=f_regmap[hr]; + regs[i+2].wasdirty&=~(1<>16)!=0x1000) { + regmap_pre[k+2][hr]=f_regmap[hr]; + regs[k+2].wasdirty&=~(1<=0) + break; + if(get_reg(regs[j].regmap,f_regmap[hr])>=0) { + //DebugMessage(M64MSG_VERBOSE, "no-match due to different register"); + break; + } + if((regs[j+1].is32&(1LL<>16)==0x1000) + { + // Stop on unconditional branch + break; + } + if(itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) + { + if(ooo[j]) { + if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) + break; + }else{ + if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) + break; + } + if(get_reg(branch_regs[j].regmap,f_regmap[hr])>=0) { + //DebugMessage(M64MSG_VERBOSE, "no-match due to different register (branch)"); + break; + } + } + if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) { + //DebugMessage(M64MSG_VERBOSE, "No free regs for store %x",start+j*4); + break; + } + if(f_regmap[hr]>=64) { + if(regs[j].is32&(1LL<<(f_regmap[hr]&63))) { + break; + } + else + { + if(get_reg(regs[j].regmap,f_regmap[hr]&63)<0) { + break; + } + } + } + } + } + } + } + } + }else{ + // Non branch or undetermined branch target + for(hr=0;hr64) { + if(!((regs[i].dirty>>hr)&1)) + f_regmap[hr]=regs[i].regmap[hr]; + } + else if(regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;n %x",start+k*4,start+j*4); + while(ki&&f_regmap[HOST_CCREG]==CCREG) + { + //DebugMessage(M64MSG_VERBOSE, "Extend backwards"); + int k; + k=i; + while(regs[k-1].regmap[HOST_CCREG]==-1) { + if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { + //DebugMessage(M64MSG_VERBOSE, "no free regs for store %x",start+(k-1)*4); + break; + } + k--; + } + if(regs[k-1].regmap[HOST_CCREG]==CCREG) { + //DebugMessage(M64MSG_VERBOSE, "Extend CC, %x ->",start+k*4); + while(k<=i) { + regs[k].regmap_entry[HOST_CCREG]=CCREG; + regs[k].regmap[HOST_CCREG]=CCREG; + regmap_pre[k+1][HOST_CCREG]=CCREG; + regs[k+1].wasdirty|=1<",start+k*4); + } + } + } + if(itype[i]!=STORE&&itype[i]!=STORELR&&itype[i]!=C1LS&&itype[i]!=SHIFT&& + itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&& + itype[i]!=IMM16&&itype[i]!=LOAD&&itype[i]!=COP1&&itype[i]!=FLOAT&& + itype[i]!=FCONV&&itype[i]!=FCOMP) + { + memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap)); + } + } + } + + // Cache memory offset or tlb map pointer if a register is available + #ifndef HOST_IMM_ADDR32 + #ifndef RAM_OFFSET + if(using_tlb) + #endif + { + int earliest_available[HOST_REGS]; + int loop_start[HOST_REGS]; + int score[HOST_REGS]; + int end[HOST_REGS]; + int reg=using_tlb?MMREG:ROREG; + + // Init + for(hr=0;hr=0) { + score[hr]=0;earliest_available[hr]=i+1; + loop_start[hr]=MAXBLOCK; + } + if(itype[i]==UJUMP||itype[i]==RJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { + if(branch_regs[i].regmap[hr]>=0) { + score[hr]=0;earliest_available[hr]=i+2; + loop_start[hr]=MAXBLOCK; + } + } + } + // No register allocations after unconditional jumps + if(itype[i]==UJUMP||itype[i]==RJUMP||(source[i]>>16)==0x1000) + { + for(hr=0;hr=0) break; + if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { + if(branch_regs[j].regmap[hr]>=0) break; + if(ooo[j]) { + if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) break; + }else{ + if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) break; + } + } + else if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) break; + if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { + int t=(ba[j]-start)>>2; + if(t=earliest_available[hr]) { + if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) { // call/ret assumes no registers allocated + // Score a point for hoisting loop invariant + if(t>16)==0x1000) + { + // Stop on unconditional branch + break; + } + else + if(itype[j]==LOAD||itype[j]==LOADLR|| + itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS) { + score[hr]++; + end[hr]=j; + } + } + } + } + // Find highest score and allocate that register + int maxscore=0; + for(hr=0;hrscore[maxscore]) { + maxscore=hr; + //DebugMessage(M64MSG_VERBOSE, "highest score: %d %d (%x->%x)",score[hr],hr,start+i*4,start+end[hr]*4); + } + } + } + if(score[maxscore]>1) + { + if(i=0) {DebugMessage(M64MSG_ERROR, "oops: %x %x was %d=%d",loop_start[maxscore]*4+start,j*4+start,maxscore,regs[j].regmap[maxscore]);} + assert(regs[j].regmap[maxscore]<0); + if(j>loop_start[maxscore]) regs[j].regmap_entry[maxscore]=reg; + regs[j].regmap[maxscore]=reg; + regs[j].dirty&=~(1<>16)!=0x1000) { + regmap_pre[j+2][maxscore]=reg; + regs[j+2].wasdirty&=~(1<>2; + if(t==loop_start[maxscore]) { + if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) // call/ret assumes no registers allocated + regs[t].regmap_entry[maxscore]=reg; + } + } + else + { + if(j<1||(itype[j-1]!=RJUMP&&itype[j-1]!=UJUMP&&itype[j-1]!=CJUMP&&itype[j-1]!=SJUMP&&itype[j-1]!=FJUMP)) { + regmap_pre[j+1][maxscore]=reg; + regs[j+1].wasdirty&=~(1<=0) + { + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=regs[i+1].regmap[hr]; + regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; + regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; + regs[i].isconst&=~(1<=0) + { + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=regs[i+1].regmap[hr]; + regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; + regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; + regs[i].isconst&=~(1<=0) + { + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=rs1[i+1]; + regmap_pre[i+1][hr]=rs1[i+1]; + regs[i+1].regmap_entry[hr]=rs1[i+1]; + regs[i].isconst&=~(1<=0) + { + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=rs1[i+1]; + regmap_pre[i+1][hr]=rs1[i+1]; + regs[i+1].regmap_entry[hr]=rs1[i+1]; + regs[i].isconst&=~(1<=0) { + int sr=get_reg(regs[i+1].regmap,rs1[i+1]); + if(sr>=0&&((regs[i+1].wasconst>>sr)&1)) { + int nr; + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=MGEN1+((i+1)&1); + regmap_pre[i+1][hr]=MGEN1+((i+1)&1); + regs[i+1].regmap_entry[hr]=MGEN1+((i+1)&1); + regs[i].isconst&=~(1<=0) + { + // move it to another register + regs[i+1].regmap[hr]=-1; + regmap_pre[i+2][hr]=-1; + regs[i+1].regmap[nr]=TLREG; + regmap_pre[i+2][nr]=TLREG; + regs[i].regmap[nr]=MGEN1+((i+1)&1); + regmap_pre[i+1][nr]=MGEN1+((i+1)&1); + regs[i+1].regmap_entry[nr]=MGEN1+((i+1)&1); + regs[i].isconst&=~(1<=0); + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=rs1[i+1]; + regmap_pre[i+1][hr]=rs1[i+1]; + regs[i+1].regmap_entry[hr]=rs1[i+1]; + regs[i].isconst&=~(1<=0); + if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) + { + regs[i].regmap[hr]=rs1[i+1]; + regmap_pre[i+1][hr]=rs1[i+1]; + regs[i+1].regmap_entry[hr]=rs1[i+1]; + regs[i].isconst&=~(1<=0) + { + // move it to another register + regs[i+1].regmap[hr]=-1; + regmap_pre[i+2][hr]=-1; + regs[i+1].regmap[nr]=FTEMP; + regmap_pre[i+2][nr]=FTEMP; + regs[i].regmap[nr]=rs1[i+1]; + regmap_pre[i+1][nr]=rs1[i+1]; + regs[i+1].regmap_entry[nr]=rs1[i+1]; + regs[i].isconst&=~(1<=0&®s[i].regmap[hr]<0) { + int rs=get_reg(regs[i+1].regmap,rs1[i+1]); + if(rs>=0&&((regs[i+1].wasconst>>rs)&1)) { + regs[i].regmap[hr]=AGEN1+((i+1)&1); + regmap_pre[i+1][hr]=AGEN1+((i+1)&1); + regs[i+1].regmap_entry[hr]=AGEN1+((i+1)&1); + regs[i].isconst&=~(1<=0;i--) + { + int hr; + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + if(ba[i]=(start+slen*4)) + { + // Branch out of this block, don't need anything + r32=0; + } + else + { + // Internal branch + // Need whatever matches the target + // (and doesn't get overwritten by the delay slot instruction) + r32=0; + int t=(ba[i]-start)>>2; + if(ba[i]>start+i*4) { + // Forward branch + if(!(requires_32bit[t]&~regs[i].was32)) + r32|=requires_32bit[t]&(~(1LL<>16)!=0x1000) + { + if(i0) + { + if((regs[i].was32>>us1[i+1])&1) r32|=1LL<0) + { + if((regs[i].was32>>us2[i+1])&1) r32|=1LL<>dep1[i+1])&1)) + { + if((regs[i].was32>>dep1[i+1])&1) r32|=1LL<>dep2[i+1])&1)) + { + if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<0) + { + if((regs[i].was32>>us1[i])&1) r32|=1LL<0) + { + if((regs[i].was32>>us2[i])&1) r32|=1LL<>dep1[i])&1)) + { + if((regs[i].was32>>dep1[i])&1) r32|=1LL<>dep2[i])&1)) + { + if((regs[i].was32>>dep2[i])&1) r32|=1LL<0&®s[i].regmap_entry[hr]<64) { + if((regs[i].was32>>regs[i].regmap_entry[hr])&(regs[i].wasdirty>>hr)&1) { + if(!((unneeded_reg_upper[i]>>regs[i].regmap_entry[hr])&1)) + requires_32bit[i]|=1LL<>r)&1) { + if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + DebugMessage(M64MSG_VERBOSE, " UU:"); + for(r=1;r<=CCREG;r++) { + if(((unneeded_reg_upper[i]&~unneeded_reg[i])>>r)&1) { + if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + DebugMessage(M64MSG_VERBOSE, " 32:"); + for(r=0;r<=CCREG;r++) { + //if(((is32[i]>>r)&(~unneeded_reg[i]>>r))&1) { + if((regs[i].was32>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + #if NEW_DYNAREC == NEW_DYNAREC_X86 + DebugMessage(M64MSG_VERBOSE, "pre: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",regmap_pre[i][0],regmap_pre[i][1],regmap_pre[i][2],regmap_pre[i][3],regmap_pre[i][5],regmap_pre[i][6],regmap_pre[i][7]); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + DebugMessage(M64MSG_VERBOSE, "pre: r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d",regmap_pre[i][0],regmap_pre[i][1],regmap_pre[i][2],regmap_pre[i][3],regmap_pre[i][4],regmap_pre[i][5],regmap_pre[i][6],regmap_pre[i][7],regmap_pre[i][8],regmap_pre[i][9],regmap_pre[i][10],regmap_pre[i][12]); + #endif + DebugMessage(M64MSG_VERBOSE, "needs: "); + if(needed_reg[i]&1) DebugMessage(M64MSG_VERBOSE, "eax "); + if((needed_reg[i]>>1)&1) DebugMessage(M64MSG_VERBOSE, "ecx "); + if((needed_reg[i]>>2)&1) DebugMessage(M64MSG_VERBOSE, "edx "); + if((needed_reg[i]>>3)&1) DebugMessage(M64MSG_VERBOSE, "ebx "); + if((needed_reg[i]>>5)&1) DebugMessage(M64MSG_VERBOSE, "ebp "); + if((needed_reg[i]>>6)&1) DebugMessage(M64MSG_VERBOSE, "esi "); + if((needed_reg[i]>>7)&1) DebugMessage(M64MSG_VERBOSE, "edi "); + DebugMessage(M64MSG_VERBOSE, "r:"); + for(r=0;r<=CCREG;r++) { + //if(((requires_32bit[i]>>r)&(~unneeded_reg[i]>>r))&1) { + if((requires_32bit[i]>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + /*DebugMessage(M64MSG_VERBOSE, "pr:"); + for(r=0;r<=CCREG;r++) { + //if(((requires_32bit[i]>>r)&(~unneeded_reg[i]>>r))&1) { + if((pr32[i]>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + if(pr32[i]!=requires_32bit[i]) DebugMessage(M64MSG_ERROR, " OOPS");*/ + #if NEW_DYNAREC == NEW_DYNAREC_X86 + DebugMessage(M64MSG_VERBOSE, "entry: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d",regs[i].regmap_entry[0],regs[i].regmap_entry[1],regs[i].regmap_entry[2],regs[i].regmap_entry[3],regs[i].regmap_entry[5],regs[i].regmap_entry[6],regs[i].regmap_entry[7]); + DebugMessage(M64MSG_VERBOSE, "dirty: "); + if(regs[i].wasdirty&1) DebugMessage(M64MSG_VERBOSE, "eax "); + if((regs[i].wasdirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "ecx "); + if((regs[i].wasdirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "edx "); + if((regs[i].wasdirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "ebx "); + if((regs[i].wasdirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "ebp "); + if((regs[i].wasdirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "esi "); + if((regs[i].wasdirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "edi "); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + DebugMessage(M64MSG_VERBOSE, "entry: r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d",regs[i].regmap_entry[0],regs[i].regmap_entry[1],regs[i].regmap_entry[2],regs[i].regmap_entry[3],regs[i].regmap_entry[4],regs[i].regmap_entry[5],regs[i].regmap_entry[6],regs[i].regmap_entry[7],regs[i].regmap_entry[8],regs[i].regmap_entry[9],regs[i].regmap_entry[10],regs[i].regmap_entry[12]); + DebugMessage(M64MSG_VERBOSE, "dirty: "); + if(regs[i].wasdirty&1) DebugMessage(M64MSG_VERBOSE, "r0 "); + if((regs[i].wasdirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "r1 "); + if((regs[i].wasdirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "r2 "); + if((regs[i].wasdirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "r3 "); + if((regs[i].wasdirty>>4)&1) DebugMessage(M64MSG_VERBOSE, "r4 "); + if((regs[i].wasdirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "r5 "); + if((regs[i].wasdirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "r6 "); + if((regs[i].wasdirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "r7 "); + if((regs[i].wasdirty>>8)&1) DebugMessage(M64MSG_VERBOSE, "r8 "); + if((regs[i].wasdirty>>9)&1) DebugMessage(M64MSG_VERBOSE, "r9 "); + if((regs[i].wasdirty>>10)&1) DebugMessage(M64MSG_VERBOSE, "r10 "); + if((regs[i].wasdirty>>12)&1) DebugMessage(M64MSG_VERBOSE, "r12 "); + #endif + disassemble_inst(i); + //printf ("ccadj[%d] = %d",i,ccadj[i]); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + DebugMessage(M64MSG_VERBOSE, "eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d dirty: ",regs[i].regmap[0],regs[i].regmap[1],regs[i].regmap[2],regs[i].regmap[3],regs[i].regmap[5],regs[i].regmap[6],regs[i].regmap[7]); + if(regs[i].dirty&1) DebugMessage(M64MSG_VERBOSE, "eax "); + if((regs[i].dirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "ecx "); + if((regs[i].dirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "edx "); + if((regs[i].dirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "ebx "); + if((regs[i].dirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "ebp "); + if((regs[i].dirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "esi "); + if((regs[i].dirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "edi "); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + DebugMessage(M64MSG_VERBOSE, "r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d dirty: ",regs[i].regmap[0],regs[i].regmap[1],regs[i].regmap[2],regs[i].regmap[3],regs[i].regmap[4],regs[i].regmap[5],regs[i].regmap[6],regs[i].regmap[7],regs[i].regmap[8],regs[i].regmap[9],regs[i].regmap[10],regs[i].regmap[12]); + if(regs[i].dirty&1) DebugMessage(M64MSG_VERBOSE, "r0 "); + if((regs[i].dirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "r1 "); + if((regs[i].dirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "r2 "); + if((regs[i].dirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "r3 "); + if((regs[i].dirty>>4)&1) DebugMessage(M64MSG_VERBOSE, "r4 "); + if((regs[i].dirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "r5 "); + if((regs[i].dirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "r6 "); + if((regs[i].dirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "r7 "); + if((regs[i].dirty>>8)&1) DebugMessage(M64MSG_VERBOSE, "r8 "); + if((regs[i].dirty>>9)&1) DebugMessage(M64MSG_VERBOSE, "r9 "); + if((regs[i].dirty>>10)&1) DebugMessage(M64MSG_VERBOSE, "r10 "); + if((regs[i].dirty>>12)&1) DebugMessage(M64MSG_VERBOSE, "r12 "); + #endif + if(regs[i].isconst) { + DebugMessage(M64MSG_VERBOSE, "constants: "); + #if NEW_DYNAREC == NEW_DYNAREC_X86 + if(regs[i].isconst&1) DebugMessage(M64MSG_VERBOSE, "eax=%x ",(int)constmap[i][0]); + if((regs[i].isconst>>1)&1) DebugMessage(M64MSG_VERBOSE, "ecx=%x ",(int)constmap[i][1]); + if((regs[i].isconst>>2)&1) DebugMessage(M64MSG_VERBOSE, "edx=%x ",(int)constmap[i][2]); + if((regs[i].isconst>>3)&1) DebugMessage(M64MSG_VERBOSE, "ebx=%x ",(int)constmap[i][3]); + if((regs[i].isconst>>5)&1) DebugMessage(M64MSG_VERBOSE, "ebp=%x ",(int)constmap[i][5]); + if((regs[i].isconst>>6)&1) DebugMessage(M64MSG_VERBOSE, "esi=%x ",(int)constmap[i][6]); + if((regs[i].isconst>>7)&1) DebugMessage(M64MSG_VERBOSE, "edi=%x ",(int)constmap[i][7]); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + if(regs[i].isconst&1) DebugMessage(M64MSG_VERBOSE, "r0=%x ",(int)constmap[i][0]); + if((regs[i].isconst>>1)&1) DebugMessage(M64MSG_VERBOSE, "r1=%x ",(int)constmap[i][1]); + if((regs[i].isconst>>2)&1) DebugMessage(M64MSG_VERBOSE, "r2=%x ",(int)constmap[i][2]); + if((regs[i].isconst>>3)&1) DebugMessage(M64MSG_VERBOSE, "r3=%x ",(int)constmap[i][3]); + if((regs[i].isconst>>4)&1) DebugMessage(M64MSG_VERBOSE, "r4=%x ",(int)constmap[i][4]); + if((regs[i].isconst>>5)&1) DebugMessage(M64MSG_VERBOSE, "r5=%x ",(int)constmap[i][5]); + if((regs[i].isconst>>6)&1) DebugMessage(M64MSG_VERBOSE, "r6=%x ",(int)constmap[i][6]); + if((regs[i].isconst>>7)&1) DebugMessage(M64MSG_VERBOSE, "r7=%x ",(int)constmap[i][7]); + if((regs[i].isconst>>8)&1) DebugMessage(M64MSG_VERBOSE, "r8=%x ",(int)constmap[i][8]); + if((regs[i].isconst>>9)&1) DebugMessage(M64MSG_VERBOSE, "r9=%x ",(int)constmap[i][9]); + if((regs[i].isconst>>10)&1) DebugMessage(M64MSG_VERBOSE, "r10=%x ",(int)constmap[i][10]); + if((regs[i].isconst>>12)&1) DebugMessage(M64MSG_VERBOSE, "r12=%x ",(int)constmap[i][12]); + #endif + } + DebugMessage(M64MSG_VERBOSE, " 32:"); + for(r=0;r<=CCREG;r++) { + if((regs[i].is32>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + /*DebugMessage(M64MSG_VERBOSE, " p32:"); + for(r=0;r<=CCREG;r++) { + if((p32[i]>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + if(p32[i]!=regs[i].is32) DebugMessage(M64MSG_VERBOSE, " NO MATCH");*/ + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { + #if NEW_DYNAREC == NEW_DYNAREC_X86 + DebugMessage(M64MSG_VERBOSE, "branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d dirty: ",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); + if(branch_regs[i].dirty&1) DebugMessage(M64MSG_VERBOSE, "eax "); + if((branch_regs[i].dirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "ecx "); + if((branch_regs[i].dirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "edx "); + if((branch_regs[i].dirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "ebx "); + if((branch_regs[i].dirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "ebp "); + if((branch_regs[i].dirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "esi "); + if((branch_regs[i].dirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "edi "); + #endif + #if NEW_DYNAREC == NEW_DYNAREC_ARM + DebugMessage(M64MSG_VERBOSE, "branch(%d): r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d dirty: ",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[4],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7],branch_regs[i].regmap[8],branch_regs[i].regmap[9],branch_regs[i].regmap[10],branch_regs[i].regmap[12]); + if(branch_regs[i].dirty&1) DebugMessage(M64MSG_VERBOSE, "r0 "); + if((branch_regs[i].dirty>>1)&1) DebugMessage(M64MSG_VERBOSE, "r1 "); + if((branch_regs[i].dirty>>2)&1) DebugMessage(M64MSG_VERBOSE, "r2 "); + if((branch_regs[i].dirty>>3)&1) DebugMessage(M64MSG_VERBOSE, "r3 "); + if((branch_regs[i].dirty>>4)&1) DebugMessage(M64MSG_VERBOSE, "r4 "); + if((branch_regs[i].dirty>>5)&1) DebugMessage(M64MSG_VERBOSE, "r5 "); + if((branch_regs[i].dirty>>6)&1) DebugMessage(M64MSG_VERBOSE, "r6 "); + if((branch_regs[i].dirty>>7)&1) DebugMessage(M64MSG_VERBOSE, "r7 "); + if((branch_regs[i].dirty>>8)&1) DebugMessage(M64MSG_VERBOSE, "r8 "); + if((branch_regs[i].dirty>>9)&1) DebugMessage(M64MSG_VERBOSE, "r9 "); + if((branch_regs[i].dirty>>10)&1) DebugMessage(M64MSG_VERBOSE, "r10 "); + if((branch_regs[i].dirty>>12)&1) DebugMessage(M64MSG_VERBOSE, "r12 "); + #endif + DebugMessage(M64MSG_VERBOSE, " 32:"); + for(r=0;r<=CCREG;r++) { + if((branch_regs[i].is32>>r)&1) { + if(r==CCREG) DebugMessage(M64MSG_VERBOSE, " CC"); + else if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); + else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); + else DebugMessage(M64MSG_VERBOSE, " r%d",r); + } + } + } + } +#endif + + /* Pass 8 - Assembly */ + linkcount=0;stubcount=0; + ds=0;is_delayslot=0; + cop1_usable=0; + #ifndef DESTRUCTIVE_WRITEBACK + uint64_t is32_pre=0; + u_int dirty_pre=0; + #endif + u_int beginning=(u_int)out; + if((u_int)addr&1) { + ds=1; + pagespan_ds(); + } + for(i=0;i>16)!=0x1000)) + { + wb_sx(regmap_pre[i],regs[i].regmap_entry,regs[i].wasdirty,is32_pre,regs[i].was32, + unneeded_reg[i],unneeded_reg_upper[i]); + wb_valid(regmap_pre[i],regs[i].regmap_entry,dirty_pre,regs[i].wasdirty,is32_pre, + unneeded_reg[i],unneeded_reg_upper[i]); + } + is32_pre=regs[i].is32; + dirty_pre=regs[i].dirty; + #endif + // write back + if(i<2||(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000)) + { + wb_invalidate(regmap_pre[i],regs[i].regmap_entry,regs[i].wasdirty,regs[i].was32, + unneeded_reg[i],unneeded_reg_upper[i]); + loop_preload(regmap_pre[i],regs[i].regmap_entry); + } + // branch target entry point + instr_addr[i]=(u_int)out; + assem_debug("<->"); + // load regs + if(regs[i].regmap_entry[HOST_CCREG]==CCREG&®s[i].regmap[HOST_CCREG]!=CCREG) + wb_register(CCREG,regs[i].regmap_entry,regs[i].wasdirty,regs[i].was32); + load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i],rs2[i]); + address_generation(i,®s[i],regs[i].regmap_entry); + load_consts(regmap_pre[i],regs[i].regmap,regs[i].was32,i); + if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + // Load the delay slot registers if necessary + if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]) + load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]); + if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]) + load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]); + if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39) + load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP); + } + else if(i+1>16)==0x1000) + literal_pool(1024); + else + literal_pool_jumpover(256); + } + } + //assert(itype[i-2]==UJUMP||itype[i-2]==RJUMP||(source[i-2]>>16)==0x1000); + // If the block did not end with an unconditional branch, + // add a jump to the next instruction. + if(i>1) { + if(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000&&itype[i-1]!=SPAN) { + assert(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP); + assert(i==slen); + if(itype[i-2]!=CJUMP&&itype[i-2]!=SJUMP&&itype[i-2]!=FJUMP) { + store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); + if(regs[i-1].regmap[HOST_CCREG]!=CCREG) + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); + } + else if(!likely[i-2]) + { + store_regs_bt(branch_regs[i-2].regmap,branch_regs[i-2].is32,branch_regs[i-2].dirty,start+i*4); + assert(branch_regs[i-2].regmap[HOST_CCREG]==CCREG); + } + else + { + store_regs_bt(regs[i-2].regmap,regs[i-2].is32,regs[i-2].dirty,start+i*4); + assert(regs[i-2].regmap[HOST_CCREG]==CCREG); + } + add_to_linker((int)out,start+i*4,0); + emit_jmp(0); + } + } + else + { + assert(i>0); + assert(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP); + store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); + if(regs[i-1].regmap[HOST_CCREG]!=CCREG) + emit_loadreg(CCREG,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); + add_to_linker((int)out,start+i*4,0); + emit_jmp(0); + } + + // TODO: delay slot stubs? + // Stubs + for(i=0;i %8x",link_addr[i][0],link_addr[i][1]); + literal_pool(64); + if(!link_addr[i][2]) + { + void *stub=out; + void *addr=check_addr(link_addr[i][1]); + emit_extjump(link_addr[i][0],link_addr[i][1]); + if(addr) { + set_jump_target(link_addr[i][0],(int)addr); + add_link(link_addr[i][1],stub); + } + else set_jump_target(link_addr[i][0],(int)stub); + } + else + { + // Internal branch + int target=(link_addr[i][1]-start)>>2; + assert(target>=0&&target>1); + //#else + set_jump_target(link_addr[i][0],instr_addr[target]); + //#endif + } + } + // External Branch Targets (jump_in) + if(copy+slen*4>shadow+sizeof(shadow)) copy=shadow; + for(i=0;i>12; + u_int vpage=page; + if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[page^0x80000]^0x80000000)>>12; + if(page>2048) page=2048+(page&2047); + if(vpage>262143&&tlb_LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead + if(vpage>2048) vpage=2048+(vpage&2047); + literal_pool(256); + //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<>16)^vaddr)&0xFFFF]; + if(ht_bin[0]==vaddr) { + ht_bin[1]=entry_point; + } + if(ht_bin[2]==vaddr) { + ht_bin[3]=entry_point; + } + } + else + { + u_int r=requires_32bit[i]|!!(requires_32bit[i]>>32); + assem_debug("%8x (%d) <- %8x",instr_addr[i],i,start+i*4); + assem_debug("jump_in: %x (restricted - %x)",start+i*4,r); + //int entry_point=(int)out; + ////assem_debug("entry_point: %x",entry_point); + //load_regs_entry(i); + //if(entry_point==(int)out) + // entry_point=instr_addr[i]; + //else + // emit_jmp(instr_addr[i]); + //ll_add_32(jump_in+page,vaddr,r,(void *)entry_point); + ll_add_32(jump_dirty+vpage,vaddr,r,(void *)out); + int entry_point=do_dirty_stub(i); + ll_add_32(jump_in+page,vaddr,r,(void *)entry_point); + } + } + } + } + // Write out the literal pool if necessary + literal_pool(0); + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + // Align code + if(((u_int)out)&7) emit_addnop(13); + #endif + assert((u_int)out-beginning (u_char *)((u_char *)base_addr+(1<>12;i<=(int)((start+slen*4)>>12);i++) { + invalid_code[i]=0; + memory_map[i]|=0x40000000; + if((signed int)start>=(signed int)0xC0000000) { + assert(using_tlb); + j=(((u_int)i<<12)+(memory_map[i]<<2)-(u_int)g_rdram+(u_int)0x80000000)>>12; + invalid_code[j]=0; + memory_map[j]|=0x40000000; + //DebugMessage(M64MSG_VERBOSE, "write protect physical page: %x (virtual %x)",j<<12,start); + } + } + + /* Pass 10 - Free memory by expiring oldest blocks */ + + int end=((((intptr_t)out-(intptr_t)base_addr)>>(TARGET_SIZE_2-16))+16384)&65535; + while(expirep!=end) + { + int shift=TARGET_SIZE_2-3; // Divide into 8 blocks + int base=(int)base_addr+((expirep>>13)<>11)&3) + { + case 0: + // Clear jump_in and jump_dirty + ll_remove_matching_addrs(jump_in+(expirep&2047),base,shift); + ll_remove_matching_addrs(jump_dirty+(expirep&2047),base,shift); + ll_remove_matching_addrs(jump_in+2048+(expirep&2047),base,shift); + ll_remove_matching_addrs(jump_dirty+2048+(expirep&2047),base,shift); + break; + case 1: + // Clear pointers + ll_kill_pointers(jump_out[expirep&2047],base,shift); + ll_kill_pointers(jump_out[(expirep&2047)+2048],base,shift); + break; + case 2: + // Clear hash table + for(i=0;i<32;i++) { + u_int *ht_bin=hash_table[((expirep&2047)<<5)+i]; + if(((ht_bin[3]-(u_int)base_addr)>>shift)==((base-(u_int)base_addr)>>shift) || + ((ht_bin[3]-(u_int)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((base-(u_int)base_addr)>>shift)) { + inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[2],ht_bin[3]); + ht_bin[2]=ht_bin[3]=-1; + } + if(((ht_bin[1]-(u_int)base_addr)>>shift)==((base-(u_int)base_addr)>>shift) || + ((ht_bin[1]-(u_int)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((base-(u_int)base_addr)>>shift)) { + inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[0],ht_bin[1]); + ht_bin[0]=ht_bin[2]; + ht_bin[1]=ht_bin[3]; + ht_bin[2]=ht_bin[3]=-1; + } + } + break; + case 3: + // Clear jump_out + #if NEW_DYNAREC == NEW_DYNAREC_ARM + if((expirep&2047)==0) + do_clear_cache(); + #endif + ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift); + ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift); + break; + } + expirep=(expirep+1)&65535; + } + return 0; +} + +void TLBWI_new(void) +{ + unsigned int i; + /* Remove old entries */ + unsigned int old_start_even=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_even; + unsigned int old_end_even=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_even; + unsigned int old_start_odd=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_odd; + unsigned int old_end_odd=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_odd; + for (i=old_start_even>>12; i<=old_end_even>>12; i++) + { + if(i<0x80000||i>0xBFFFF) + { + invalidate_block(i); + memory_map[i]=-1; + } + } + for (i=old_start_odd>>12; i<=old_end_odd>>12; i++) + { + if(i<0x80000||i>0xBFFFF) + { + invalidate_block(i); + memory_map[i]=-1; + } + } + cached_interpreter_table.TLBWI(); + //DebugMessage(M64MSG_VERBOSE, "TLBWI: index=%d",g_cp0_regs[CP0_INDEX_REG]); + //DebugMessage(M64MSG_VERBOSE, "TLBWI: start_even=%x end_even=%x phys_even=%x v=%d d=%d",tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_even,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_even,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].phys_even,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].v_even,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].d_even); + //DebugMessage(M64MSG_VERBOSE, "TLBWI: start_odd=%x end_odd=%x phys_odd=%x v=%d d=%d",tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_odd,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_odd,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].phys_odd,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].v_odd,tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].d_odd); + /* Combine tlb_LUT_r, tlb_LUT_w, and invalid_code into a single table + for fast look up. */ + for (i=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_even>>12; i<=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_even>>12; i++) + { + //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,tlb_LUT_r[i],tlb_LUT_w[i]); + if(i<0x80000||i>0xBFFFF) + { + if(tlb_LUT_r[i]) { + memory_map[i]=((tlb_LUT_r[i]&0xFFFFF000)-(i<<12)+(unsigned int)g_rdram-0x80000000)>>2; + // FIXME: should make sure the physical page is invalid too + if(!tlb_LUT_w[i]||!invalid_code[i]) { + memory_map[i]|=0x40000000; // Write protect + }else{ + assert(tlb_LUT_r[i]==tlb_LUT_w[i]); + } + if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); + // Tell the dynamic recompiler to generate tlb lookup code + using_tlb=1; + } + else memory_map[i]=-1; + } + //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,memory_map[i],memory_map[i]<<2); + } + for (i=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].start_odd>>12; i<=tlb_e[g_cp0_regs[CP0_INDEX_REG]&0x3F].end_odd>>12; i++) + { + //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,tlb_LUT_r[i],tlb_LUT_w[i]); + if(i<0x80000||i>0xBFFFF) + { + if(tlb_LUT_r[i]) { + memory_map[i]=((tlb_LUT_r[i]&0xFFFFF000)-(i<<12)+(unsigned int)g_rdram-0x80000000)>>2; + // FIXME: should make sure the physical page is invalid too + if(!tlb_LUT_w[i]||!invalid_code[i]) { + memory_map[i]|=0x40000000; // Write protect + }else{ + assert(tlb_LUT_r[i]==tlb_LUT_w[i]); + } + if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); + // Tell the dynamic recompiler to generate tlb lookup code + using_tlb=1; + } + else memory_map[i]=-1; + } + //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,memory_map[i],memory_map[i]<<2); + } +} + +void TLBWR_new(void) +{ + unsigned int i; + g_cp0_regs[CP0_RANDOM_REG] = (g_cp0_regs[CP0_COUNT_REG]/2 % (32 - g_cp0_regs[CP0_WIRED_REG])) + g_cp0_regs[CP0_WIRED_REG]; + /* Remove old entries */ + unsigned int old_start_even=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].start_even; + unsigned int old_end_even=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].end_even; + unsigned int old_start_odd=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].start_odd; + unsigned int old_end_odd=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].end_odd; + for (i=old_start_even>>12; i<=old_end_even>>12; i++) + { + if(i<0x80000||i>0xBFFFF) + { + invalidate_block(i); + memory_map[i]=-1; + } + } + for (i=old_start_odd>>12; i<=old_end_odd>>12; i++) + { + if(i<0x80000||i>0xBFFFF) + { + invalidate_block(i); + memory_map[i]=-1; + } + } + cached_interpreter_table.TLBWR(); + /* Combine tlb_LUT_r, tlb_LUT_w, and invalid_code into a single table + for fast look up. */ + for (i=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].start_even>>12; i<=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].end_even>>12; i++) + { + //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,tlb_LUT_r[i],tlb_LUT_w[i]); + if(i<0x80000||i>0xBFFFF) + { + if(tlb_LUT_r[i]) { + memory_map[i]=((tlb_LUT_r[i]&0xFFFFF000)-(i<<12)+(unsigned int)g_rdram-0x80000000)>>2; + // FIXME: should make sure the physical page is invalid too + if(!tlb_LUT_w[i]||!invalid_code[i]) { + memory_map[i]|=0x40000000; // Write protect + }else{ + assert(tlb_LUT_r[i]==tlb_LUT_w[i]); + } + if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); + // Tell the dynamic recompiler to generate tlb lookup code + using_tlb=1; + } + else memory_map[i]=-1; + } + //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,memory_map[i],memory_map[i]<<2); + } + for (i=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].start_odd>>12; i<=tlb_e[g_cp0_regs[CP0_RANDOM_REG]&0x3F].end_odd>>12; i++) + { + //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,tlb_LUT_r[i],tlb_LUT_w[i]); + if(i<0x80000||i>0xBFFFF) + { + if(tlb_LUT_r[i]) { + memory_map[i]=((tlb_LUT_r[i]&0xFFFFF000)-(i<<12)+(unsigned int)g_rdram-0x80000000)>>2; + // FIXME: should make sure the physical page is invalid too + if(!tlb_LUT_w[i]||!invalid_code[i]) { + memory_map[i]|=0x40000000; // Write protect + }else{ + assert(tlb_LUT_r[i]==tlb_LUT_w[i]); + } + if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); + // Tell the dynamic recompiler to generate tlb lookup code + using_tlb=1; + } + else memory_map[i]=-1; + } + //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,memory_map[i],memory_map[i]<<2); + } +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.h b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.h new file mode 100644 index 000000000..db48770c0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/new_dynarec/new_dynarec.h @@ -0,0 +1,44 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - new_dynarec.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_NEW_DYNAREC_H +#define M64P_R4300_NEW_DYNAREC_H + +#define NEW_DYNAREC_X86 1 +#define NEW_DYNAREC_AMD64 2 +#define NEW_DYNAREC_ARM 3 + +#ifdef __cplusplus +extern "C" { +#endif +extern int pcaddr; +extern int pending_exception; +#ifdef __cplusplus +} +#endif + +void invalidate_all_pages(void); +void invalidate_block(unsigned int block); +void new_dynarec_init(void); +void new_dyna_start(void); +void new_dynarec_cleanup(void); + +#endif /* M64P_R4300_NEW_DYNAREC_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/ops.h b/Frameworks/lazyusf/lazyusf/r4300/ops.h new file mode 100644 index 000000000..f4efcd8ea --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/ops.h @@ -0,0 +1,327 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - ops.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_OPS_H +#define M64P_R4300_OPS_H + +#include "osal/preproc.h" + +typedef struct _cpu_instruction_table +{ + /* All jump/branch instructions (except JR and JALR) have three versions: + * - JUMPNAME() which for jumps inside the current block. + * - JUMPNAME_OUT() which jumps outside the current block. + * - JUMPNAME_IDLE() which does busy wait optimization. + * + * Busy wait optimization is used when a jump jumps to itself, + * and the instruction on the delay slot is a NOP. + * The program is waiting for the next interrupt, so we can just + * increase Count until the point where the next interrupt happens. */ + + // Load and store instructions + void (osal_fastcall *LB)(usf_state_t *); + void (osal_fastcall *LBU)(usf_state_t *); + void (osal_fastcall *LH)(usf_state_t *); + void (osal_fastcall *LHU)(usf_state_t *); + void (osal_fastcall *LW)(usf_state_t *); + void (osal_fastcall *LWL)(usf_state_t *); + void (osal_fastcall *LWR)(usf_state_t *); + void (osal_fastcall *SB)(usf_state_t *); + void (osal_fastcall *SH)(usf_state_t *); + void (osal_fastcall *SW)(usf_state_t *); + void (osal_fastcall *SWL)(usf_state_t *); + void (osal_fastcall *SWR)(usf_state_t *); + + void (osal_fastcall *LD)(usf_state_t *); + void (osal_fastcall *LDL)(usf_state_t *); + void (osal_fastcall *LDR)(usf_state_t *); + void (osal_fastcall *LL)(usf_state_t *); + void (osal_fastcall *LWU)(usf_state_t *); + void (osal_fastcall *SC)(usf_state_t *); + void (osal_fastcall *SD)(usf_state_t *); + void (osal_fastcall *SDL)(usf_state_t *); + void (osal_fastcall *SDR)(usf_state_t *); + void (osal_fastcall *SYNC)(usf_state_t *); + + // Arithmetic instructions (ALU immediate) + void (osal_fastcall *ADDI)(usf_state_t *); + void (osal_fastcall *ADDIU)(usf_state_t *); + void (osal_fastcall *SLTI)(usf_state_t *); + void (osal_fastcall *SLTIU)(usf_state_t *); + void (osal_fastcall *ANDI)(usf_state_t *); + void (osal_fastcall *ORI)(usf_state_t *); + void (osal_fastcall *XORI)(usf_state_t *); + void (osal_fastcall *LUI)(usf_state_t *); + + void (osal_fastcall *DADDI)(usf_state_t *); + void (osal_fastcall *DADDIU)(usf_state_t *); + + // Arithmetic instructions (3-operand) + void (osal_fastcall *ADD)(usf_state_t *); + void (osal_fastcall *ADDU)(usf_state_t *); + void (osal_fastcall *SUB)(usf_state_t *); + void (osal_fastcall *SUBU)(usf_state_t *); + void (osal_fastcall *SLT)(usf_state_t *); + void (osal_fastcall *SLTU)(usf_state_t *); + void (osal_fastcall *AND)(usf_state_t *); + void (osal_fastcall *OR)(usf_state_t *); + void (osal_fastcall *XOR)(usf_state_t *); + void (osal_fastcall *NOR)(usf_state_t *); + + void (osal_fastcall *DADD)(usf_state_t *); + void (osal_fastcall *DADDU)(usf_state_t *); + void (osal_fastcall *DSUB)(usf_state_t *); + void (osal_fastcall *DSUBU)(usf_state_t *); + + // Multiply and divide instructions + void (osal_fastcall *MULT)(usf_state_t *); + void (osal_fastcall *MULTU)(usf_state_t *); + void (osal_fastcall *DIV)(usf_state_t *); + void (osal_fastcall *DIVU)(usf_state_t *); + void (osal_fastcall *MFHI)(usf_state_t *); + void (osal_fastcall *MTHI)(usf_state_t *); + void (osal_fastcall *MFLO)(usf_state_t *); + void (osal_fastcall *MTLO)(usf_state_t *); + + void (osal_fastcall *DMULT)(usf_state_t *); + void (osal_fastcall *DMULTU)(usf_state_t *); + void (osal_fastcall *DDIV)(usf_state_t *); + void (osal_fastcall *DDIVU)(usf_state_t *); + + // Jump and branch instructions + void (osal_fastcall *J)(usf_state_t *); + void (osal_fastcall *J_OUT)(usf_state_t *); + void (osal_fastcall *J_IDLE)(usf_state_t *); + void (osal_fastcall *JAL)(usf_state_t *); + void (osal_fastcall *JAL_OUT)(usf_state_t *); + void (osal_fastcall *JAL_IDLE)(usf_state_t *); + void (osal_fastcall *JR)(usf_state_t *); + void (osal_fastcall *JALR)(usf_state_t *); + void (osal_fastcall *BEQ)(usf_state_t *); + void (osal_fastcall *BEQ_OUT)(usf_state_t *); + void (osal_fastcall *BEQ_IDLE)(usf_state_t *); + void (osal_fastcall *BNE)(usf_state_t *); + void (osal_fastcall *BNE_OUT)(usf_state_t *); + void (osal_fastcall *BNE_IDLE)(usf_state_t *); + void (osal_fastcall *BLEZ)(usf_state_t *); + void (osal_fastcall *BLEZ_OUT)(usf_state_t *); + void (osal_fastcall *BLEZ_IDLE)(usf_state_t *); + void (osal_fastcall *BGTZ)(usf_state_t *); + void (osal_fastcall *BGTZ_OUT)(usf_state_t *); + void (osal_fastcall *BGTZ_IDLE)(usf_state_t *); + void (osal_fastcall *BLTZ)(usf_state_t *); + void (osal_fastcall *BLTZ_OUT)(usf_state_t *); + void (osal_fastcall *BLTZ_IDLE)(usf_state_t *); + void (osal_fastcall *BGEZ)(usf_state_t *); + void (osal_fastcall *BGEZ_OUT)(usf_state_t *); + void (osal_fastcall *BGEZ_IDLE)(usf_state_t *); + void (osal_fastcall *BLTZAL)(usf_state_t *); + void (osal_fastcall *BLTZAL_OUT)(usf_state_t *); + void (osal_fastcall *BLTZAL_IDLE)(usf_state_t *); + void (osal_fastcall *BGEZAL)(usf_state_t *); + void (osal_fastcall *BGEZAL_OUT)(usf_state_t *); + void (osal_fastcall *BGEZAL_IDLE)(usf_state_t *); + + void (osal_fastcall *BEQL)(usf_state_t *); + void (osal_fastcall *BEQL_OUT)(usf_state_t *); + void (osal_fastcall *BEQL_IDLE)(usf_state_t *); + void (osal_fastcall *BNEL)(usf_state_t *); + void (osal_fastcall *BNEL_OUT)(usf_state_t *); + void (osal_fastcall *BNEL_IDLE)(usf_state_t *); + void (osal_fastcall *BLEZL)(usf_state_t *); + void (osal_fastcall *BLEZL_OUT)(usf_state_t *); + void (osal_fastcall *BLEZL_IDLE)(usf_state_t *); + void (osal_fastcall *BGTZL)(usf_state_t *); + void (osal_fastcall *BGTZL_OUT)(usf_state_t *); + void (osal_fastcall *BGTZL_IDLE)(usf_state_t *); + void (osal_fastcall *BLTZL)(usf_state_t *); + void (osal_fastcall *BLTZL_OUT)(usf_state_t *); + void (osal_fastcall *BLTZL_IDLE)(usf_state_t *); + void (osal_fastcall *BGEZL)(usf_state_t *); + void (osal_fastcall *BGEZL_OUT)(usf_state_t *); + void (osal_fastcall *BGEZL_IDLE)(usf_state_t *); + void (osal_fastcall *BLTZALL)(usf_state_t *); + void (osal_fastcall *BLTZALL_OUT)(usf_state_t *); + void (osal_fastcall *BLTZALL_IDLE)(usf_state_t *); + void (osal_fastcall *BGEZALL)(usf_state_t *); + void (osal_fastcall *BGEZALL_OUT)(usf_state_t *); + void (osal_fastcall *BGEZALL_IDLE)(usf_state_t *); + void (osal_fastcall *BC1TL)(usf_state_t *); + void (osal_fastcall *BC1TL_OUT)(usf_state_t *); + void (osal_fastcall *BC1TL_IDLE)(usf_state_t *); + void (osal_fastcall *BC1FL)(usf_state_t *); + void (osal_fastcall *BC1FL_OUT)(usf_state_t *); + void (osal_fastcall *BC1FL_IDLE)(usf_state_t *); + + // Shift instructions + void (osal_fastcall *SLL)(usf_state_t *); + void (osal_fastcall *SRL)(usf_state_t *); + void (osal_fastcall *SRA)(usf_state_t *); + void (osal_fastcall *SLLV)(usf_state_t *); + void (osal_fastcall *SRLV)(usf_state_t *); + void (osal_fastcall *SRAV)(usf_state_t *); + + void (osal_fastcall *DSLL)(usf_state_t *); + void (osal_fastcall *DSRL)(usf_state_t *); + void (osal_fastcall *DSRA)(usf_state_t *); + void (osal_fastcall *DSLLV)(usf_state_t *); + void (osal_fastcall *DSRLV)(usf_state_t *); + void (osal_fastcall *DSRAV)(usf_state_t *); + void (osal_fastcall *DSLL32)(usf_state_t *); + void (osal_fastcall *DSRL32)(usf_state_t *); + void (osal_fastcall *DSRA32)(usf_state_t *); + + // COP0 instructions + void (osal_fastcall *MTC0)(usf_state_t *); + void (osal_fastcall *MFC0)(usf_state_t *); + + void (osal_fastcall *TLBR)(usf_state_t *); + void (osal_fastcall *TLBWI)(usf_state_t *); + void (osal_fastcall *TLBWR)(usf_state_t *); + void (osal_fastcall *TLBP)(usf_state_t *); + void (osal_fastcall *CACHE)(usf_state_t *); + void (osal_fastcall *ERET)(usf_state_t *); + + // COP1 instructions + void (osal_fastcall *LWC1)(usf_state_t *); + void (osal_fastcall *SWC1)(usf_state_t *); + void (osal_fastcall *MTC1)(usf_state_t *); + void (osal_fastcall *MFC1)(usf_state_t *); + void (osal_fastcall *CTC1)(usf_state_t *); + void (osal_fastcall *CFC1)(usf_state_t *); + void (osal_fastcall *BC1T)(usf_state_t *); + void (osal_fastcall *BC1T_OUT)(usf_state_t *); + void (osal_fastcall *BC1T_IDLE)(usf_state_t *); + void (osal_fastcall *BC1F)(usf_state_t *); + void (osal_fastcall *BC1F_OUT)(usf_state_t *); + void (osal_fastcall *BC1F_IDLE)(usf_state_t *); + + void (osal_fastcall *DMFC1)(usf_state_t *); + void (osal_fastcall *DMTC1)(usf_state_t *); + void (osal_fastcall *LDC1)(usf_state_t *); + void (osal_fastcall *SDC1)(usf_state_t *); + + void (osal_fastcall *CVT_S_D)(usf_state_t *); + void (osal_fastcall *CVT_S_W)(usf_state_t *); + void (osal_fastcall *CVT_S_L)(usf_state_t *); + void (osal_fastcall *CVT_D_S)(usf_state_t *); + void (osal_fastcall *CVT_D_W)(usf_state_t *); + void (osal_fastcall *CVT_D_L)(usf_state_t *); + void (osal_fastcall *CVT_W_S)(usf_state_t *); + void (osal_fastcall *CVT_W_D)(usf_state_t *); + void (osal_fastcall *CVT_L_S)(usf_state_t *); + void (osal_fastcall *CVT_L_D)(usf_state_t *); + + void (osal_fastcall *ROUND_W_S)(usf_state_t *); + void (osal_fastcall *ROUND_W_D)(usf_state_t *); + void (osal_fastcall *ROUND_L_S)(usf_state_t *); + void (osal_fastcall *ROUND_L_D)(usf_state_t *); + + void (osal_fastcall *TRUNC_W_S)(usf_state_t *); + void (osal_fastcall *TRUNC_W_D)(usf_state_t *); + void (osal_fastcall *TRUNC_L_S)(usf_state_t *); + void (osal_fastcall *TRUNC_L_D)(usf_state_t *); + + void (osal_fastcall *CEIL_W_S)(usf_state_t *); + void (osal_fastcall *CEIL_W_D)(usf_state_t *); + void (osal_fastcall *CEIL_L_S)(usf_state_t *); + void (osal_fastcall *CEIL_L_D)(usf_state_t *); + + void (osal_fastcall *FLOOR_W_S)(usf_state_t *); + void (osal_fastcall *FLOOR_W_D)(usf_state_t *); + void (osal_fastcall *FLOOR_L_S)(usf_state_t *); + void (osal_fastcall *FLOOR_L_D)(usf_state_t *); + + void (osal_fastcall *ADD_S)(usf_state_t *); + void (osal_fastcall *ADD_D)(usf_state_t *); + + void (osal_fastcall *SUB_S)(usf_state_t *); + void (osal_fastcall *SUB_D)(usf_state_t *); + + void (osal_fastcall *MUL_S)(usf_state_t *); + void (osal_fastcall *MUL_D)(usf_state_t *); + + void (osal_fastcall *DIV_S)(usf_state_t *); + void (osal_fastcall *DIV_D)(usf_state_t *); + + void (osal_fastcall *ABS_S)(usf_state_t *); + void (osal_fastcall *ABS_D)(usf_state_t *); + + void (osal_fastcall *MOV_S)(usf_state_t *); + void (osal_fastcall *MOV_D)(usf_state_t *); + + void (osal_fastcall *NEG_S)(usf_state_t *); + void (osal_fastcall *NEG_D)(usf_state_t *); + + void (osal_fastcall *SQRT_S)(usf_state_t *); + void (osal_fastcall *SQRT_D)(usf_state_t *); + + void (osal_fastcall *C_F_S)(usf_state_t *); + void (osal_fastcall *C_F_D)(usf_state_t *); + void (osal_fastcall *C_UN_S)(usf_state_t *); + void (osal_fastcall *C_UN_D)(usf_state_t *); + void (osal_fastcall *C_EQ_S)(usf_state_t *); + void (osal_fastcall *C_EQ_D)(usf_state_t *); + void (osal_fastcall *C_UEQ_S)(usf_state_t *); + void (osal_fastcall *C_UEQ_D)(usf_state_t *); + void (osal_fastcall *C_OLT_S)(usf_state_t *); + void (osal_fastcall *C_OLT_D)(usf_state_t *); + void (osal_fastcall *C_ULT_S)(usf_state_t *); + void (osal_fastcall *C_ULT_D)(usf_state_t *); + void (osal_fastcall *C_OLE_S)(usf_state_t *); + void (osal_fastcall *C_OLE_D)(usf_state_t *); + void (osal_fastcall *C_ULE_S)(usf_state_t *); + void (osal_fastcall *C_ULE_D)(usf_state_t *); + void (osal_fastcall *C_SF_S)(usf_state_t *); + void (osal_fastcall *C_SF_D)(usf_state_t *); + void (osal_fastcall *C_NGLE_S)(usf_state_t *); + void (osal_fastcall *C_NGLE_D)(usf_state_t *); + void (osal_fastcall *C_SEQ_S)(usf_state_t *); + void (osal_fastcall *C_SEQ_D)(usf_state_t *); + void (osal_fastcall *C_NGL_S)(usf_state_t *); + void (osal_fastcall *C_NGL_D)(usf_state_t *); + void (osal_fastcall *C_LT_S)(usf_state_t *); + void (osal_fastcall *C_LT_D)(usf_state_t *); + void (osal_fastcall *C_NGE_S)(usf_state_t *); + void (osal_fastcall *C_NGE_D)(usf_state_t *); + void (osal_fastcall *C_LE_S)(usf_state_t *); + void (osal_fastcall *C_LE_D)(usf_state_t *); + void (osal_fastcall *C_NGT_S)(usf_state_t *); + void (osal_fastcall *C_NGT_D)(usf_state_t *); + + // Special instructions + void (osal_fastcall *SYSCALL)(usf_state_t *); + void (osal_fastcall *BREAK)(usf_state_t *); + + // Exception instructions + void (osal_fastcall *TEQ)(usf_state_t *); + + // Emulator helper functions + void (osal_fastcall *NOP)(usf_state_t *); // No operation (used to nullify R0 writes) + void (osal_fastcall *RESERVED)(usf_state_t *); // Reserved instruction handler + void (osal_fastcall *NI)(usf_state_t *); // Not implemented instruction handler + + void (osal_fastcall *FIN_BLOCK)(usf_state_t *); // Handler for the end of a block + void (osal_fastcall *NOTCOMPILED)(usf_state_t *); // Handler for not yet compiled code + void (osal_fastcall *NOTCOMPILED2)(usf_state_t *); // TODOXXX +} cpu_instruction_table; + +#endif /* M64P_R4300_OPS_H_*/ diff --git a/Frameworks/lazyusf/lazyusf/r4300/pure_interp.c b/Frameworks/lazyusf/lazyusf/r4300/pure_interp.c new file mode 100644 index 000000000..fc208654f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/pure_interp.c @@ -0,0 +1,746 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pure_interp.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2015 Nebuleon * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "memory/memory.h" +#include "main/main.h" +#include "osal/preproc.h" + +/* TLBWrite requires invalid_code and blocks from cached_interp.h, but only if + * (at run time) the active core is not the Pure Interpreter. */ +#include "cached_interp.h" +#include "r4300.h" +#include "cp0.h" +#include "cp1.h" +#include "exception.h" +#include "interupt.h" +#include "tlb.h" + +#include "usf/usf_internal.h" + +static void InterpretOpcode(usf_state_t * state); + +#define PCADDR state->interp_PC.addr +#define ADD_TO_PC(x) state->interp_PC.addr += x*4; +#define DECLARE_INSTRUCTION(name) static void name(usf_state_t * state, uint32_t op) +#define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ + static void name(usf_state_t * state, uint32_t op) \ + { \ + const int take_jump = (condition); \ + const unsigned int jump_target = (destination); \ + long long int *link_register = (link); \ + if (cop1 && check_cop1_unusable(state)) return; \ + if (link_register != &state->reg[0]) \ + { \ + *link_register=state->interp_PC.addr + 8; \ + sign_extended(*link_register); \ + } \ + if (!likely || take_jump) \ + { \ + state->interp_PC.addr += 4; \ + state->delay_slot=1; \ + InterpretOpcode(state); \ + update_count(state); \ + state->delay_slot=0; \ + if (take_jump && !state->skip_jump) \ + { \ + state->interp_PC.addr = jump_target; \ + } \ + } \ + else \ + { \ + state->interp_PC.addr += 8; \ + update_count(state); \ + } \ + state->last_addr = state->interp_PC.addr; \ + if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ + } \ + static void name##_IDLE(usf_state_t * state, uint32_t op) \ + { \ + const int take_jump = (condition); \ + int skip; \ + if (cop1 && check_cop1_unusable(state)) return; \ + if (take_jump) \ + { \ + update_count(state); \ + skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \ + if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \ + else name(state, op); \ + } \ + else name(state, op); \ + } +#define CHECK_MEMORY() + +#define RD_OF(op) (((op) >> 11) & 0x1F) +#define RS_OF(op) (((op) >> 21) & 0x1F) +#define RT_OF(op) (((op) >> 16) & 0x1F) +#define SA_OF(op) (((op) >> 6) & 0x1F) +#define IMM16S_OF(op) ((int16_t) (op)) +#define IMM16U_OF(op) ((uint16_t) (op)) +#define FD_OF(op) (((op) >> 6) & 0x1F) +#define FS_OF(op) (((op) >> 11) & 0x1F) +#define FT_OF(op) (((op) >> 16) & 0x1F) +#define JUMP_OF(op) ((op) & UINT32_C(0x3FFFFFF)) + +/* Determines whether a relative jump in a 16-bit immediate goes back to the + * same instruction without doing any work in its delay slot. The jump is + * relative to the instruction in the delay slot, so 1 instruction backwards + * (-1) goes back to the jump. */ +#define IS_RELATIVE_IDLE_LOOP(op, addr) \ + (IMM16S_OF(op) == -1 && *fast_mem_access(state, (addr) + 4) == 0) + +/* Determines whether an absolute jump in a 26-bit immediate goes back to the + * same instruction without doing any work in its delay slot. The jump is + * in the same 256 MiB segment as the delay slot, so if the jump instruction + * is at the last address in its segment, it does not jump back to itself. */ +#define IS_ABSOLUTE_IDLE_LOOP(op, addr) \ + (JUMP_OF(op) == ((addr) & UINT32_C(0x0FFFFFFF)) >> 2 \ + && ((addr) & UINT32_C(0x0FFFFFFF)) != UINT32_C(0x0FFFFFFC) \ + && *fast_mem_access(state, (addr) + 4) == 0) + +#define sign_extended(a) a = (int64_t) ((int32_t) (a)) +#define sign_extendedb(a) a = (int64_t) ((int8_t) (a)) +#define sign_extendedh(a) a = (int64_t) ((int16_t) (a)) + +/* These macros are like those in macros.h, but they parse opcode fields. */ +#define rrt state->reg[RT_OF(op)] +#define rrd state->reg[RD_OF(op)] +#define rfs FS_OF(op) +#define rrs state->reg[RS_OF(op)] +#define rsa SA_OF(op) +#define irt state->reg[RT_OF(op)] +#define ioffset IMM16S_OF(op) +#define iimmediate IMM16S_OF(op) +#define irs state->reg[RS_OF(op)] +#define ibase state->reg[RS_OF(op)] +#define jinst_index JUMP_OF(op) +#define lfbase RS_OF(op) +#define lfft FT_OF(op) +#define lfoffset IMM16S_OF(op) +#define cfft FT_OF(op) +#define cffs FS_OF(op) +#define cffd FD_OF(op) + +// 32 bits macros +#ifndef M64P_BIG_ENDIAN +#define rrt32 *((int32_t*) &state->reg[RT_OF(op)]) +#define rrd32 *((int32_t*) &state->reg[RD_OF(op)]) +#define rrs32 *((int32_t*) &state->reg[RS_OF(op)]) +#define irs32 *((int32_t*) &state->reg[RS_OF(op)]) +#define irt32 *((int32_t*) &state->reg[RT_OF(op)]) +#else +#define rrt32 *((int32_t*) &state->reg[RT_OF(op)] + 1) +#define rrd32 *((int32_t*) &state->reg[RD_OF(op)] + 1) +#define rrs32 *((int32_t*) &state->reg[RS_OF(op)] + 1) +#define irs32 *((int32_t*) &state->reg[RS_OF(op)] + 1) +#define irt32 *((int32_t*) &state->reg[RT_OF(op)] + 1) +#endif + +// two functions are defined from the macros above but never used +// these prototype declarations will prevent a warning +#if defined(__GNUC__) + static void JR_IDLE(usf_state_t *, uint32_t) __attribute__((used)); + static void JALR_IDLE(usf_state_t *, uint32_t) __attribute__((used)); +#endif + +#include "interpreter.def" +#include +#include + +#ifdef DEBUG_INFO +#include "debugger/dbg_decoder.h" +#include +#endif + +void InterpretOpcode(usf_state_t * state) +{ + uint32_t op = *fast_mem_access(state, state->PC->addr); +#ifdef DEBUG_INFO + if (0) + { + char instr[256]; + char arguments[256]; + r4300_decode_op(op, instr, arguments, state->PC->addr); + fprintf(state->debug_log, "%08x: %-16s %s\n", state->PC->addr, instr, arguments); + } +#endif + switch ((op >> 26) & 0x3F) { + case 0: /* SPECIAL prefix */ + switch (op & 0x3F) { + case 0: /* SPECIAL opcode 0: SLL */ + if (RD_OF(op) != 0) SLL(state, op); + else NOP(state, 0); + break; + case 2: /* SPECIAL opcode 2: SRL */ + if (RD_OF(op) != 0) SRL(state, op); + else NOP(state, 0); + break; + case 3: /* SPECIAL opcode 3: SRA */ + if (RD_OF(op) != 0) SRA(state, op); + else NOP(state, 0); + break; + case 4: /* SPECIAL opcode 4: SLLV */ + if (RD_OF(op) != 0) SLLV(state, op); + else NOP(state, 0); + break; + case 6: /* SPECIAL opcode 6: SRLV */ + if (RD_OF(op) != 0) SRLV(state, op); + else NOP(state, 0); + break; + case 7: /* SPECIAL opcode 7: SRAV */ + if (RD_OF(op) != 0) SRAV(state, op); + else NOP(state, 0); + break; + case 8: JR(state, op); break; + case 9: /* SPECIAL opcode 9: JALR */ + /* Note: This can omit the check for Rd == 0 because the JALR + * function checks for link_register != ®[0]. If you're + * using this as a reference for a JIT, do check Rd == 0 in it. */ + JALR(state, op); + break; + case 12: SYSCALL(state, op); break; + case 13: /* SPECIAL opcode 13: BREAK */ + BREAK(state, op); + break; + case 15: SYNC(state, op); break; + case 16: /* SPECIAL opcode 16: MFHI */ + if (RD_OF(op) != 0) MFHI(state, op); + else NOP(state, 0); + break; + case 17: MTHI(state, op); break; + case 18: /* SPECIAL opcode 18: MFLO */ + if (RD_OF(op) != 0) MFLO(state, op); + else NOP(state, 0); + break; + case 19: MTLO(state, op); break; + case 20: /* SPECIAL opcode 20: DSLLV */ + if (RD_OF(op) != 0) DSLLV(state, op); + else NOP(state, 0); + break; + case 22: /* SPECIAL opcode 22: DSRLV */ + if (RD_OF(op) != 0) DSRLV(state, op); + else NOP(state, 0); + break; + case 23: /* SPECIAL opcode 23: DSRAV */ + if (RD_OF(op) != 0) DSRAV(state, op); + else NOP(state, 0); + break; + case 24: MULT(state, op); break; + case 25: MULTU(state, op); break; + case 26: DIV(state, op); break; + case 27: DIVU(state, op); break; + case 28: DMULT(state, op); break; + case 29: DMULTU(state, op); break; + case 30: DDIV(state, op); break; + case 31: DDIVU(state, op); break; + case 32: /* SPECIAL opcode 32: ADD */ + if (RD_OF(op) != 0) ADD(state, op); + else NOP(state, 0); + break; + case 33: /* SPECIAL opcode 33: ADDU */ + if (RD_OF(op) != 0) ADDU(state, op); + else NOP(state, 0); + break; + case 34: /* SPECIAL opcode 34: SUB */ + if (RD_OF(op) != 0) SUB(state, op); + else NOP(state, 0); + break; + case 35: /* SPECIAL opcode 35: SUBU */ + if (RD_OF(op) != 0) SUBU(state, op); + else NOP(state, 0); + break; + case 36: /* SPECIAL opcode 36: AND */ + if (RD_OF(op) != 0) AND(state, op); + else NOP(state, 0); + break; + case 37: /* SPECIAL opcode 37: OR */ + if (RD_OF(op) != 0) OR(state, op); + else NOP(state, 0); + break; + case 38: /* SPECIAL opcode 38: XOR */ + if (RD_OF(op) != 0) XOR(state, op); + else NOP(state, 0); + break; + case 39: /* SPECIAL opcode 39: NOR */ + if (RD_OF(op) != 0) NOR(state, op); + else NOP(state, 0); + break; + case 42: /* SPECIAL opcode 42: SLT */ + if (RD_OF(op) != 0) SLT(state, op); + else NOP(state, 0); + break; + case 43: /* SPECIAL opcode 43: SLTU */ + if (RD_OF(op) != 0) SLTU(state, op); + else NOP(state, 0); + break; + case 44: /* SPECIAL opcode 44: DADD */ + if (RD_OF(op) != 0) DADD(state, op); + else NOP(state, 0); + break; + case 45: /* SPECIAL opcode 45: DADDU */ + if (RD_OF(op) != 0) DADDU(state, op); + else NOP(state, 0); + break; + case 46: /* SPECIAL opcode 46: DSUB */ + if (RD_OF(op) != 0) DSUB(state, op); + else NOP(state, 0); + break; + case 47: /* SPECIAL opcode 47: DSUBU */ + if (RD_OF(op) != 0) DSUBU(state, op); + else NOP(state, 0); + break; + case 48: /* SPECIAL opcode 48: TGE (Not implemented) */ + case 49: /* SPECIAL opcode 49: TGEU (Not implemented) */ + case 50: /* SPECIAL opcode 50: TLT (Not implemented) */ + case 51: /* SPECIAL opcode 51: TLTU (Not implemented) */ + NI(state, op); + break; + case 52: TEQ(state, op); break; + case 54: /* SPECIAL opcode 54: TNE (Not implemented) */ + NI(state, op); + break; + case 56: /* SPECIAL opcode 56: DSLL */ + if (RD_OF(op) != 0) DSLL(state, op); + else NOP(state, 0); + break; + case 58: /* SPECIAL opcode 58: DSRL */ + if (RD_OF(op) != 0) DSRL(state, op); + else NOP(state, 0); + break; + case 59: /* SPECIAL opcode 59: DSRA */ + if (RD_OF(op) != 0) DSRA(state, op); + else NOP(state, 0); + break; + case 60: /* SPECIAL opcode 60: DSLL32 */ + if (RD_OF(op) != 0) DSLL32(state, op); + else NOP(state, 0); + break; + case 62: /* SPECIAL opcode 62: DSRL32 */ + if (RD_OF(op) != 0) DSRL32(state, op); + else NOP(state, 0); + break; + case 63: /* SPECIAL opcode 63: DSRA32 */ + if (RD_OF(op) != 0) DSRA32(state, op); + else NOP(state, 0); + break; + default: /* SPECIAL opcodes 1, 5, 10, 11, 14, 21, 40, 41, 53, 55, 57, + 61: Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch (op & 0x3F) for the SPECIAL prefix */ + break; + case 1: /* REGIMM prefix */ + switch ((op >> 16) & 0x1F) { + case 0: /* REGIMM opcode 0: BLTZ */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZ_IDLE(state, op); + else BLTZ(state, op); + break; + case 1: /* REGIMM opcode 1: BGEZ */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZ_IDLE(state, op); + else BGEZ(state, op); + break; + case 2: /* REGIMM opcode 2: BLTZL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZL_IDLE(state, op); + else BLTZL(state, op); + break; + case 3: /* REGIMM opcode 3: BGEZL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZL_IDLE(state, op); + else BGEZL(state, op); + break; + case 8: /* REGIMM opcode 8: TGEI (Not implemented) */ + case 9: /* REGIMM opcode 9: TGEIU (Not implemented) */ + case 10: /* REGIMM opcode 10: TLTI (Not implemented) */ + case 11: /* REGIMM opcode 11: TLTIU (Not implemented) */ + case 12: /* REGIMM opcode 12: TEQI (Not implemented) */ + case 14: /* REGIMM opcode 14: TNEI (Not implemented) */ + NI(state, op); + break; + case 16: /* REGIMM opcode 16: BLTZAL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZAL_IDLE(state, op); + else BLTZAL(state, op); + break; + case 17: /* REGIMM opcode 17: BGEZAL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZAL_IDLE(state, op); + else BGEZAL(state, op); + break; + case 18: /* REGIMM opcode 18: BLTZALL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZALL_IDLE(state, op); + else BLTZALL(state, op); + break; + case 19: /* REGIMM opcode 19: BGEZALL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZALL_IDLE(state, op); + else BGEZALL(state, op); + break; + default: /* REGIMM opcodes 4..7, 13, 15, 20..31: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch ((op >> 16) & 0x1F) for the REGIMM prefix */ + break; + case 2: /* Major opcode 2: J */ + if (IS_ABSOLUTE_IDLE_LOOP(op, state->PC->addr)) J_IDLE(state, op); + else J(state, op); + break; + case 3: /* Major opcode 3: JAL */ + if (IS_ABSOLUTE_IDLE_LOOP(op, state->PC->addr)) JAL_IDLE(state, op); + else JAL(state, op); + break; + case 4: /* Major opcode 4: BEQ */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BEQ_IDLE(state, op); + else BEQ(state, op); + break; + case 5: /* Major opcode 5: BNE */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BNE_IDLE(state, op); + else BNE(state, op); + break; + case 6: /* Major opcode 6: BLEZ */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLEZ_IDLE(state, op); + else BLEZ(state, op); + break; + case 7: /* Major opcode 7: BGTZ */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGTZ_IDLE(state, op); + else BGTZ(state, op); + break; + case 8: /* Major opcode 8: ADDI */ + if (RT_OF(op) != 0) ADDI(state, op); + else NOP(state, 0); + break; + case 9: /* Major opcode 9: ADDIU */ + if (RT_OF(op) != 0) ADDIU(state, op); + else NOP(state, 0); + break; + case 10: /* Major opcode 10: SLTI */ + if (RT_OF(op) != 0) SLTI(state, op); + else NOP(state, 0); + break; + case 11: /* Major opcode 11: SLTIU */ + if (RT_OF(op) != 0) SLTIU(state, op); + else NOP(state, 0); + break; + case 12: /* Major opcode 12: ANDI */ + if (RT_OF(op) != 0) ANDI(state, op); + else NOP(state, 0); + break; + case 13: /* Major opcode 13: ORI */ + if (RT_OF(op) != 0) ORI(state, op); + else NOP(state, 0); + break; + case 14: /* Major opcode 14: XORI */ + if (RT_OF(op) != 0) XORI(state, op); + else NOP(state, 0); + break; + case 15: /* Major opcode 15: LUI */ + if (RT_OF(op) != 0) LUI(state, op); + else NOP(state, 0); + break; + case 16: /* Coprocessor 0 prefix */ + switch ((op >> 21) & 0x1F) { + case 0: /* Coprocessor 0 opcode 0: MFC0 */ + if (RT_OF(op) != 0) MFC0(state, op); + else NOP(state, 0); + break; + case 4: MTC0(state, op); break; + case 16: /* Coprocessor 0 opcode 16: TLB */ + switch (op & 0x3F) { + case 1: TLBR(state, op); break; + case 2: TLBWI(state, op); break; + case 6: TLBWR(state, op); break; + case 8: TLBP(state, op); break; + case 24: ERET(state, op); break; + default: /* TLB sub-opcodes 0, 3..5, 7, 9..23, 25..63: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch (op & 0x3F) for Coprocessor 0 TLB opcodes */ + break; + default: /* Coprocessor 0 opcodes 1..3, 4..15, 17..31: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch ((op >> 21) & 0x1F) for the Coprocessor 0 prefix */ + break; + case 17: /* Coprocessor 1 prefix */ + switch ((op >> 21) & 0x1F) { + case 0: /* Coprocessor 1 opcode 0: MFC1 */ + if (RT_OF(op) != 0) MFC1(state, op); + else NOP(state, 0); + break; + case 1: /* Coprocessor 1 opcode 1: DMFC1 */ + if (RT_OF(op) != 0) DMFC1(state, op); + else NOP(state, 0); + break; + case 2: /* Coprocessor 1 opcode 2: CFC1 */ + if (RT_OF(op) != 0) CFC1(state, op); + else NOP(state, 0); + break; + case 4: MTC1(state, op); break; + case 5: DMTC1(state, op); break; + case 6: CTC1(state, op); break; + case 8: /* Coprocessor 1 opcode 8: Branch on C1 condition... */ + switch ((op >> 16) & 0x3) { + case 0: /* opcode 0: BC1F */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1F_IDLE(state, op); + else BC1F(state, op); + break; + case 1: /* opcode 1: BC1T */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1T_IDLE(state, op); + else BC1T(state, op); + break; + case 2: /* opcode 2: BC1FL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1FL_IDLE(state, op); + else BC1FL(state, op); + break; + case 3: /* opcode 3: BC1TL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1TL_IDLE(state, op); + else BC1TL(state, op); + break; + } /* switch ((op >> 16) & 0x3) for branches on C1 condition */ + break; + case 16: /* Coprocessor 1 S-format opcodes */ + switch (op & 0x3F) { + case 0: ADD_S(state, op); break; + case 1: SUB_S(state, op); break; + case 2: MUL_S(state, op); break; + case 3: DIV_S(state, op); break; + case 4: SQRT_S(state, op); break; + case 5: ABS_S(state, op); break; + case 6: MOV_S(state, op); break; + case 7: NEG_S(state, op); break; + case 8: ROUND_L_S(state, op); break; + case 9: TRUNC_L_S(state, op); break; + case 10: CEIL_L_S(state, op); break; + case 11: FLOOR_L_S(state, op); break; + case 12: ROUND_W_S(state, op); break; + case 13: TRUNC_W_S(state, op); break; + case 14: CEIL_W_S(state, op); break; + case 15: FLOOR_W_S(state, op); break; + case 33: CVT_D_S(state, op); break; + case 36: CVT_W_S(state, op); break; + case 37: CVT_L_S(state, op); break; + case 48: C_F_S(state, op); break; + case 49: C_UN_S(state, op); break; + case 50: C_EQ_S(state, op); break; + case 51: C_UEQ_S(state, op); break; + case 52: C_OLT_S(state, op); break; + case 53: C_ULT_S(state, op); break; + case 54: C_OLE_S(state, op); break; + case 55: C_ULE_S(state, op); break; + case 56: C_SF_S(state, op); break; + case 57: C_NGLE_S(state, op); break; + case 58: C_SEQ_S(state, op); break; + case 59: C_NGL_S(state, op); break; + case 60: C_LT_S(state, op); break; + case 61: C_NGE_S(state, op); break; + case 62: C_LE_S(state, op); break; + case 63: C_NGT_S(state, op); break; + default: /* Coprocessor 1 S-format opcodes 16..32, 34..35, 38..47: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch (op & 0x3F) for Coprocessor 1 S-format opcodes */ + break; + case 17: /* Coprocessor 1 D-format opcodes */ + switch (op & 0x3F) { + case 0: ADD_D(state, op); break; + case 1: SUB_D(state, op); break; + case 2: MUL_D(state, op); break; + case 3: DIV_D(state, op); break; + case 4: SQRT_D(state, op); break; + case 5: ABS_D(state, op); break; + case 6: MOV_D(state, op); break; + case 7: NEG_D(state, op); break; + case 8: ROUND_L_D(state, op); break; + case 9: TRUNC_L_D(state, op); break; + case 10: CEIL_L_D(state, op); break; + case 11: FLOOR_L_D(state, op); break; + case 12: ROUND_W_D(state, op); break; + case 13: TRUNC_W_D(state, op); break; + case 14: CEIL_W_D(state, op); break; + case 15: FLOOR_W_D(state, op); break; + case 32: CVT_S_D(state, op); break; + case 36: CVT_W_D(state, op); break; + case 37: CVT_L_D(state, op); break; + case 48: C_F_D(state, op); break; + case 49: C_UN_D(state, op); break; + case 50: C_EQ_D(state, op); break; + case 51: C_UEQ_D(state, op); break; + case 52: C_OLT_D(state, op); break; + case 53: C_ULT_D(state, op); break; + case 54: C_OLE_D(state, op); break; + case 55: C_ULE_D(state, op); break; + case 56: C_SF_D(state, op); break; + case 57: C_NGLE_D(state, op); break; + case 58: C_SEQ_D(state, op); break; + case 59: C_NGL_D(state, op); break; + case 60: C_LT_D(state, op); break; + case 61: C_NGE_D(state, op); break; + case 62: C_LE_D(state, op); break; + case 63: C_NGT_D(state, op); break; + default: /* Coprocessor 1 D-format opcodes 16..31, 33..35, 38..47: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch (op & 0x3F) for Coprocessor 1 D-format opcodes */ + break; + case 20: /* Coprocessor 1 W-format opcodes */ + switch (op & 0x3F) { + case 32: CVT_S_W(state, op); break; + case 33: CVT_D_W(state, op); break; + default: /* Coprocessor 1 W-format opcodes 0..31, 34..63: + Reserved Instructions */ + RESERVED(state, op); + break; + } + break; + case 21: /* Coprocessor 1 L-format opcodes */ + switch (op & 0x3F) { + case 32: CVT_S_L(state, op); break; + case 33: CVT_D_L(state, op); break; + default: /* Coprocessor 1 L-format opcodes 0..31, 34..63: + Reserved Instructions */ + RESERVED(state, op); + break; + } + break; + default: /* Coprocessor 1 opcodes 3, 7, 9..15, 18..19, 22..31: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch ((op >> 21) & 0x1F) for the Coprocessor 1 prefix */ + break; + case 20: /* Major opcode 20: BEQL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BEQL_IDLE(state, op); + else BEQL(state, op); + break; + case 21: /* Major opcode 21: BNEL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BNEL_IDLE(state, op); + else BNEL(state, op); + break; + case 22: /* Major opcode 22: BLEZL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLEZL_IDLE(state, op); + else BLEZL(state, op); + break; + case 23: /* Major opcode 23: BGTZL */ + if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGTZL_IDLE(state, op); + else BGTZL(state, op); + break; + case 24: /* Major opcode 24: DADDI */ + if (RT_OF(op) != 0) DADDI(state, op); + else NOP(state, 0); + break; + case 25: /* Major opcode 25: DADDIU */ + if (RT_OF(op) != 0) DADDIU(state, op); + else NOP(state, 0); + break; + case 26: /* Major opcode 26: LDL */ + if (RT_OF(op) != 0) LDL(state, op); + else NOP(state, 0); + break; + case 27: /* Major opcode 27: LDR */ + if (RT_OF(op) != 0) LDR(state, op); + else NOP(state, 0); + break; + case 32: /* Major opcode 32: LB */ + if (RT_OF(op) != 0) LB(state, op); + else NOP(state, 0); + break; + case 33: /* Major opcode 33: LH */ + if (RT_OF(op) != 0) LH(state, op); + else NOP(state, 0); + break; + case 34: /* Major opcode 34: LWL */ + if (RT_OF(op) != 0) LWL(state, op); + else NOP(state, 0); + break; + case 35: /* Major opcode 35: LW */ + if (RT_OF(op) != 0) LW(state, op); + else NOP(state, 0); + break; + case 36: /* Major opcode 36: LBU */ + if (RT_OF(op) != 0) LBU(state, op); + else NOP(state, 0); + break; + case 37: /* Major opcode 37: LHU */ + if (RT_OF(op) != 0) LHU(state, op); + else NOP(state, 0); + break; + case 38: /* Major opcode 38: LWR */ + if (RT_OF(op) != 0) LWR(state, op); + else NOP(state, 0); + break; + case 39: /* Major opcode 39: LWU */ + if (RT_OF(op) != 0) LWU(state, op); + else NOP(state, 0); + break; + case 40: SB(state, op); break; + case 41: SH(state, op); break; + case 42: SWL(state, op); break; + case 43: SW(state, op); break; + case 44: SDL(state, op); break; + case 45: SDR(state, op); break; + case 46: SWR(state, op); break; + case 47: CACHE(state, op); break; + case 48: /* Major opcode 48: LL */ + if (RT_OF(op) != 0) LL(state, op); + else NOP(state, 0); + break; + case 49: LWC1(state, op); break; + case 52: /* Major opcode 52: LLD (Not implemented) */ + NI(state, op); + break; + case 53: LDC1(state, op); break; + case 55: /* Major opcode 55: LD */ + if (RT_OF(op) != 0) LD(state, op); + else NOP(state, 0); + break; + case 56: /* Major opcode 56: SC */ + if (RT_OF(op) != 0) SC(state, op); + else NOP(state, 0); + break; + case 57: SWC1(state, op); break; + case 60: /* Major opcode 60: SCD (Not implemented) */ + NI(state, op); + break; + case 61: SDC1(state, op); break; + case 63: SD(state, op); break; + default: /* Major opcodes 18..19, 28..31, 50..51, 54, 58..59, 62: + Reserved Instructions */ + RESERVED(state, op); + break; + } /* switch ((op >> 26) & 0x3F) */ +} + +void pure_interpreter(usf_state_t * state) +{ + state->stop = 0; + state->PC = &state->interp_PC; + + while (!state->stop) + { + r4300_checkpoint(state); + InterpretOpcode(state); + } +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/pure_interp.h b/Frameworks/lazyusf/lazyusf/r4300/pure_interp.h new file mode 100644 index 000000000..5121ca7b5 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/pure_interp.h @@ -0,0 +1,27 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pure_interp.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_PURE_INTERP_H +#define M64P_R4300_PURE_INTERP_H + +void pure_interpreter(usf_state_t *); + +#endif /* M64P_R4300_PURE_INTERP_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/r4300.c b/Frameworks/lazyusf/lazyusf/r4300/r4300.c new file mode 100644 index 000000000..fdde0aa9a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/r4300.c @@ -0,0 +1,349 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - r4300.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "ai/ai_controller.h" +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "memory/memory.h" +#include "main/main.h" +#include "main/rom.h" +#include "pi/pi_controller.h" +#include "rsp/rsp_core.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + +#include "r4300.h" +#include "r4300_core.h" +#include "cached_interp.h" +#include "cp0.h" +#include "cp1.h" +#include "ops.h" +#include "interupt.h" +#include "pure_interp.h" +#include "recomp.h" +#include "recomph.h" +#include "tlb.h" +#include "new_dynarec/new_dynarec.h" + +#ifdef DBG +#include "debugger/dbg_types.h" +#include "debugger/debugger.h" +#endif + +#if defined(COUNT_INSTR) +#include "instr_counters.h" +#endif + +void generic_jump_to(usf_state_t * state, unsigned int address) +{ + if (state->r4300emu == CORE_PURE_INTERPRETER) + state->interp_PC.addr = address; + else { +#ifdef NEW_DYNAREC + if (state->r4300emu == CORE_DYNAREC) + state->last_addr = pcaddr; + else + jump_to(address); +#else + jump_to(address); +#endif + } +} + +/* this hard reset function simulates the boot-up state of the R4300 CPU */ +void r4300_reset_hard(usf_state_t * state) +{ + unsigned int i; + + // clear r4300 registers and TLB entries + for (i = 0; i < 32; i++) + { + state->reg[i]=0; + state->g_cp0_regs[i]=0; + state->reg_cop1_fgr_64[i]=0; + + // --------------tlb------------------------ + state->tlb_e[i].mask=0; + state->tlb_e[i].vpn2=0; + state->tlb_e[i].g=0; + state->tlb_e[i].asid=0; + state->tlb_e[i].pfn_even=0; + state->tlb_e[i].c_even=0; + state->tlb_e[i].d_even=0; + state->tlb_e[i].v_even=0; + state->tlb_e[i].pfn_odd=0; + state->tlb_e[i].c_odd=0; + state->tlb_e[i].d_odd=0; + state->tlb_e[i].v_odd=0; + state->tlb_e[i].r=0; + //tlb_e[i].check_parity_mask=0x1000; + + state->tlb_e[i].start_even=0; + state->tlb_e[i].end_even=0; + state->tlb_e[i].phys_even=0; + state->tlb_e[i].start_odd=0; + state->tlb_e[i].end_odd=0; + state->tlb_e[i].phys_odd=0; + } + for (i=0; i<0x100000; i++) + { + state->tlb_LUT_r[i] = 0; + state->tlb_LUT_w[i] = 0; + } + state->llbit=0; + state->hi=0; + state->lo=0; + state->FCR0=0x511; + state->FCR31=0; + + // set COP0 registers + state->g_cp0_regs[CP0_RANDOM_REG] = 31; + state->g_cp0_regs[CP0_STATUS_REG]= 0x34000000; + set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]); + state->g_cp0_regs[CP0_CONFIG_REG]= 0x6e463; + state->g_cp0_regs[CP0_PREVID_REG] = 0xb00; + state->g_cp0_regs[CP0_COUNT_REG] = 0x5000; + state->g_cp0_regs[CP0_CAUSE_REG] = 0x5C; + state->g_cp0_regs[CP0_CONTEXT_REG] = 0x7FFFF0; + state->g_cp0_regs[CP0_EPC_REG] = 0xFFFFFFFF; + state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF; + state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF; + + state->rounding_mode = 0x33F; +} + + +static unsigned int get_tv_type(usf_state_t * state) +{ + switch(state->ROM_PARAMS.systemtype) + { + default: + case SYSTEM_NTSC: return 1; + case SYSTEM_PAL: return 0; + case SYSTEM_MPAL: return 2; + } +} + +/* Simulates end result of PIFBootROM execution */ +void r4300_reset_soft(usf_state_t * state) +{ + unsigned int rom_type = 0; /* 0:Cart, 1:DD */ + unsigned int reset_type = 0; /* 0:ColdReset, 1:NMI */ + unsigned int s7 = 0; /* ??? */ + unsigned int tv_type = get_tv_type(state); /* 0:PAL, 1:NTSC, 2:MPAL */ + uint32_t bsd_dom1_config = (state->g_rom && state->g_rom_size >= 4) ? *(uint32_t*)state->g_rom : 0; + + state->g_cp0_regs[CP0_STATUS_REG] = 0x34000000; + state->g_cp0_regs[CP0_CONFIG_REG] = 0x0006e463; + + state->g_sp.regs[SP_STATUS_REG] = 1; + state->g_sp.regs2[SP_PC_REG] = 0; + + state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = (bsd_dom1_config ) & 0xff; + state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = (bsd_dom1_config >> 8) & 0xff; + state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = (bsd_dom1_config >> 16) & 0x0f; + state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = (bsd_dom1_config >> 20) & 0x03; + state->g_pi.regs[PI_STATUS_REG] = 0; + + state->g_ai.regs[AI_DRAM_ADDR_REG] = 0; + state->g_ai.regs[AI_LEN_REG] = 0; + + state->g_vi.regs[VI_V_INTR_REG] = 1023; + state->g_vi.regs[VI_CURRENT_REG] = 0; + state->g_vi.regs[VI_H_START_REG] = 0; + + state->g_r4300.mi.regs[MI_INTR_REG] &= ~(MI_INTR_PI | MI_INTR_VI | MI_INTR_AI | MI_INTR_SP); + + if (state->g_rom && state->g_rom_size >= 0xfc0) + memcpy((unsigned char*)state->g_sp.mem+0x40, state->g_rom+0x40, 0xfc0); + + state->reg[19] = rom_type; /* s3 */ + state->reg[20] = tv_type; /* s4 */ + state->reg[21] = reset_type; /* s5 */ + state->reg[22] = state->g_si.pif.cic.seed;/* s6 */ + state->reg[23] = s7; /* s7 */ + + /* required by CIC x105 */ + state->g_sp.mem[0x1000/4] = 0x3c0dbfc0; + state->g_sp.mem[0x1004/4] = 0x8da807fc; + state->g_sp.mem[0x1008/4] = 0x25ad07c0; + state->g_sp.mem[0x100c/4] = 0x31080080; + state->g_sp.mem[0x1010/4] = 0x5500fffc; + state->g_sp.mem[0x1014/4] = 0x3c0dbfc0; + state->g_sp.mem[0x1018/4] = 0x8da80024; + state->g_sp.mem[0x101c/4] = 0x3c0bb000; + + /* required by CIC x105 */ + state->reg[11] = 0xffffffffa4000040ULL; /* t3 */ + state->reg[29] = 0xffffffffa4001ff0ULL; /* sp */ + state->reg[31] = 0xffffffffa4001550ULL; /* ra */ + + /* ready to execute IPL3 */ +} + +#if !defined(NO_ASM) +static void dynarec_setup_code() +{ + usf_state_t * state; +#ifdef _MSC_VER + _asm + { + mov state, esi + } +#else + asm volatile +#ifdef __x86_64__ + (" mov %%r15, (%[state]) \n" +#else + (" mov %%esi, (%[state]) \n" +#endif + : + : [state]"r"(&state) + : "memory" + ); +#endif + // The dynarec jumps here after we call dyna_start and it prepares + // Here we need to prepare the initial code block and jump to it + jump_to(state->last_addr); + + // Prevent segfault on failed jump_to + if (!state->actual || !state->actual->block || !state->actual->code) + dyna_stop(state); +} +#endif + +void r4300_begin(usf_state_t * state) +{ + state->current_instruction_table = cached_interpreter_table; + + state->delay_slot=0; + state->stop = 0; + state->rompause = 0; + + state->next_interupt = 624999; + init_interupt(state); + + if (state->r4300emu == CORE_PURE_INTERPRETER) + { + DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Pure Interpreter"); + state->r4300emu = CORE_PURE_INTERPRETER; + } +#if defined(DYNAREC) + else if (state->r4300emu >= 2) + { + DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Dynamic Recompiler"); + state->r4300emu = CORE_DYNAREC; + init_blocks(state); +#ifdef NEW_DYNAREC + new_dynarec_init(state); +#endif + } +#endif + else /* if (r4300emu == CORE_INTERPRETER) */ + { + DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Cached Interpreter"); + state->r4300emu = CORE_INTERPRETER; + init_blocks(state); + } +} + +void r4300_reset_checkpoint(usf_state_t * state, unsigned int new_cp0_count) +{ + unsigned int diff = state->g_cp0_regs[CP0_COUNT_REG] - state->g_timer_checkpoint; + state->g_timer_checkpoint = new_cp0_count - diff; +} + +void r4300_checkpoint(usf_state_t * state) +{ + if (state->g_cp0_regs[CP0_COUNT_REG] - state->g_timer_checkpoint >= state->count_per_op * 20000000) + { + if (state->last_sample_buffer_count == state->sample_buffer_count) + { + DebugMessage(state, 1, "Emulator appears to be stuck!"); + return; + } + state->last_sample_buffer_count = state->sample_buffer_count; + state->g_timer_checkpoint = state->g_cp0_regs[CP0_COUNT_REG]; + } +} + +void r4300_execute(usf_state_t * state) +{ + state->g_timer_checkpoint = state->g_cp0_regs[CP0_COUNT_REG]; + state->last_sample_buffer_count = state->sample_buffer_count; + + if (state->r4300emu == CORE_PURE_INTERPRETER) + { + pure_interpreter(state); + } +#if defined(DYNAREC) + else if (state->r4300emu == CORE_DYNAREC) + { +#ifdef NEW_DYNAREC + new_dyna_start(state); +#else + dyna_start(state, (void*)dynarec_setup_code); + state->PC++; +#endif + } +#endif + else /* if (r4300emu == CORE_INTERPRETER) */ + { + /* Prevent segfault on failed jump_to */ + if (!state->actual->block) + return; + + while (!state->stop) + { + r4300_checkpoint(state); + state->PC->ops(state); + } + } +} + +void r4300_end(usf_state_t * state) +{ + if (state->r4300emu == CORE_PURE_INTERPRETER) + { + } +#if defined(DYNAREC) + else if (state->r4300emu == CORE_DYNAREC) + { +#ifdef NEW_DYNAREC + new_dynarec_cleanup(state); +#endif + free_blocks(state); + } +#endif + else /* if (r4300emu == CORE_INTERPRETER) */ + { + free_blocks(state); + } + + DebugMessage(state, M64MSG_INFO, "R4300 emulator finished."); +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/r4300.h b/Frameworks/lazyusf/lazyusf/r4300/r4300.h new file mode 100644 index 000000000..4d3d2e36b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/r4300.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - r4300.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_R4300_H +#define M64P_R4300_R4300_H + +#include "usf/usf.h" + +#include "ops.h" +#include "recomp.h" + +#define COUNT_PER_OP_DEFAULT 2 + +void r4300_reset_hard(usf_state_t *); +void r4300_reset_soft(usf_state_t *); + +void r4300_begin(usf_state_t *); +void r4300_execute(usf_state_t *); +void r4300_end(usf_state_t *); + +void r4300_reset_checkpoint(usf_state_t *, unsigned int new_cp0_count); +void r4300_checkpoint(usf_state_t *); + +/* Jump to the given address. This works for all r4300 emulator, but is slower. + * Use this for common code which can be executed from any r4300 emulator. */ +void generic_jump_to(usf_state_t *, unsigned int address); + +// r4300 emulators +#define CORE_PURE_INTERPRETER 0 +#define CORE_INTERPRETER 1 +#define CORE_DYNAREC 2 + +#endif /* M64P_R4300_R4300_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/r4300_core.c b/Frameworks/lazyusf/lazyusf/r4300/r4300_core.c new file mode 100644 index 000000000..7944e5dc5 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/r4300_core.c @@ -0,0 +1,35 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - r4300_core.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "r4300_core.h" + +void init_r4300(struct r4300_core* r4300) +{ + init_mi(&r4300->mi); +} + +void connect_r4300(struct r4300_core* r4300, + usf_state_t* state) +{ + r4300->state = state; +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/r4300_core.h b/Frameworks/lazyusf/lazyusf/r4300/r4300_core.h new file mode 100644 index 000000000..1cfe44cfe --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/r4300_core.h @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - r4300_core.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_R4300_CORE_H +#define M64P_R4300_R4300_CORE_H + +#include "mi_controller.h" + +struct r4300_core +{ + struct mi_controller mi; + + usf_state_t* state; +}; + +void init_r4300(struct r4300_core* r4300); + +void connect_r4300(struct r4300_core* r4300, + usf_state_t* state); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/r4300/recomp.c b/Frameworks/lazyusf/lazyusf/r4300/recomp.c new file mode 100644 index 000000000..b45709c94 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/recomp.c @@ -0,0 +1,2577 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - recomp.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#if defined(__GNUC__) +#include +#ifndef __MINGW32__ +#include +#endif +#endif + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "memory/memory.h" + +#include "cached_interp.h" +#include "recomp.h" +#include "recomph.h" //include for function prototypes +#include "cp0.h" +#include "r4300.h" +#include "ops.h" +#include "tlb.h" + +static void *malloc_exec(usf_state_t *, size_t size); +static void free_exec(void *ptr, size_t length); + + + +static void RSV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.RESERVED; + state->recomp_func = genreserved; +} + +static void RFIN_BLOCK(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.FIN_BLOCK; + state->recomp_func = genfin_block; +} + +static void RNOTCOMPILED(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NOTCOMPILED; + state->recomp_func = gennotcompiled; +} + +static void recompile_standard_i_type(usf_state_t * state) +{ + state->dst->f.i.rs = state->reg + ((state->src >> 21) & 0x1F); + state->dst->f.i.rt = state->reg + ((state->src >> 16) & 0x1F); + state->dst->f.i.immediate = state->src & 0xFFFF; +} + +static void recompile_standard_j_type(usf_state_t * state) +{ + state->dst->f.j.inst_index = state->src & 0x3FFFFFF; +} + +static void recompile_standard_r_type(usf_state_t * state) +{ + state->dst->f.r.rs = state->reg + ((state->src >> 21) & 0x1F); + state->dst->f.r.rt = state->reg + ((state->src >> 16) & 0x1F); + state->dst->f.r.rd = state->reg + ((state->src >> 11) & 0x1F); + state->dst->f.r.sa = (state->src >> 6) & 0x1F; +} + +static void recompile_standard_lf_type(usf_state_t * state) +{ + state->dst->f.lf.base = (state->src >> 21) & 0x1F; + state->dst->f.lf.ft = (state->src >> 16) & 0x1F; + state->dst->f.lf.offset = state->src & 0xFFFF; +} + +static void recompile_standard_cf_type(usf_state_t * state) +{ + state->dst->f.cf.ft = (state->src >> 16) & 0x1F; + state->dst->f.cf.fs = (state->src >> 11) & 0x1F; + state->dst->f.cf.fd = (state->src >> 6) & 0x1F; +} + +//------------------------------------------------------------------------- +// SPECIAL +//------------------------------------------------------------------------- + +static void RNOP(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NOP; + state->recomp_func = gennop; +} + +static void RSLL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLL; + state->recomp_func = gensll; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSRL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SRL; + state->recomp_func = gensrl; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSRA(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SRA; + state->recomp_func = gensra; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSLLV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLLV; + state->recomp_func = gensllv; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSRLV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SRLV; + state->recomp_func = gensrlv; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSRAV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SRAV; + state->recomp_func = gensrav; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RJR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.JR; + state->recomp_func = genjr; + recompile_standard_i_type(state); +} + +static void RJALR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.JALR; + state->recomp_func = genjalr; + recompile_standard_r_type(state); +} + +static void RSYSCALL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SYSCALL; + state->recomp_func = gensyscall; +} + +/* Idle loop hack from 64th Note */ +static void RBREAK(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.BREAK; + state->recomp_func = genbreak; +} + +static void RSYNC(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SYNC; + state->recomp_func = gensync; +} + +static void RMFHI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MFHI; + state->recomp_func = genmfhi; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RMTHI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MTHI; + state->recomp_func = genmthi; + recompile_standard_r_type(state); +} + +static void RMFLO(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MFLO; + state->recomp_func = genmflo; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RMTLO(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MTLO; + state->recomp_func = genmtlo; + recompile_standard_r_type(state); +} + +static void RDSLLV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSLLV; + state->recomp_func = gendsllv; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRLV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRLV; + state->recomp_func = gendsrlv; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRAV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRAV; + state->recomp_func = gendsrav; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RMULT(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MULT; + state->recomp_func = genmult; + recompile_standard_r_type(state); +} + +static void RMULTU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MULTU; + state->recomp_func = genmultu; + recompile_standard_r_type(state); +} + +static void RDIV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DIV; + state->recomp_func = gendiv; + recompile_standard_r_type(state); +} + +static void RDIVU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DIVU; + state->recomp_func = gendivu; + recompile_standard_r_type(state); +} + +static void RDMULT(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DMULT; + state->recomp_func = gendmult; + recompile_standard_r_type(state); +} + +static void RDMULTU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DMULTU; + state->recomp_func = gendmultu; + recompile_standard_r_type(state); +} + +static void RDDIV(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DDIV; + state->recomp_func = genddiv; + recompile_standard_r_type(state); +} + +static void RDDIVU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DDIVU; + state->recomp_func = genddivu; + recompile_standard_r_type(state); +} + +static void RADD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADD; + state->recomp_func = genadd; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RADDU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADDU; + state->recomp_func = genaddu; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSUB(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SUB; + state->recomp_func = gensub; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSUBU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SUBU; + state->recomp_func = gensubu; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RAND(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.AND; + state->recomp_func = genand; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void ROR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.OR; + state->recomp_func = genor; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RXOR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.XOR; + state->recomp_func = genxor; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RNOR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NOR; + state->recomp_func = gennor; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSLT(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLT; + state->recomp_func = genslt; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RSLTU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLTU; + state->recomp_func = gensltu; + recompile_standard_r_type(state); + if(state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDADD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DADD; + state->recomp_func = gendadd; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDADDU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DADDU; + state->recomp_func = gendaddu; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSUB(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSUB; + state->recomp_func = gendsub; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSUBU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSUBU; + state->recomp_func = gendsubu; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RTGE(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTGEU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTLT(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTLTU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTEQ(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TEQ; + state->recomp_func = genteq; + recompile_standard_r_type(state); +} + +static void RTNE(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RDSLL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSLL; + state->recomp_func = gendsll; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRL; + state->recomp_func = gendsrl; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRA(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRA; + state->recomp_func = gendsra; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSLL32(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSLL32; + state->recomp_func = gendsll32; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRL32(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRL32; + state->recomp_func = gendsrl32; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void RDSRA32(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DSRA32; + state->recomp_func = gendsra32; + recompile_standard_r_type(state); + if (state->dst->f.r.rd == state->reg) RNOP(state); +} + +static void (*recomp_special[64])(usf_state_t *) = +{ + RSLL , RSV , RSRL , RSRA , RSLLV , RSV , RSRLV , RSRAV , + RJR , RJALR , RSV , RSV , RSYSCALL, RBREAK , RSV , RSYNC , + RMFHI, RMTHI , RMFLO, RMTLO, RDSLLV , RSV , RDSRLV , RDSRAV , + RMULT, RMULTU, RDIV , RDIVU, RDMULT , RDMULTU, RDDIV , RDDIVU , + RADD , RADDU , RSUB , RSUBU, RAND , ROR , RXOR , RNOR , + RSV , RSV , RSLT , RSLTU, RDADD , RDADDU , RDSUB , RDSUBU , + RTGE , RTGEU , RTLT , RTLTU, RTEQ , RSV , RTNE , RSV , + RDSLL, RSV , RDSRL, RDSRA, RDSLL32 , RSV , RDSRL32, RDSRA32 +}; + +//------------------------------------------------------------------------- +// REGIMM +//------------------------------------------------------------------------- + +static void RBLTZ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLTZ; + state->recomp_func = genbltz; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLTZ_IDLE; + state->recomp_func = genbltz_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLTZ_OUT; + state->recomp_func = genbltz_out; + } +} + +static void RBGEZ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGEZ; + state->recomp_func = genbgez; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGEZ_IDLE; + state->recomp_func = genbgez_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGEZ_OUT; + state->recomp_func = genbgez_out; + } +} + +static void RBLTZL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLTZL; + state->recomp_func = genbltzl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLTZL_IDLE; + state->recomp_func = genbltzl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLTZL_OUT; + state->recomp_func = genbltzl_out; + } +} + +static void RBGEZL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGEZL; + state->recomp_func = genbgezl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGEZL_IDLE; + state->recomp_func = genbgezl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGEZL_OUT; + state->recomp_func = genbgezl_out; + } +} + +static void RTGEI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTGEIU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTLTI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTLTIU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTEQI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RTNEI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; +} + +static void RBLTZAL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLTZAL; + state->recomp_func = genbltzal; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLTZAL_IDLE; + state->recomp_func = genbltzal_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLTZAL_OUT; + state->recomp_func = genbltzal_out; + } +} + +static void RBGEZAL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGEZAL; + state->recomp_func = genbgezal; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGEZAL_IDLE; + state->recomp_func = genbgezal_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGEZAL_OUT; + state->recomp_func = genbgezal_out; + } +} + +static void RBLTZALL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLTZALL; + state->recomp_func = genbltzall; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLTZALL_IDLE; + state->recomp_func = genbltzall_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLTZALL_OUT; + state->recomp_func = genbltzall_out; + } +} + +static void RBGEZALL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGEZALL; + state->recomp_func = genbgezall; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGEZALL_IDLE; + state->recomp_func = genbgezall_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGEZALL_OUT; + state->recomp_func = genbgezall_out; + } +} + +static void (*recomp_regimm[32])(usf_state_t *) = +{ + RBLTZ , RBGEZ , RBLTZL , RBGEZL , RSV , RSV, RSV , RSV, + RTGEI , RTGEIU , RTLTI , RTLTIU , RTEQI, RSV, RTNEI, RSV, + RBLTZAL, RBGEZAL, RBLTZALL, RBGEZALL, RSV , RSV, RSV , RSV, + RSV , RSV , RSV , RSV , RSV , RSV, RSV , RSV +}; + +//------------------------------------------------------------------------- +// TLB +//------------------------------------------------------------------------- + +static void RTLBR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TLBR; + state->recomp_func = gentlbr; +} + +static void RTLBWI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TLBWI; + state->recomp_func = gentlbwi; +} + +static void RTLBWR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TLBWR; + state->recomp_func = gentlbwr; +} + +static void RTLBP(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TLBP; + state->recomp_func = gentlbp; +} + +static void RERET(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ERET; + state->recomp_func = generet; +} + +static void (*recomp_tlb[64])(usf_state_t *) = +{ + RSV , RTLBR, RTLBWI, RSV, RSV, RSV, RTLBWR, RSV, + RTLBP, RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RSV , RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RERET, RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RSV , RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RSV , RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RSV , RSV , RSV , RSV, RSV, RSV, RSV , RSV, + RSV , RSV , RSV , RSV, RSV, RSV, RSV , RSV +}; + +//------------------------------------------------------------------------- +// COP0 +//------------------------------------------------------------------------- + +static void RMFC0(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MFC0; + state->recomp_func = genmfc0; + recompile_standard_r_type(state); + state->dst->f.r.rd = (long long*)(state->g_cp0_regs + ((state->src >> 11) & 0x1F)); + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; + if (state->dst->f.r.rt == state->reg) RNOP(state); +} + +static void RMTC0(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MTC0; + state->recomp_func = genmtc0; + recompile_standard_r_type(state); + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; +} + +static void RTLB(usf_state_t * state) +{ + recomp_tlb[(state->src & 0x3F)](state); +} + +static void (*recomp_cop0[32])(usf_state_t *) = +{ + RMFC0, RSV, RSV, RSV, RMTC0, RSV, RSV, RSV, + RSV , RSV, RSV, RSV, RSV , RSV, RSV, RSV, + RTLB , RSV, RSV, RSV, RSV , RSV, RSV, RSV, + RSV , RSV, RSV, RSV, RSV , RSV, RSV, RSV +}; + +//------------------------------------------------------------------------- +// BC +//------------------------------------------------------------------------- + +static void RBC1F(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BC1F; + state->recomp_func = genbc1f; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BC1F_IDLE; + state->recomp_func = genbc1f_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BC1F_OUT; + state->recomp_func = genbc1f_out; + } +} + +static void RBC1T(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BC1T; + state->recomp_func = genbc1t; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BC1T_IDLE; + state->recomp_func = genbc1t_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BC1T_OUT; + state->recomp_func = genbc1t_out; + } +} + +static void RBC1FL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BC1FL; + state->recomp_func = genbc1fl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BC1FL_IDLE; + state->recomp_func = genbc1fl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BC1FL_OUT; + state->recomp_func = genbc1fl_out; + } +} + +static void RBC1TL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BC1TL; + state->recomp_func = genbc1tl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BC1TL_IDLE; + state->recomp_func = genbc1tl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BC1TL_OUT; + state->recomp_func = genbc1tl_out; + } +} + +static void (*recomp_bc[4])(usf_state_t *) = +{ + RBC1F , RBC1T , + RBC1FL, RBC1TL +}; + +//------------------------------------------------------------------------- +// S +//------------------------------------------------------------------------- + +static void RADD_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADD_S; + state->recomp_func = genadd_s; + recompile_standard_cf_type(state); +} + +static void RSUB_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SUB_S; + state->recomp_func = gensub_s; + recompile_standard_cf_type(state); +} + +static void RMUL_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MUL_S; + state->recomp_func = genmul_s; + recompile_standard_cf_type(state); +} + +static void RDIV_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DIV_S; + state->recomp_func = gendiv_s; + recompile_standard_cf_type(state); +} + +static void RSQRT_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SQRT_S; + state->recomp_func = gensqrt_s; + recompile_standard_cf_type(state); +} + +static void RABS_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ABS_S; + state->recomp_func = genabs_s; + recompile_standard_cf_type(state); +} + +static void RMOV_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MOV_S; + state->recomp_func = genmov_s; + recompile_standard_cf_type(state); +} + +static void RNEG_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NEG_S; + state->recomp_func = genneg_s; + recompile_standard_cf_type(state); +} + +static void RROUND_L_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ROUND_L_S; + state->recomp_func = genround_l_s; + recompile_standard_cf_type(state); +} + +static void RTRUNC_L_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TRUNC_L_S; + state->recomp_func = gentrunc_l_s; + recompile_standard_cf_type(state); +} + +static void RCEIL_L_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CEIL_L_S; + state->recomp_func = genceil_l_s; + recompile_standard_cf_type(state); +} + +static void RFLOOR_L_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.FLOOR_L_S; + state->recomp_func = genfloor_l_s; + recompile_standard_cf_type(state); +} + +static void RROUND_W_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ROUND_W_S; + state->recomp_func = genround_w_s; + recompile_standard_cf_type(state); +} + +static void RTRUNC_W_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TRUNC_W_S; + state->recomp_func = gentrunc_w_s; + recompile_standard_cf_type(state); +} + +static void RCEIL_W_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CEIL_W_S; + state->recomp_func = genceil_w_s; + recompile_standard_cf_type(state); +} + +static void RFLOOR_W_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.FLOOR_W_S; + state->recomp_func = genfloor_w_s; + recompile_standard_cf_type(state); +} + +static void RCVT_D_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_D_S; + state->recomp_func = gencvt_d_s; + recompile_standard_cf_type(state); +} + +static void RCVT_W_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_W_S; + state->recomp_func = gencvt_w_s; + recompile_standard_cf_type(state); +} + +static void RCVT_L_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_L_S; + state->recomp_func = gencvt_l_s; + recompile_standard_cf_type(state); +} + +static void RC_F_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_F_S; + state->recomp_func = genc_f_s; + recompile_standard_cf_type(state); +} + +static void RC_UN_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_UN_S; + state->recomp_func = genc_un_s; + recompile_standard_cf_type(state); +} + +static void RC_EQ_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_EQ_S; + state->recomp_func = genc_eq_s; + recompile_standard_cf_type(state); +} + +static void RC_UEQ_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_UEQ_S; + state->recomp_func = genc_ueq_s; + recompile_standard_cf_type(state); +} + +static void RC_OLT_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_OLT_S; + state->recomp_func = genc_olt_s; + recompile_standard_cf_type(state); +} + +static void RC_ULT_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_ULT_S; + state->recomp_func = genc_ult_s; + recompile_standard_cf_type(state); +} + +static void RC_OLE_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_OLE_S; + state->recomp_func = genc_ole_s; + recompile_standard_cf_type(state); +} + +static void RC_ULE_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_ULE_S; + state->recomp_func = genc_ule_s; + recompile_standard_cf_type(state); +} + +static void RC_SF_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_SF_S; + state->recomp_func = genc_sf_s; + recompile_standard_cf_type(state); +} + +static void RC_NGLE_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGLE_S; + state->recomp_func = genc_ngle_s; + recompile_standard_cf_type(state); +} + +static void RC_SEQ_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_SEQ_S; + state->recomp_func = genc_seq_s; + recompile_standard_cf_type(state); +} + +static void RC_NGL_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGL_S; + state->recomp_func = genc_ngl_s; + recompile_standard_cf_type(state); +} + +static void RC_LT_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_LT_S; + state->recomp_func = genc_lt_s; + recompile_standard_cf_type(state); +} + +static void RC_NGE_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGE_S; + state->recomp_func = genc_nge_s; + recompile_standard_cf_type(state); +} + +static void RC_LE_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_LE_S; + state->recomp_func = genc_le_s; + recompile_standard_cf_type(state); +} + +static void RC_NGT_S(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGT_S; + state->recomp_func = genc_ngt_s; + recompile_standard_cf_type(state); +} + +static void (*recomp_s[64])(usf_state_t *) = +{ + RADD_S , RSUB_S , RMUL_S , RDIV_S , RSQRT_S , RABS_S , RMOV_S , RNEG_S , + RROUND_L_S, RTRUNC_L_S, RCEIL_L_S, RFLOOR_L_S, RROUND_W_S, RTRUNC_W_S, RCEIL_W_S, RFLOOR_W_S, + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RSV , RCVT_D_S , RSV , RSV , RCVT_W_S , RCVT_L_S , RSV , RSV , + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RC_F_S , RC_UN_S , RC_EQ_S , RC_UEQ_S , RC_OLT_S , RC_ULT_S , RC_OLE_S , RC_ULE_S , + RC_SF_S , RC_NGLE_S , RC_SEQ_S , RC_NGL_S , RC_LT_S , RC_NGE_S , RC_LE_S , RC_NGT_S +}; + +//------------------------------------------------------------------------- +// D +//------------------------------------------------------------------------- + +static void RADD_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADD_D; + state->recomp_func = genadd_d; + recompile_standard_cf_type(state); +} + +static void RSUB_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SUB_D; + state->recomp_func = gensub_d; + recompile_standard_cf_type(state); +} + +static void RMUL_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MUL_D; + state->recomp_func = genmul_d; + recompile_standard_cf_type(state); +} + +static void RDIV_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DIV_D; + state->recomp_func = gendiv_d; + recompile_standard_cf_type(state); +} + +static void RSQRT_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SQRT_D; + state->recomp_func = gensqrt_d; + recompile_standard_cf_type(state); +} + +static void RABS_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ABS_D; + state->recomp_func = genabs_d; + recompile_standard_cf_type(state); +} + +static void RMOV_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MOV_D; + state->recomp_func = genmov_d; + recompile_standard_cf_type(state); +} + +static void RNEG_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NEG_D; + state->recomp_func = genneg_d; + recompile_standard_cf_type(state); +} + +static void RROUND_L_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ROUND_L_D; + state->recomp_func = genround_l_d; + recompile_standard_cf_type(state); +} + +static void RTRUNC_L_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TRUNC_L_D; + state->recomp_func = gentrunc_l_d; + recompile_standard_cf_type(state); +} + +static void RCEIL_L_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CEIL_L_D; + state->recomp_func = genceil_l_d; + recompile_standard_cf_type(state); +} + +static void RFLOOR_L_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.FLOOR_L_D; + state->recomp_func = genfloor_l_d; + recompile_standard_cf_type(state); +} + +static void RROUND_W_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ROUND_W_D; + state->recomp_func = genround_w_d; + recompile_standard_cf_type(state); +} + +static void RTRUNC_W_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.TRUNC_W_D; + state->recomp_func = gentrunc_w_d; + recompile_standard_cf_type(state); +} + +static void RCEIL_W_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CEIL_W_D; + state->recomp_func = genceil_w_d; + recompile_standard_cf_type(state); +} + +static void RFLOOR_W_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.FLOOR_W_D; + state->recomp_func = genfloor_w_d; + recompile_standard_cf_type(state); +} + +static void RCVT_S_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_S_D; + state->recomp_func = gencvt_s_d; + recompile_standard_cf_type(state); +} + +static void RCVT_W_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_W_D; + state->recomp_func = gencvt_w_d; + recompile_standard_cf_type(state); +} + +static void RCVT_L_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_L_D; + state->recomp_func = gencvt_l_d; + recompile_standard_cf_type(state); +} + +static void RC_F_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_F_D; + state->recomp_func = genc_f_d; + recompile_standard_cf_type(state); +} + +static void RC_UN_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_UN_D; + state->recomp_func = genc_un_d; + recompile_standard_cf_type(state); +} + +static void RC_EQ_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_EQ_D; + state->recomp_func = genc_eq_d; + recompile_standard_cf_type(state); +} + +static void RC_UEQ_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_UEQ_D; + state->recomp_func = genc_ueq_d; + recompile_standard_cf_type(state); +} + +static void RC_OLT_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_OLT_D; + state->recomp_func = genc_olt_d; + recompile_standard_cf_type(state); +} + +static void RC_ULT_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_ULT_D; + state->recomp_func = genc_ult_d; + recompile_standard_cf_type(state); +} + +static void RC_OLE_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_OLE_D; + state->recomp_func = genc_ole_d; + recompile_standard_cf_type(state); +} + +static void RC_ULE_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_ULE_D; + state->recomp_func = genc_ule_d; + recompile_standard_cf_type(state); +} + +static void RC_SF_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_SF_D; + state->recomp_func = genc_sf_d; + recompile_standard_cf_type(state); +} + +static void RC_NGLE_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGLE_D; + state->recomp_func = genc_ngle_d; + recompile_standard_cf_type(state); +} + +static void RC_SEQ_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_SEQ_D; + state->recomp_func = genc_seq_d; + recompile_standard_cf_type(state); +} + +static void RC_NGL_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGL_D; + state->recomp_func = genc_ngl_d; + recompile_standard_cf_type(state); +} + +static void RC_LT_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_LT_D; + state->recomp_func = genc_lt_d; + recompile_standard_cf_type(state); +} + +static void RC_NGE_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGE_D; + state->recomp_func = genc_nge_d; + recompile_standard_cf_type(state); +} + +static void RC_LE_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_LE_D; + state->recomp_func = genc_le_d; + recompile_standard_cf_type(state); +} + +static void RC_NGT_D(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.C_NGT_D; + state->recomp_func = genc_ngt_d; + recompile_standard_cf_type(state); +} + +static void (*recomp_d[64])(usf_state_t *) = +{ + RADD_D , RSUB_D , RMUL_D , RDIV_D , RSQRT_D , RABS_D , RMOV_D , RNEG_D , + RROUND_L_D, RTRUNC_L_D, RCEIL_L_D, RFLOOR_L_D, RROUND_W_D, RTRUNC_W_D, RCEIL_W_D, RFLOOR_W_D, + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RCVT_S_D , RSV , RSV , RSV , RCVT_W_D , RCVT_L_D , RSV , RSV , + RSV , RSV , RSV , RSV , RSV , RSV , RSV , RSV , + RC_F_D , RC_UN_D , RC_EQ_D , RC_UEQ_D , RC_OLT_D , RC_ULT_D , RC_OLE_D , RC_ULE_D , + RC_SF_D , RC_NGLE_D , RC_SEQ_D , RC_NGL_D , RC_LT_D , RC_NGE_D , RC_LE_D , RC_NGT_D +}; + +//------------------------------------------------------------------------- +// W +//------------------------------------------------------------------------- + +static void RCVT_S_W(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_S_W; + state->recomp_func = gencvt_s_w; + recompile_standard_cf_type(state); +} + +static void RCVT_D_W(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_D_W; + state->recomp_func = gencvt_d_w; + recompile_standard_cf_type(state); +} + +static void (*recomp_w[64])(usf_state_t *) = +{ + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RCVT_S_W, RCVT_D_W, RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV +}; + +//------------------------------------------------------------------------- +// L +//------------------------------------------------------------------------- + +static void RCVT_S_L(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_S_L; + state->recomp_func = gencvt_s_l; + recompile_standard_cf_type(state); +} + +static void RCVT_D_L(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CVT_D_L; + state->recomp_func = gencvt_d_l; + recompile_standard_cf_type(state); +} + +static void (*recomp_l[64])(usf_state_t *) = +{ + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RCVT_S_L, RCVT_D_L, RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, + RSV , RSV , RSV, RSV, RSV, RSV, RSV, RSV, +}; + +//------------------------------------------------------------------------- +// COP1 +//------------------------------------------------------------------------- + +static void RMFC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MFC1; + state->recomp_func = genmfc1; + recompile_standard_r_type(state); + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; + if (state->dst->f.r.rt == state->reg) RNOP(state); +} + +static void RDMFC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DMFC1; + state->recomp_func = gendmfc1; + recompile_standard_r_type(state); + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; + if (state->dst->f.r.rt == state->reg) RNOP(state); +} + +static void RCFC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CFC1; + state->recomp_func = gencfc1; + recompile_standard_r_type(state); + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; + if (state->dst->f.r.rt == state->reg) RNOP(state); +} + +static void RMTC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.MTC1; + recompile_standard_r_type(state); + state->recomp_func = genmtc1; + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; +} + +static void RDMTC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DMTC1; + recompile_standard_r_type(state); + state->recomp_func = gendmtc1; + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; +} + +static void RCTC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.CTC1; + recompile_standard_r_type(state); + state->recomp_func = genctc1; + state->dst->f.r.nrd = (state->src >> 11) & 0x1F; +} + +static void RBC(usf_state_t * state) +{ + recomp_bc[((state->src >> 16) & 3)](state); +} + +static void RS(usf_state_t * state) +{ + recomp_s[(state->src & 0x3F)](state); +} + +static void RD(usf_state_t * state) +{ + recomp_d[(state->src & 0x3F)](state); +} + +static void RW(usf_state_t * state) +{ + recomp_w[(state->src & 0x3F)](state); +} + +static void RL(usf_state_t * state) +{ + recomp_l[(state->src & 0x3F)](state); +} + +static void (*recomp_cop1[32])(usf_state_t *) = +{ + RMFC1, RDMFC1, RCFC1, RSV, RMTC1, RDMTC1, RCTC1, RSV, + RBC , RSV , RSV , RSV, RSV , RSV , RSV , RSV, + RS , RD , RSV , RSV, RW , RL , RSV , RSV, + RSV , RSV , RSV , RSV, RSV , RSV , RSV , RSV +}; + +//------------------------------------------------------------------------- +// R4300 +//------------------------------------------------------------------------- + +static void RSPECIAL(usf_state_t * state) +{ + recomp_special[(state->src & 0x3F)](state); +} + +static void RREGIMM(usf_state_t * state) +{ + recomp_regimm[((state->src >> 16) & 0x1F)](state); +} + +static void RJ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.J; + state->recomp_func = genj; + recompile_standard_j_type(state); + target = (state->dst->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.J_IDLE; + state->recomp_func = genj_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.J_OUT; + state->recomp_func = genj_out; + } +} + +static void RJAL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.JAL; + state->recomp_func = genjal; + recompile_standard_j_type(state); + target = (state->dst->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.JAL_IDLE; + state->recomp_func = genjal_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.JAL_OUT; + state->recomp_func = genjal_out; + } +} + +static void RBEQ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BEQ; + state->recomp_func = genbeq; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BEQ_IDLE; + state->recomp_func = genbeq_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BEQ_OUT; + state->recomp_func = genbeq_out; + } +} + +static void RBNE(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BNE; + state->recomp_func = genbne; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BNE_IDLE; + state->recomp_func = genbne_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BNE_OUT; + state->recomp_func = genbne_out; + } +} + +static void RBLEZ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLEZ; + state->recomp_func = genblez; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLEZ_IDLE; + state->recomp_func = genblez_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLEZ_OUT; + state->recomp_func = genblez_out; + } +} + +static void RBGTZ(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGTZ; + state->recomp_func = genbgtz; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGTZ_IDLE; + state->recomp_func = genbgtz_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGTZ_OUT; + state->recomp_func = genbgtz_out; + } +} + +static void RADDI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADDI; + state->recomp_func = genaddi; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RADDIU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ADDIU; + state->recomp_func = genaddiu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RSLTI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLTI; + state->recomp_func = genslti; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RSLTIU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SLTIU; + state->recomp_func = gensltiu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RANDI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ANDI; + state->recomp_func = genandi; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RORI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.ORI; + state->recomp_func = genori; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RXORI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.XORI; + state->recomp_func = genxori; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLUI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LUI; + state->recomp_func = genlui; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RCOP0(usf_state_t * state) +{ + recomp_cop0[((state->src >> 21) & 0x1F)](state); +} + +static void RCOP1(usf_state_t * state) +{ + recomp_cop1[((state->src >> 21) & 0x1F)](state); +} + +static void RBEQL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BEQL; + state->recomp_func = genbeql; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BEQL_IDLE; + state->recomp_func = genbeql_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BEQL_OUT; + state->recomp_func = genbeql_out; + } +} + +static void RBNEL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BNEL; + state->recomp_func = genbnel; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BNEL_IDLE; + state->recomp_func = genbnel_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BNEL_OUT; + state->recomp_func = genbnel_out; + } +} + +static void RBLEZL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BLEZL; + state->recomp_func = genblezl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BLEZL_IDLE; + state->recomp_func = genblezl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BLEZL_OUT; + state->recomp_func = genblezl_out; + } +} + +static void RBGTZL(usf_state_t * state) +{ + unsigned int target; + state->dst->ops = state->current_instruction_table.BGTZL; + state->recomp_func = genbgtzl; + recompile_standard_i_type(state); + target = state->dst->addr + state->dst->f.i.immediate*4 + 4; + if (target == state->dst->addr) + { + if (state->check_nop) + { + state->dst->ops = state->current_instruction_table.BGTZL_IDLE; + state->recomp_func = genbgtzl_idle; + } + } + else if (target < state->dst_block->start || target >= state->dst_block->end || state->dst->addr == (state->dst_block->end-4)) + { + state->dst->ops = state->current_instruction_table.BGTZL_OUT; + state->recomp_func = genbgtzl_out; + } +} + +static void RDADDI(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DADDI; + state->recomp_func = gendaddi; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RDADDIU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.DADDIU; + state->recomp_func = gendaddiu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLDL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LDL; + state->recomp_func = genldl; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLDR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LDR; + state->recomp_func = genldr; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLB(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LB; + state->recomp_func = genlb; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLH(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LH; + state->recomp_func = genlh; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLWL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LWL; + state->recomp_func = genlwl; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLW(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LW; + state->recomp_func = genlw; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLBU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LBU; + state->recomp_func = genlbu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLHU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LHU; + state->recomp_func = genlhu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLWR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LWR; + state->recomp_func = genlwr; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLWU(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LWU; + state->recomp_func = genlwu; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RSB(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SB; + state->recomp_func = gensb; + recompile_standard_i_type(state); +} + +static void RSH(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SH; + state->recomp_func = gensh; + recompile_standard_i_type(state); +} + +static void RSWL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SWL; + state->recomp_func = genswl; + recompile_standard_i_type(state); +} + +static void RSW(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SW; + state->recomp_func = gensw; + recompile_standard_i_type(state); +} + +static void RSDL(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SDL; + state->recomp_func = gensdl; + recompile_standard_i_type(state); +} + +static void RSDR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SDR; + state->recomp_func = gensdr; + recompile_standard_i_type(state); +} + +static void RSWR(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SWR; + state->recomp_func = genswr; + recompile_standard_i_type(state); +} + +static void RCACHE(usf_state_t * state) +{ + state->recomp_func = gencache; + state->dst->ops = state->current_instruction_table.CACHE; +} + +static void RLL(usf_state_t * state) +{ + state->recomp_func = genll; + state->dst->ops = state->current_instruction_table.LL; + recompile_standard_i_type(state); + if(state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RLWC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LWC1; + state->recomp_func = genlwc1; + recompile_standard_lf_type(state); +} + +static void RLLD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; + recompile_standard_i_type(state); +} + +static void RLDC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LDC1; + state->recomp_func = genldc1; + recompile_standard_lf_type(state); +} + +static void RLD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.LD; + state->recomp_func = genld; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RSC(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SC; + state->recomp_func = gensc; + recompile_standard_i_type(state); + if (state->dst->f.i.rt == state->reg) RNOP(state); +} + +static void RSWC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SWC1; + state->recomp_func = genswc1; + recompile_standard_lf_type(state); +} + +static void RSCD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.NI; + state->recomp_func = genni; + recompile_standard_i_type(state); +} + +static void RSDC1(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SDC1; + state->recomp_func = gensdc1; + recompile_standard_lf_type(state); +} + +static void RSD(usf_state_t * state) +{ + state->dst->ops = state->current_instruction_table.SD; + state->recomp_func = gensd; + recompile_standard_i_type(state); +} + +static void (*recomp_ops[64])(usf_state_t *) = +{ + RSPECIAL, RREGIMM, RJ , RJAL , RBEQ , RBNE , RBLEZ , RBGTZ , + RADDI , RADDIU , RSLTI, RSLTIU, RANDI, RORI , RXORI , RLUI , + RCOP0 , RCOP1 , RSV , RSV , RBEQL, RBNEL, RBLEZL, RBGTZL, + RDADDI , RDADDIU, RLDL , RLDR , RSV , RSV , RSV , RSV , + RLB , RLH , RLWL , RLW , RLBU , RLHU , RLWR , RLWU , + RSB , RSH , RSWL , RSW , RSDL , RSDR , RSWR , RCACHE, + RLL , RLWC1 , RSV , RSV , RLLD , RLDC1, RSV , RLD , + RSC , RSWC1 , RSV , RSV , RSCD , RSDC1, RSV , RSD +}; + +static int get_block_length(const precomp_block *block) +{ + return (block->end-block->start)/4; +} + +static size_t get_block_memsize(const precomp_block *block) +{ + int length = get_block_length(block); + return ((length+1)+(length>>2)) * sizeof(precomp_instr); +} + +/********************************************************************** + ******************** initialize an empty block *********************** + **********************************************************************/ +void init_block(usf_state_t * state, precomp_block *block) +{ + int i, length, already_exist = 1; + + length = get_block_length(block); + + if (!block->block) + { + size_t memsize = get_block_memsize(block); + if (state->r4300emu == CORE_DYNAREC) { + block->block = (precomp_instr *) malloc_exec(state, memsize); + if (!block->block) { + DebugMessage(state, M64MSG_ERROR, "Memory error: couldn't allocate executable memory for dynamic recompiler. Try to use an interpreter mode."); + return; + } + } + else { + block->block = (precomp_instr *) malloc(memsize); + if (!block->block) { + DebugMessage(state, M64MSG_ERROR, "Memory error: couldn't allocate memory for cached interpreter."); + return; + } + } + + memset(block->block, 0, memsize); + already_exist = 0; + } + + if (state->r4300emu == CORE_DYNAREC) + { + if (!block->code) + { + state->max_code_length = 32768; + block->code = (unsigned char *) malloc_exec(state, state->max_code_length); + } + else + { + state->max_code_length = block->max_code_length; + } + state->code_length = 0; + state->inst_pointer = &block->code; + + if (block->jumps_table) + { + free(block->jumps_table); + block->jumps_table = NULL; + } + if (block->riprel_table) + { + free(block->riprel_table); + block->riprel_table = NULL; + } + init_assembler(state, NULL, 0, NULL, 0); + init_cache(state, block->block); + } + + if (!already_exist) + { + for (i=0; idst = block->block + i; + state->dst->addr = block->start + i*4; + state->dst->reg_cache_infos.need_map = 0; + state->dst->local_addr = state->code_length; + RNOTCOMPILED(state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + } + state->init_length = state->code_length; + } + else + { + state->code_length = state->init_length; /* recompile everything, overwrite old recompiled instructions */ + for (i=0; idst = block->block + i; + state->dst->reg_cache_infos.need_map = 0; + state->dst->local_addr = i * (state->init_length / length); + state->dst->ops = state->current_instruction_table.NOTCOMPILED; + } + } + + if (state->r4300emu == CORE_DYNAREC) + { + free_all_registers(state); + /* calling pass2 of the assembler is not necessary here because all of the code emitted by + gennotcompiled() and gendebug() is position-independent and contains no jumps . */ + block->code_length = state->code_length; + block->max_code_length = state->max_code_length; + free_assembler(state, &block->jumps_table, &block->jumps_number, &block->riprel_table, &block->riprel_number); + } + + /* here we're marking the block as a valid code even if it's not compiled + * yet as the game should have already set up the code correctly. + */ + state->invalid_code[block->start>>12] = 0; + if (block->end < 0x80000000 || block->start >= 0xc0000000) + { + unsigned int paddr; + + paddr = virtual_to_physical_address(state, block->start, 2); + state->invalid_code[paddr>>12] = 0; + if (!state->blocks[paddr>>12]) + { + state->blocks[paddr>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + state->blocks[paddr>>12]->code = NULL; + state->blocks[paddr>>12]->block = NULL; + state->blocks[paddr>>12]->jumps_table = NULL; + state->blocks[paddr>>12]->riprel_table = NULL; + state->blocks[paddr>>12]->start = paddr & ~0xFFF; + state->blocks[paddr>>12]->end = (paddr & ~0xFFF) + 0x1000; + } + init_block(state, state->blocks[paddr>>12]); + + paddr += block->end - block->start - 4; + state->invalid_code[paddr>>12] = 0; + if (!state->blocks[paddr>>12]) + { + state->blocks[paddr>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + state->blocks[paddr>>12]->code = NULL; + state->blocks[paddr>>12]->block = NULL; + state->blocks[paddr>>12]->jumps_table = NULL; + state->blocks[paddr>>12]->riprel_table = NULL; + state->blocks[paddr>>12]->start = paddr & ~0xFFF; + state->blocks[paddr>>12]->end = (paddr & ~0xFFF) + 0x1000; + } + init_block(state, state->blocks[paddr>>12]); + } + else + { + if (block->start >= 0x80000000 && block->end < 0xa0000000 && state->invalid_code[(block->start+0x20000000)>>12]) + { + if (!state->blocks[(block->start+0x20000000)>>12]) + { + state->blocks[(block->start+0x20000000)>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + state->blocks[(block->start+0x20000000)>>12]->code = NULL; + state->blocks[(block->start+0x20000000)>>12]->block = NULL; + state->blocks[(block->start+0x20000000)>>12]->jumps_table = NULL; + state->blocks[(block->start+0x20000000)>>12]->riprel_table = NULL; + state->blocks[(block->start+0x20000000)>>12]->start = (block->start+0x20000000) & ~0xFFF; + state->blocks[(block->start+0x20000000)>>12]->end = ((block->start+0x20000000) & ~0xFFF) + 0x1000; + } + init_block(state, state->blocks[(block->start+0x20000000)>>12]); + } + if (block->start >= 0xa0000000 && block->end < 0xc0000000 && state->invalid_code[(block->start-0x20000000)>>12]) + { + if (!state->blocks[(block->start-0x20000000)>>12]) + { + state->blocks[(block->start-0x20000000)>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + state->blocks[(block->start-0x20000000)>>12]->code = NULL; + state->blocks[(block->start-0x20000000)>>12]->block = NULL; + state->blocks[(block->start-0x20000000)>>12]->jumps_table = NULL; + state->blocks[(block->start-0x20000000)>>12]->riprel_table = NULL; + state->blocks[(block->start-0x20000000)>>12]->start = (block->start-0x20000000) & ~0xFFF; + state->blocks[(block->start-0x20000000)>>12]->end = ((block->start-0x20000000) & ~0xFFF) + 0x1000; + } + init_block(state, state->blocks[(block->start-0x20000000)>>12]); + } + } +} + +void free_block(usf_state_t * state, precomp_block *block) +{ + size_t memsize = get_block_memsize(block); + + if (block->block) { + if (state->r4300emu == CORE_DYNAREC) + free_exec(block->block, memsize); + else + free(block->block); + block->block = NULL; + } + if (block->code) { free_exec(block->code, block->max_code_length); block->code = NULL; } + if (block->jumps_table) { free(block->jumps_table); block->jumps_table = NULL; } + if (block->riprel_table) { free(block->riprel_table); block->riprel_table = NULL; } +} + +/********************************************************************** + ********************* recompile a block of code ********************** + **********************************************************************/ +void recompile_block(usf_state_t * state, int *source, precomp_block *block, unsigned int func) +{ + int i, length, finished=0; + length = (block->end-block->start)/4; + state->dst_block = block; + + //for (i=0; i<16; i++) block->md5[i] = 0; + block->adler32 = 0; + + if (state->r4300emu == CORE_DYNAREC) + { + state->code_length = block->code_length; + state->max_code_length = block->max_code_length; + state->inst_pointer = &block->code; + init_assembler(state, block->jumps_table, block->jumps_number, block->riprel_table, block->riprel_number); + init_cache(state, block->block + (func & 0xFFF) / 4); + } + + for (i = (func & 0xFFF) / 4; finished != 2; i++) + { + if(block->start < 0x80000000 || block->start >= 0xc0000000) + { + unsigned int address2 = + virtual_to_physical_address(state, block->start + i*4, 0); + if(state->blocks[address2>>12]->block[(address2&0xFFF)/4].ops == state->current_instruction_table.NOTCOMPILED) + state->blocks[address2>>12]->block[(address2&0xFFF)/4].ops = state->current_instruction_table.NOTCOMPILED2; + } + + state->SRC = source + i; + state->src = source[i]; + state->check_nop = source[i+1] == 0; + state->dst = block->block + i; + state->dst->addr = block->start + i*4; + state->dst->reg_cache_infos.need_map = 0; + state->dst->local_addr = state->code_length; + state->recomp_func = NULL; + recomp_ops[((state->src >> 26) & 0x3F)](state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + state->dst = block->block + i; + + /*if ((dst+1)->ops != NOTCOMPILED && !delay_slot_compiled && + i < length) + { + if (r4300emu == CORE_DYNAREC) genlink_subblock(); + finished = 2; + }*/ + if (state->delay_slot_compiled) + { + state->delay_slot_compiled--; + free_all_registers(state); + } + + if (i >= length-2+(length>>2)) finished = 2; + if (i >= (length-1) && (block->start == 0xa4000000 || + block->start >= 0xc0000000 || + block->end < 0x80000000)) finished = 2; + if (state->dst->ops == state->current_instruction_table.ERET || finished == 1) finished = 2; + if (/*i >= length &&*/ + (state->dst->ops == state->current_instruction_table.J || + state->dst->ops == state->current_instruction_table.J_OUT || + state->dst->ops == state->current_instruction_table.JR) && + !(i >= (length-1) && (block->start >= 0xc0000000 || + block->end < 0x80000000))) + finished = 1; + } + + if (i >= length) + { + state->dst = block->block + i; + state->dst->addr = block->start + i*4; + state->dst->reg_cache_infos.need_map = 0; + state->dst->local_addr = state->code_length; + RFIN_BLOCK(state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + i++; + if (i < length-1+(length>>2)) // useful when last opcode is a jump + { + state->dst = block->block + i; + state->dst->addr = block->start + i*4; + state->dst->reg_cache_infos.need_map = 0; + state->dst->local_addr = state->code_length; + RFIN_BLOCK(state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + i++; + } + } + else if (state->r4300emu == CORE_DYNAREC) genlink_subblock(state); + + if (state->r4300emu == CORE_DYNAREC) + { + free_all_registers(state); + passe2(state, block->block, (func&0xFFF)/4, i, block); + block->code_length = state->code_length; + block->max_code_length = state->max_code_length; + free_assembler(state, &block->jumps_table, &block->jumps_number, &block->riprel_table, &block->riprel_number); + } +} + +static int is_jump(usf_state_t * state) +{ + recomp_ops[((state->src >> 26) & 0x3F)](state); + return + (state->dst->ops == state->current_instruction_table.J || + state->dst->ops == state->current_instruction_table.J_OUT || + state->dst->ops == state->current_instruction_table.J_IDLE || + state->dst->ops == state->current_instruction_table.JAL || + state->dst->ops == state->current_instruction_table.JAL_OUT || + state->dst->ops == state->current_instruction_table.JAL_IDLE || + state->dst->ops == state->current_instruction_table.BEQ || + state->dst->ops == state->current_instruction_table.BEQ_OUT || + state->dst->ops == state->current_instruction_table.BEQ_IDLE || + state->dst->ops == state->current_instruction_table.BNE || + state->dst->ops == state->current_instruction_table.BNE_OUT || + state->dst->ops == state->current_instruction_table.BNE_IDLE || + state->dst->ops == state->current_instruction_table.BLEZ || + state->dst->ops == state->current_instruction_table.BLEZ_OUT || + state->dst->ops == state->current_instruction_table.BLEZ_IDLE || + state->dst->ops == state->current_instruction_table.BGTZ || + state->dst->ops == state->current_instruction_table.BGTZ_OUT || + state->dst->ops == state->current_instruction_table.BGTZ_IDLE || + state->dst->ops == state->current_instruction_table.BEQL || + state->dst->ops == state->current_instruction_table.BEQL_OUT || + state->dst->ops == state->current_instruction_table.BEQL_IDLE || + state->dst->ops == state->current_instruction_table.BNEL || + state->dst->ops == state->current_instruction_table.BNEL_OUT || + state->dst->ops == state->current_instruction_table.BNEL_IDLE || + state->dst->ops == state->current_instruction_table.BLEZL || + state->dst->ops == state->current_instruction_table.BLEZL_OUT || + state->dst->ops == state->current_instruction_table.BLEZL_IDLE || + state->dst->ops == state->current_instruction_table.BGTZL || + state->dst->ops == state->current_instruction_table.BGTZL_OUT || + state->dst->ops == state->current_instruction_table.BGTZL_IDLE || + state->dst->ops == state->current_instruction_table.JR || + state->dst->ops == state->current_instruction_table.JALR || + state->dst->ops == state->current_instruction_table.BLTZ || + state->dst->ops == state->current_instruction_table.BLTZ_OUT || + state->dst->ops == state->current_instruction_table.BLTZ_IDLE || + state->dst->ops == state->current_instruction_table.BGEZ || + state->dst->ops == state->current_instruction_table.BGEZ_OUT || + state->dst->ops == state->current_instruction_table.BGEZ_IDLE || + state->dst->ops == state->current_instruction_table.BLTZL || + state->dst->ops == state->current_instruction_table.BLTZL_OUT || + state->dst->ops == state->current_instruction_table.BLTZL_IDLE || + state->dst->ops == state->current_instruction_table.BGEZL || + state->dst->ops == state->current_instruction_table.BGEZL_OUT || + state->dst->ops == state->current_instruction_table.BGEZL_IDLE || + state->dst->ops == state->current_instruction_table.BLTZAL || + state->dst->ops == state->current_instruction_table.BLTZAL_OUT || + state->dst->ops == state->current_instruction_table.BLTZAL_IDLE || + state->dst->ops == state->current_instruction_table.BGEZAL || + state->dst->ops == state->current_instruction_table.BGEZAL_OUT || + state->dst->ops == state->current_instruction_table.BGEZAL_IDLE || + state->dst->ops == state->current_instruction_table.BLTZALL || + state->dst->ops == state->current_instruction_table.BLTZALL_OUT || + state->dst->ops == state->current_instruction_table.BLTZALL_IDLE || + state->dst->ops == state->current_instruction_table.BGEZALL || + state->dst->ops == state->current_instruction_table.BGEZALL_OUT || + state->dst->ops == state->current_instruction_table.BGEZALL_IDLE || + state->dst->ops == state->current_instruction_table.BC1F || + state->dst->ops == state->current_instruction_table.BC1F_OUT || + state->dst->ops == state->current_instruction_table.BC1F_IDLE || + state->dst->ops == state->current_instruction_table.BC1T || + state->dst->ops == state->current_instruction_table.BC1T_OUT || + state->dst->ops == state->current_instruction_table.BC1T_IDLE || + state->dst->ops == state->current_instruction_table.BC1FL || + state->dst->ops == state->current_instruction_table.BC1FL_OUT || + state->dst->ops == state->current_instruction_table.BC1FL_IDLE || + state->dst->ops == state->current_instruction_table.BC1TL || + state->dst->ops == state->current_instruction_table.BC1TL_OUT || + state->dst->ops == state->current_instruction_table.BC1TL_IDLE); +} + +/********************************************************************** + ************ recompile only one opcode (use for delay slot) ********** + **********************************************************************/ +void recompile_opcode(usf_state_t * state) +{ + state->SRC++; + state->src = *state->SRC; + state->dst++; + state->dst->addr = (state->dst-1)->addr + 4; + state->dst->reg_cache_infos.need_map = 0; + if(!is_jump(state)) + { + state->recomp_func = NULL; + recomp_ops[((state->src >> 26) & 0x3F)](state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + } + else + { + RNOP(state); + if (state->r4300emu == CORE_DYNAREC) state->recomp_func(state); + } + state->delay_slot_compiled = 2; +} + +/********************************************************************** + ************** allocate memory with executable bit set *************** + **********************************************************************/ +static void *malloc_exec(usf_state_t * state, size_t size) +{ +#if defined(WIN32) + return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +#elif defined(__GNUC__) + + #ifndef MAP_ANONYMOUS + #ifdef MAP_ANON + #define MAP_ANONYMOUS MAP_ANON + #endif + #endif + + void *block = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (block == MAP_FAILED) + { DebugMessage(state, M64MSG_ERROR, "Memory error: couldn't allocate %zi byte block of aligned RWX memory.", size); return NULL; } + + return block; +#else + return malloc(size); +#endif +} + +/********************************************************************** + ************* reallocate memory with executable bit set ************** + **********************************************************************/ +void *realloc_exec(usf_state_t * state, void *ptr, size_t oldsize, size_t newsize) +{ + void* block = malloc_exec(state, newsize); + if (block != NULL) + { + size_t copysize; + if (oldsize < newsize) + copysize = oldsize; + else + copysize = newsize; + memcpy(block, ptr, copysize); + } + free_exec(ptr, oldsize); + return block; +} + +/********************************************************************** + **************** frees memory with executable bit set **************** + **********************************************************************/ +static void free_exec(void *ptr, size_t length) +{ +#if defined(WIN32) + VirtualFree(ptr, 0, MEM_RELEASE); +#elif defined(__GNUC__) + munmap(ptr, length); +#else + free(ptr); +#endif +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/recomp.h b/Frameworks/lazyusf/lazyusf/r4300/recomp.h new file mode 100644 index 000000000..1bd9b1689 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/recomp.h @@ -0,0 +1,114 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - recomp.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_RECOMP_H +#define M64P_R4300_RECOMP_H + +#include + +#include "osal/preproc.h" + +#ifndef PRECOMP_STRUCTS +#define PRECOMP_STRUCTS + +#if defined(__x86_64__) +#include "x86_64/assemble_struct.h" +#else +#include "x86/assemble_struct.h" +#endif + +typedef struct _precomp_instr +{ + void (osal_fastcall *ops)(usf_state_t * state); + union + { + struct + { + long long int *rs; + long long int *rt; + short immediate; + } i; + struct + { + unsigned int inst_index; + } j; + struct + { + long long int *rs; + long long int *rt; + long long int *rd; + unsigned char sa; + unsigned char nrd; + } r; + struct + { + unsigned char base; + unsigned char ft; + short offset; + } lf; + struct + { + unsigned char ft; + unsigned char fs; + unsigned char fd; + } cf; + } f; + unsigned int addr; /* word-aligned instruction address in r4300 address space */ + unsigned int local_addr; /* byte offset to start of corresponding x86_64 instructions, from start of code block */ + reg_cache_struct reg_cache_infos; +} precomp_instr; + +typedef struct _precomp_block +{ + precomp_instr *block; + unsigned int start; + unsigned int end; + unsigned char *code; + unsigned int code_length; + unsigned int max_code_length; + void *jumps_table; + int jumps_number; + void *riprel_table; + int riprel_number; + //unsigned char md5[16]; + unsigned int adler32; +} precomp_block; +#endif + +void recompile_block(usf_state_t *, int *source, precomp_block *block, unsigned int func); +void init_block(usf_state_t *, precomp_block *block); +void free_block(usf_state_t *, precomp_block *block); +void recompile_opcode(usf_state_t *); +void dyna_jump(usf_state_t *); +void dyna_start(usf_state_t *, void *code); +void dyna_stop(usf_state_t *); +void *realloc_exec(usf_state_t *, void *ptr, size_t oldsize, size_t newsize); + +#if defined(__x86_64__) + #include "x86_64/assemble.h" + #include "x86_64/regcache.h" +#else + #include "x86/assemble.h" + #include "x86/regcache.h" +#endif + +#endif /* M64P_R4300_RECOMP_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/recomph.h b/Frameworks/lazyusf/lazyusf/r4300/recomph.h new file mode 100644 index 000000000..899d05137 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/recomph.h @@ -0,0 +1,294 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - recomph.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_RECOMPH_H +#define M64P_R4300_RECOMPH_H + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "recomp.h" + +void passe2(usf_state_t *, precomp_instr *dest, int start, int end, precomp_block* block); +void init_assembler(usf_state_t *, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number); +void free_assembler(usf_state_t *, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number); + +#if defined(__x86_64__) +void gencallinterp(usf_state_t *, unsigned long long addr, int jump); +#else +void gencallinterp(usf_state_t *, unsigned long addr, int jump); +#endif + +void genupdate_system(usf_state_t *, int type); +void genbnel(usf_state_t *); +void genblezl(usf_state_t *); +void genlw(usf_state_t *); +void genlbu(usf_state_t *); +void genlhu(usf_state_t *); +void gensb(usf_state_t *); +void gensh(usf_state_t *); +void gensw(usf_state_t *); +void gencache(usf_state_t *); +void genlwc1(usf_state_t *); +void genld(usf_state_t *); +void gensd(usf_state_t *); +void genbeq(usf_state_t *); +void genbne(usf_state_t *); +void genblez(usf_state_t *); +void genaddi(usf_state_t *); +void genaddiu(usf_state_t *); +void genslti(usf_state_t *); +void gensltiu(usf_state_t *); +void genandi(usf_state_t *); +void genori(usf_state_t *); +void genxori(usf_state_t *); +void genlui(usf_state_t *); +void genbeql(usf_state_t *); +void genmul_s(usf_state_t *); +void gendiv_s(usf_state_t *); +void gencvt_d_s(usf_state_t *); +void genadd_d(usf_state_t *); +void gentrunc_w_d(usf_state_t *); +void gencvt_s_w(usf_state_t *); +void genmfc1(usf_state_t *); +void gencfc1(usf_state_t *); +void genmtc1(usf_state_t *); +void genctc1(usf_state_t *); +void genj(usf_state_t *); +void genjal(usf_state_t *); +void genslt(usf_state_t *); +void gensltu(usf_state_t *); +void gendsll32(usf_state_t *); +void gendsra32(usf_state_t *); +void genbgez(usf_state_t *); +void genbgezl(usf_state_t *); +void genbgezal(usf_state_t *); +void gentlbwi(usf_state_t *); +void generet(usf_state_t *); +void genmfc0(usf_state_t *); +void genadd_s(usf_state_t *); +void genmult(usf_state_t *); +void genmultu(usf_state_t *); +void genmflo(usf_state_t *); +void genmtlo(usf_state_t *); +void gendiv(usf_state_t *); +void gendmultu(usf_state_t *); +void genddivu(usf_state_t *); +void genadd(usf_state_t *); +void genaddu(usf_state_t *); +void gensubu(usf_state_t *); +void genand(usf_state_t *); +void genor(usf_state_t *); +void genxor(usf_state_t *); +void genreserved(usf_state_t *); +void gennop(usf_state_t *); +void gensll(usf_state_t *); +void gensrl(usf_state_t *); +void gensra(usf_state_t *); +void gensllv(usf_state_t *); +void gensrlv(usf_state_t *); +void genjr(usf_state_t *); +void genni(usf_state_t *); +void genmfhi(usf_state_t *); +void genmthi(usf_state_t *); +void genmtc0(usf_state_t *); +void genbltz(usf_state_t *); +void genlwl(usf_state_t *); +void genswl(usf_state_t *); +void gentlbp(usf_state_t *); +void gentlbr(usf_state_t *); +void genswr(usf_state_t *); +void genlwr(usf_state_t *); +void gensrav(usf_state_t *); +void genbgtz(usf_state_t *); +void genlb(usf_state_t *); +void genswc1(usf_state_t *); +void genldc1(usf_state_t *); +void gencvt_d_w(usf_state_t *); +void genmul_d(usf_state_t *); +void gensub_d(usf_state_t *); +void gendiv_d(usf_state_t *); +void gencvt_s_d(usf_state_t *); +void genmov_s(usf_state_t *); +void genc_le_s(usf_state_t *); +void genbc1t(usf_state_t *); +void gentrunc_w_s(usf_state_t *); +void genbc1tl(usf_state_t *); +void genc_lt_s(usf_state_t *); +void genbc1fl(usf_state_t *); +void genneg_s(usf_state_t *); +void genc_le_d(usf_state_t *); +void genbgezal_idle(usf_state_t *); +void genj_idle(usf_state_t *); +void genbeq_idle(usf_state_t *); +void genlh(usf_state_t *); +void genmov_d(usf_state_t *); +void genc_lt_d(usf_state_t *); +void genbc1f(usf_state_t *); +void gennor(usf_state_t *); +void genneg_d(usf_state_t *); +void gensub(usf_state_t *); +void genblez_idle(usf_state_t *); +void gendivu(usf_state_t *); +void gencvt_w_s(usf_state_t *); +void genbltzl(usf_state_t *); +void gensdc1(usf_state_t *); +void genc_eq_s(usf_state_t *); +void genjalr(usf_state_t *); +void gensub_s(usf_state_t *); +void gensqrt_s(usf_state_t *); +void genc_eq_d(usf_state_t *); +void gencvt_w_d(usf_state_t *); +void genfin_block(usf_state_t *); +void genddiv(usf_state_t *); +void gendaddiu(usf_state_t *); +void genbgtzl(usf_state_t *); +void gendsrav(usf_state_t *); +void gendsllv(usf_state_t *); +void gencvt_s_l(usf_state_t *); +void gendmtc1(usf_state_t *); +void gendsrlv(usf_state_t *); +void gendsra(usf_state_t *); +void gendmult(usf_state_t *); +void gendsll(usf_state_t *); +void genabs_s(usf_state_t *); +void gensc(usf_state_t *); +void gennotcompiled(usf_state_t *); +void genjal_idle(usf_state_t *); +void genjal_out(usf_state_t *); +void genbeq_out(usf_state_t *); +void gensyscall(usf_state_t *); +void gensync(usf_state_t *); +void gendadd(usf_state_t *); +void gendaddu(usf_state_t *); +void gendsub(usf_state_t *); +void gendsubu(usf_state_t *); +void genteq(usf_state_t *); +void gendsrl(usf_state_t *); +void gendsrl32(usf_state_t *); +void genbltz_idle(usf_state_t *); +void genbltz_out(usf_state_t *); +void genbgez_idle(usf_state_t *); +void genbgez_out(usf_state_t *); +void genbltzl_idle(usf_state_t *); +void genbltzl_out(usf_state_t *); +void genbgezl_idle(usf_state_t *); +void genbgezl_out(usf_state_t *); +void genbltzal_idle(usf_state_t *); +void genbltzal_out(usf_state_t *); +void genbltzal(usf_state_t *); +void genbgezal_out(usf_state_t *); +void genbltzall_idle(usf_state_t *); +void genbltzall_out(usf_state_t *); +void genbltzall(usf_state_t *); +void genbgezall_idle(usf_state_t *); +void genbgezall_out(usf_state_t *); +void genbgezall(usf_state_t *); +void gentlbwr(usf_state_t *); +void genbc1f_idle(usf_state_t *); +void genbc1f_out(usf_state_t *); +void genbc1t_idle(usf_state_t *); +void genbc1t_out(usf_state_t *); +void genbc1fl_idle(usf_state_t *); +void genbc1fl_out(usf_state_t *); +void genbc1tl_idle(usf_state_t *); +void genbc1tl_out(usf_state_t *); +void genround_l_s(usf_state_t *); +void gentrunc_l_s(usf_state_t *); +void genceil_l_s(usf_state_t *); +void genfloor_l_s(usf_state_t *); +void genround_w_s(usf_state_t *); +void genceil_w_s(usf_state_t *); +void genfloor_w_s(usf_state_t *); +void gencvt_l_s(usf_state_t *); +void genc_f_s(usf_state_t *); +void genc_un_s(usf_state_t *); +void genc_ueq_s(usf_state_t *); +void genc_olt_s(usf_state_t *); +void genc_ult_s(usf_state_t *); +void genc_ole_s(usf_state_t *); +void genc_ule_s(usf_state_t *); +void genc_sf_s(usf_state_t *); +void genc_ngle_s(usf_state_t *); +void genc_seq_s(usf_state_t *); +void genc_ngl_s(usf_state_t *); +void genc_nge_s(usf_state_t *); +void genc_ngt_s(usf_state_t *); +void gensqrt_d(usf_state_t *); +void genabs_d(usf_state_t *); +void genround_l_d(usf_state_t *); +void gentrunc_l_d(usf_state_t *); +void genceil_l_d(usf_state_t *); +void genfloor_l_d(usf_state_t *); +void genround_w_d(usf_state_t *); +void genceil_w_d(usf_state_t *); +void genfloor_w_d(usf_state_t *); +void gencvt_l_d(usf_state_t *); +void genc_f_d(usf_state_t *); +void genc_un_d(usf_state_t *); +void genc_ueq_d(usf_state_t *); +void genc_olt_d(usf_state_t *); +void genc_ult_d(usf_state_t *); +void genc_ole_d(usf_state_t *); +void genc_ule_d(usf_state_t *); +void genc_sf_d(usf_state_t *); +void genc_ngle_d(usf_state_t *); +void genc_seq_d(usf_state_t *); +void genc_ngl_d(usf_state_t *); +void genc_nge_d(usf_state_t *); +void genc_ngt_d(usf_state_t *); +void gencvt_d_l(usf_state_t *); +void gendmfc1(usf_state_t *); +void genj_out(usf_state_t *); +void genbne_idle(usf_state_t *); +void genbne_out(usf_state_t *); +void genblez_out(usf_state_t *); +void genbgtz_idle(usf_state_t *); +void genbgtz_out(usf_state_t *); +void genbeql_idle(usf_state_t *); +void genbeql_out(usf_state_t *); +void genbnel_idle(usf_state_t *); +void genbnel_out(usf_state_t *); +void genblezl_idle(usf_state_t *); +void genblezl_out(usf_state_t *); +void genbgtzl_idle(usf_state_t *); +void genbgtzl_out(usf_state_t *); +void gendaddi(usf_state_t *); +void genldl(usf_state_t *); +void genldr(usf_state_t *); +void genlwu(usf_state_t *); +void gensdl(usf_state_t *); +void gensdr(usf_state_t *); +void genlink_subblock(usf_state_t *); +void gendelayslot(usf_state_t *); +void gencheck_interupt_reg(usf_state_t *); +void gentest(usf_state_t *); +void gentest_out(usf_state_t *); +void gentest_idle(usf_state_t *); +void gentestl(usf_state_t *); +void gentestl_out(usf_state_t *); +void gencheck_cop1_unusable(usf_state_t *); +void genll(usf_state_t *); +void genbreak(usf_state_t *); + +#endif /* M64P_R4300_RECOMPH_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/reset.c b/Frameworks/lazyusf/lazyusf/r4300/reset.c new file mode 100644 index 000000000..ed9585dec --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/reset.c @@ -0,0 +1,55 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - reset.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2011 CasualJames * + * Copyright (C) 2008-2009 Richard Goedeken * + * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 * + * Hard reset based on code by hacktarux. * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "r4300/reset.h" +#include "r4300/r4300.h" +#include "r4300/interupt.h" +#include "memory/memory.h" +#include "r4300/cached_interp.h" + +void reset_hard(usf_state_t * state) +{ + init_memory(state, 0x800000); + r4300_reset_hard(state); + r4300_reset_soft(state); + state->last_addr = 0xa4000040; + state->next_interupt = 624999; + init_interupt(state); + if(state->r4300emu != CORE_PURE_INTERPRETER) + { + free_blocks(state); + init_blocks(state); + } + generic_jump_to(state, state->last_addr); +} + +void reset_soft(usf_state_t * state) +{ + add_interupt_event(state, HW2_INT, 0); /* Hardware 2 Interrupt immediately */ + add_interupt_event(state, NMI_INT, 50000000); /* Non maskable Interrupt after 1/2 second */ +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/reset.h b/Frameworks/lazyusf/lazyusf/r4300/reset.h new file mode 100644 index 000000000..284125474 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/reset.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - reset.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2011 CasualJames * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_RESET_H +#define M64P_R4300_RESET_H + +/* For hard reset, set reset_hard_job and next interrupt will cause hard reset. + * For soft reset, call reset_soft() at any time. */ +void reset_hard(usf_state_t *); +void reset_soft(usf_state_t *); + +#endif /* M64P_R4300_RESET_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/tlb.c b/Frameworks/lazyusf/lazyusf/r4300/tlb.c new file mode 100644 index 000000000..ce43b1a83 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/tlb.c @@ -0,0 +1,109 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - tlb.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "tlb.h" +#include "exception.h" + +#include "main/rom.h" + +void tlb_unmap(usf_state_t * state, tlb *entry) +{ + unsigned int i; + + if (entry->v_even) + { + for (i=entry->start_even; iend_even; i += 0x1000) + state->tlb_LUT_r[i>>12] = 0; + if (entry->d_even) + for (i=entry->start_even; iend_even; i += 0x1000) + state->tlb_LUT_w[i>>12] = 0; + } + + if (entry->v_odd) + { + for (i=entry->start_odd; iend_odd; i += 0x1000) + state->tlb_LUT_r[i>>12] = 0; + if (entry->d_odd) + for (i=entry->start_odd; iend_odd; i += 0x1000) + state->tlb_LUT_w[i>>12] = 0; + } +} + +void tlb_map(usf_state_t * state, tlb *entry) +{ + unsigned int i; + + if (entry->v_even) + { + if (entry->start_even < entry->end_even && + !(entry->start_even >= 0x80000000 && entry->end_even < 0xC0000000) && + entry->phys_even < 0x20000000) + { + for (i=entry->start_even;iend_even;i+=0x1000) + state->tlb_LUT_r[i>>12] = 0x80000000 | (entry->phys_even + (i - entry->start_even) + 0xFFF); + if (entry->d_even) + for (i=entry->start_even;iend_even;i+=0x1000) + state->tlb_LUT_w[i>>12] = 0x80000000 | (entry->phys_even + (i - entry->start_even) + 0xFFF); + } + } + + if (entry->v_odd) + { + if (entry->start_odd < entry->end_odd && + !(entry->start_odd >= 0x80000000 && entry->end_odd < 0xC0000000) && + entry->phys_odd < 0x20000000) + { + for (i=entry->start_odd;iend_odd;i+=0x1000) + state->tlb_LUT_r[i>>12] = 0x80000000 | (entry->phys_odd + (i - entry->start_odd) + 0xFFF); + if (entry->d_odd) + for (i=entry->start_odd;iend_odd;i+=0x1000) + state->tlb_LUT_w[i>>12] = 0x80000000 | (entry->phys_odd + (i - entry->start_odd) + 0xFFF); + } + } +} + +unsigned int virtual_to_physical_address(usf_state_t * state, unsigned int addresse, int w) +{ + if (w == 1) + { + if (state->tlb_LUT_w[addresse>>12]) + return (state->tlb_LUT_w[addresse>>12]&0xFFFFF000)|(addresse&0xFFF); + } + else + { + if (state->tlb_LUT_r[addresse>>12]) + return (state->tlb_LUT_r[addresse>>12]&0xFFFFF000)|(addresse&0xFFF); + } + //printf("tlb exception !!! @ %x, %x, add:%x\n", addresse, w, PC->addr); + //getchar(); +#ifdef DEBUG_INFO + fprintf(state->debug_log, "TLB exception @ %x, %x, add:%x\n", addresse, w, state->PC->addr); + fflush(state->debug_log); +#endif + TLB_refill_exception(state,addresse,w); + //return 0x80000000; + //return 0x00000000; + return state->PC->addr; +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/tlb.h b/Frameworks/lazyusf/lazyusf/r4300/tlb.h new file mode 100644 index 000000000..49aa1d5b6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/tlb.h @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - tlb.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_TLB_H +#define M64P_R4300_TLB_H + +#include "usf/usf.h" + +#ifndef TLB_STRUCTS +#define TLB_STRUCTS +typedef struct _tlb +{ + short mask; + int vpn2; + char g; + unsigned char asid; + int pfn_even; + char c_even; + char d_even; + char v_even; + int pfn_odd; + char c_odd; + char d_odd; + char v_odd; + char r; + //int check_parity_mask; + + unsigned int start_even; + unsigned int end_even; + unsigned int phys_even; + unsigned int start_odd; + unsigned int end_odd; + unsigned int phys_odd; +} tlb; +#endif + +void tlb_unmap(usf_state_t *, tlb *entry); +void tlb_map(usf_state_t *, tlb *entry); +unsigned int virtual_to_physical_address(usf_state_t *, unsigned int addresse, int w); + +#endif /* M64P_R4300_TLB_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.c b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.c new file mode 100644 index 000000000..da403f76a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.c @@ -0,0 +1,132 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "osal/preproc.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" + +void init_assembler(usf_state_t * state, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number) +{ + if (block_jumps_table) + { + state->jumps_table = (jump_table *) block_jumps_table; + state->jumps_number = block_jumps_number; + state->max_jumps_number = state->jumps_number; + } + else + { + state->jumps_table = (jump_table *) malloc(1000*sizeof(jump_table)); + state->jumps_number = 0; + state->max_jumps_number = 1000; + } +} + +void free_assembler(usf_state_t * state, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number) +{ + *block_jumps_table = state->jumps_table; + *block_jumps_number = state->jumps_number; + *block_riprel_table = NULL; /* RIP-relative addressing is only for x86-64 */ + *block_riprel_number = 0; +} + +void add_jump(usf_state_t * state, unsigned int pc_addr, unsigned int mi_addr) +{ + if (state->jumps_number == state->max_jumps_number) + { + state->max_jumps_number += 1000; + state->jumps_table = (jump_table *) realloc(state->jumps_table, state->max_jumps_number*sizeof(jump_table)); + } + state->jumps_table[state->jumps_number].pc_addr = pc_addr; + state->jumps_table[state->jumps_number].mi_addr = mi_addr; + state->jumps_number++; +} + +void passe2(usf_state_t * state, precomp_instr *dest, int start, int end, precomp_block *block) +{ + unsigned int real_code_length, addr_dest; + int i; + build_wrappers(state, dest, start, end, block); + real_code_length = state->code_length; + + for (i=0; i < state->jumps_number; i++) + { + state->code_length = state->jumps_table[i].pc_addr; + if (dest[(state->jumps_table[i].mi_addr - dest[0].addr)/4].reg_cache_infos.need_map) + { + addr_dest = (unsigned int)dest[(state->jumps_table[i].mi_addr - dest[0].addr)/4].reg_cache_infos.jump_wrapper; + put32(state, addr_dest-((unsigned int)block->code+state->code_length)-4); + } + else + { + addr_dest = dest[(state->jumps_table[i].mi_addr - dest[0].addr)/4].local_addr; + put32(state, addr_dest-state->code_length-4); + } + } + state->code_length = real_code_length; +} + +void jump_start_rel8(usf_state_t * state) +{ + state->g_jump_start8 = state->code_length; +} + +void jump_start_rel32(usf_state_t * state) +{ + state->g_jump_start32 = state->code_length; +} + +void jump_end_rel8(usf_state_t * state) +{ + unsigned int jump_end = state->code_length; + int jump_vec = jump_end - state->g_jump_start8; + + if (jump_vec > 127 || jump_vec < -128) + { + DebugMessage(state, M64MSG_ERROR, "8-bit relative jump too long! From %x to %x", state->g_jump_start8, jump_end); + OSAL_BREAKPOINT_INTERRUPT; + } + + state->code_length = state->g_jump_start8 - 1; + put8(state, jump_vec); + state->code_length = jump_end; +} + +void jump_end_rel32(usf_state_t * state) +{ + unsigned int jump_end = state->code_length; + int jump_vec = jump_end - state->g_jump_start32; + + state->code_length = state->g_jump_start32 - 4; + put32(state, jump_vec); + state->code_length = jump_end; +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.h b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.h new file mode 100644 index 000000000..35fd16234 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble.h @@ -0,0 +1,851 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_ASSEMBLE_H +#define M64P_R4300_ASSEMBLE_H + +#include "r4300/recomph.h" +#include "api/callbacks.h" +#include "osal/preproc.h" + +#include + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 1 +#define DX 2 +#define BX 3 +#define SP 4 +#define BP 5 +#define SI 6 +#define DI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 +#define AH 4 +#define CH 5 +#define DH 6 +#define BH 7 + +void jump_start_rel8(usf_state_t *); +void jump_end_rel8(usf_state_t *); +void jump_start_rel32(usf_state_t *); +void jump_end_rel32(usf_state_t *); +void add_jump(usf_state_t *, unsigned int pc_addr, unsigned int mi_addr); + +static osal_inline void put8(usf_state_t * state, unsigned char octet) +{ + (*state->inst_pointer)[state->code_length] = octet; + state->code_length++; + if (state->code_length == state->max_code_length) + { + *state->inst_pointer = (unsigned char *) realloc_exec(state, *state->inst_pointer, state->max_code_length, state->max_code_length+8192); + state->max_code_length += 8192; + } +} + +static osal_inline void put32(usf_state_t * state, unsigned int dword) +{ + if ((state->code_length+4) >= state->max_code_length) + { + *state->inst_pointer = (unsigned char *) realloc_exec(state, *state->inst_pointer, state->max_code_length, state->max_code_length+8192); + state->max_code_length += 8192; + } + *((unsigned int *)(&(*state->inst_pointer)[state->code_length])) = dword; + state->code_length+=4; +} + +static osal_inline void push_reg32(usf_state_t * state, int reg32) +{ + put8(state, 0x50 + reg32); +} + +static osal_inline void pop_reg32(usf_state_t * state, int reg32) +{ + put8(state, 0x58 + reg32); +} + +static osal_inline void mov_eax_memoffs32(usf_state_t * state, unsigned int *memoffs32) +{ + put8(state, 0xA1); + put32(state, (unsigned int)(memoffs32)); +} + +static osal_inline void mov_memoffs32_eax(usf_state_t * state, unsigned int *memoffs32) +{ + put8(state, 0xA3); + put32(state, (unsigned int)(memoffs32)); +} + +static osal_inline void mov_m8_reg8(usf_state_t * state, unsigned char *m8, int reg8) +{ + put8(state, 0x88); + put8(state, (reg8 << 3) | 5); + put32(state, (unsigned int)(m8)); +} + +static osal_inline void mov_reg16_m16(usf_state_t * state, int reg16, unsigned short *m16) +{ + put8(state, 0x66); + put8(state, 0x8B); + put8(state, (reg16 << 3) | 5); + put32(state, (unsigned int)(m16)); +} + +static osal_inline void mov_m16_reg16(usf_state_t * state, unsigned short *m16, int reg16) +{ + put8(state, 0x66); + put8(state, 0x89); + put8(state, (reg16 << 3) | 5); + put32(state, (unsigned int)(m16)); +} + +static osal_inline void cmp_reg32_m32(usf_state_t * state, int reg32, unsigned int *m32) +{ + put8(state, 0x3B); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void cmp_reg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x39); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static osal_inline void cmp_reg32_imm8(usf_state_t * state, int reg32, unsigned char imm8) +{ + put8(state, 0x83); + put8(state, 0xF8 + reg32); + put8(state, imm8); +} + +static osal_inline void cmp_preg32pimm32_imm8(usf_state_t * state, int reg32, unsigned int imm32, unsigned char imm8) +{ + put8(state, 0x80); + put8(state, 0xB8 + reg32); + put32(state, imm32); + put8(state, imm8); +} + +static osal_inline void cmp_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xF8 + reg32); + put32(state, imm32); +} + +static osal_inline void test_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0xF7); + put8(state, 0xC0 + reg32); + put32(state, imm32); +} + +static osal_inline void test_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0xF7); + put8(state, 0x05); + put32(state, (unsigned int)m32); + put32(state, imm32); +} + +static osal_inline void add_m32_reg32(usf_state_t * state, unsigned int *m32, int reg32) +{ + put8(state, 0x01); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void sub_reg32_m32(usf_state_t * state, int reg32, unsigned int *m32) +{ + put8(state, 0x2B); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void sub_reg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x29); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static osal_inline void sbb_reg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x19); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static osal_inline void sub_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xE8 + reg32); + put32(state, imm32); +} + +static osal_inline void sub_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x2D); + put32(state, imm32); +} + +static osal_inline void jne_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x75); + put8(state, saut); +} + +static osal_inline void je_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x74); + put8(state, saut); +} + +static osal_inline void jb_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x72); + put8(state, saut); +} + +static osal_inline void jbe_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x76); + put8(state, saut); +} + +static osal_inline void ja_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x77); + put8(state, saut); +} + +static osal_inline void jae_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x73); + put8(state, saut); +} + +static osal_inline void jle_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7E); + put8(state, saut); +} + +static osal_inline void jge_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7D); + put8(state, saut); +} + +static osal_inline void jg_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7F); + put8(state, saut); +} + +static osal_inline void jl_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7C); + put8(state, saut); +} + +static osal_inline void jp_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7A); + put8(state, saut); +} + +static osal_inline void je_near_rj(usf_state_t * state, unsigned int saut) +{ + put8(state, 0x0F); + put8(state, 0x84); + put32(state, saut); +} + +static osal_inline void mov_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0xB8+reg32); + put32(state, imm32); +} + +static osal_inline void jmp_imm_short(usf_state_t * state, char saut) +{ + put8(state, 0xEB); + put8(state, saut); +} + +static osal_inline void or_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0x0D); + put32(state, (unsigned int)(m32)); + put32(state, imm32); +} + +static osal_inline void or_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x09); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void and_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x21); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void and_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0x25); + put32(state, (unsigned int)(m32)); + put32(state, imm32); +} + +static osal_inline void xor_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x31); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void sub_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0x2D); + put32(state, (unsigned int)(m32)); + put32(state, imm32); +} + +static osal_inline void add_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0x83); + put8(state, 0xC0+reg32); + put8(state, imm8); +} + +static osal_inline void add_reg32_imm32(usf_state_t * state, unsigned int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xC0+reg32); + put32(state, imm32); +} + +static osal_inline void inc_m32(usf_state_t * state, unsigned int *m32) +{ + put8(state, 0xFF); + put8(state, 0x05); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void cmp_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0x3D); + put32(state, (unsigned int)(m32)); + put32(state, imm32); +} + +static osal_inline void cmp_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x3D); + put32(state, imm32); +} + +static osal_inline void mov_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + put8(state, 0xC7); + put8(state, 0x05); + put32(state, (unsigned int)(m32)); + put32(state, imm32); +} + +static osal_inline void jmp(usf_state_t * state, unsigned int mi_addr) +{ + put8(state, 0xE9); + put32(state, 0); + add_jump(state, state->code_length-4, mi_addr); +} + +static osal_inline void cdq(usf_state_t * state) +{ + put8(state, 0x99); +} + +static osal_inline void mov_m32_reg32(usf_state_t * state, unsigned int *m32, unsigned int reg32) +{ + put8(state, 0x89); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void call_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xFF); + put8(state, 0xD0+reg32); +} + +static osal_inline void shr_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xE8+reg32); + put8(state, imm8); +} + +static osal_inline void shr_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xE8+reg32); +} + +static osal_inline void sar_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xF8+reg32); +} + +static osal_inline void shl_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xE0+reg32); +} + +static osal_inline void shld_reg32_reg32_cl(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x0F); + put8(state, 0xA5); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void shld_reg32_reg32_imm8(usf_state_t * state, unsigned int reg1, unsigned int reg2, unsigned char imm8) +{ + put8(state, 0x0F); + put8(state, 0xA4); + put8(state, 0xC0 | (reg2 << 3) | reg1); + put8(state, imm8); +} + +static osal_inline void shrd_reg32_reg32_cl(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x0F); + put8(state, 0xAD); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void sar_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xF8+reg32); + put8(state, imm8); +} + +static osal_inline void shrd_reg32_reg32_imm8(usf_state_t * state, unsigned int reg1, unsigned int reg2, unsigned char imm8) +{ + put8(state, 0x0F); + put8(state, 0xAC); + put8(state, 0xC0 | (reg2 << 3) | reg1); + put8(state, imm8); +} + +static osal_inline void mul_m32(usf_state_t * state, unsigned int *m32) +{ + put8(state, 0xF7); + put8(state, 0x25); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void imul_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xE8+reg32); +} + +static osal_inline void mul_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xE0+reg32); +} + +static osal_inline void idiv_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xF8+reg32); +} + +static osal_inline void div_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xF0+reg32); +} + +static osal_inline void add_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x01); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void adc_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x11); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void add_reg32_m32(usf_state_t * state, unsigned int reg32, unsigned int *m32) +{ + put8(state, 0x03); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void adc_reg32_imm32(usf_state_t * state, unsigned int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xD0 + reg32); + put32(state, imm32); +} + +static osal_inline void jmp_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xFF); + put8(state, 0xE0 + reg32); +} + +static osal_inline void mov_reg32_preg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | reg2); +} + +static osal_inline void mov_preg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x89); + put8(state, (reg2 << 3) | reg1); +} + +static osal_inline void mov_reg32_preg32preg32pimm32(usf_state_t * state, int reg1, int reg2, int reg3, unsigned int imm32) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | 0x84); + put8(state, reg2 | (reg3 << 3)); + put32(state, imm32); +} + +static osal_inline void mov_reg32_preg32pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x8B); + put8(state, 0x80 | (reg1 << 3) | reg2); + put32(state, imm32); +} + +static osal_inline void mov_reg32_preg32x4pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | 4); + put8(state, 0x80 | (reg2 << 3) | 5); + put32(state, imm32); +} + +static osal_inline void mov_preg32pimm32_reg8(usf_state_t * state, int reg32, unsigned int imm32, int reg8) +{ + put8(state, 0x88); + put8(state, 0x80 | reg32 | (reg8 << 3)); + put32(state, imm32); +} + +static osal_inline void mov_preg32pimm32_imm8(usf_state_t * state, int reg32, unsigned int imm32, unsigned char imm8) +{ + put8(state, 0xC6); + put8(state, 0x80 + reg32); + put32(state, imm32); + put8(state, imm8); +} + +static osal_inline void mov_preg32pimm32_reg16(usf_state_t * state, int reg32, unsigned int imm32, int reg16) +{ + put8(state, 0x66); + put8(state, 0x89); + put8(state, 0x80 | reg32 | (reg16 << 3)); + put32(state, imm32); +} + +static osal_inline void mov_preg32pimm32_reg32(usf_state_t * state, int reg1, unsigned int imm32, int reg2) +{ + put8(state, 0x89); + put8(state, 0x80 | reg1 | (reg2 << 3)); + put32(state, imm32); +} + +static osal_inline void add_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x05); + put32(state, imm32); +} + +static osal_inline void shl_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xE0 + reg32); + put8(state, imm8); +} + +static osal_inline void mov_reg32_m32(usf_state_t * state, unsigned int reg32, unsigned int* m32) +{ + put8(state, 0x8B); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m32)); +} + +static osal_inline void mov_reg8_m8(usf_state_t * state, int reg8, unsigned char *m8) +{ + put8(state, 0x8A); + put8(state, (reg8 << 3) | 5); + put32(state, (unsigned int)(m8)); +} + +static osal_inline void and_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x25); + put32(state, imm32); +} + +static osal_inline void and_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xE0 + reg32); + put32(state, imm32); +} + +static osal_inline void or_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xC8 + reg32); + put32(state, imm32); +} + +static osal_inline void xor_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xF0 + reg32); + put32(state, imm32); +} + +static osal_inline void xor_reg8_imm8(usf_state_t * state, int reg8, unsigned char imm8) +{ + put8(state, 0x80); + put8(state, 0xF0 + reg8); + put8(state, imm8); +} + +static osal_inline void mov_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + if (reg1 == reg2) return; + put8(state, 0x89); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static osal_inline void not_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xD0 + reg32); +} + +static osal_inline void movsx_reg32_m8(usf_state_t * state, int reg32, unsigned char *m8) +{ + put8(state, 0x0F); + put8(state, 0xBE); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m8)); +} + +static osal_inline void movsx_reg32_8preg32pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x0F); + put8(state, 0xBE); + put8(state, (reg1 << 3) | reg2 | 0x80); + put32(state, imm32); +} + +static osal_inline void movsx_reg32_16preg32pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x0F); + put8(state, 0xBF); + put8(state, (reg1 << 3) | reg2 | 0x80); + put32(state, imm32); +} + +static osal_inline void movsx_reg32_m16(usf_state_t * state, int reg32, unsigned short *m16) +{ + put8(state, 0x0F); + put8(state, 0xBF); + put8(state, (reg32 << 3) | 5); + put32(state, (unsigned int)(m16)); +} + +static osal_inline void fldcw_m16(usf_state_t * state, unsigned short *m16) +{ + put8(state, 0xD9); + put8(state, 0x2D); + put32(state, (unsigned int)(m16)); +} + +static osal_inline void fld_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD9); + put8(state, reg32); +} + +static osal_inline void fdiv_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD8); + put8(state, 0x30 + reg32); +} + +static osal_inline void fstp_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD9); + put8(state, 0x18 + reg32); +} + +static osal_inline void fchs(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xE0); +} + +static osal_inline void fstp_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDD); + put8(state, 0x18 + reg32); +} + +static osal_inline void fadd_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD8); + put8(state, reg32); +} + +static osal_inline void fsub_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD8); + put8(state, 0x20 + reg32); +} + +static osal_inline void fmul_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xD8); + put8(state, 0x08 + reg32); +} + +static osal_inline void fistp_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xDB); + put8(state, 0x18 + reg32); +} + +static osal_inline void fistp_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDF); + put8(state, 0x38 + reg32); +} + +static osal_inline void fld_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDD); + put8(state, reg32); +} + +static osal_inline void fild_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDF); + put8(state, 0x28+reg32); +} + +static osal_inline void fild_preg32_dword(usf_state_t * state, int reg32) +{ + put8(state, 0xDB); + put8(state, reg32); +} + +static osal_inline void fadd_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDC); + put8(state, reg32); +} + +static osal_inline void fdiv_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDC); + put8(state, 0x30 + reg32); +} + +static osal_inline void fsub_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDC); + put8(state, 0x20 + reg32); +} + +static osal_inline void fmul_preg32_qword(usf_state_t * state, int reg32) +{ + put8(state, 0xDC); + put8(state, 0x08 + reg32); +} + +static osal_inline void fsqrt(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xFA); +} + +static osal_inline void fabs_(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xE1); +} + +static osal_inline void fcomip_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDF); + put8(state, 0xF0 + fpreg); +} + +static osal_inline void fucomip_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDF); + put8(state, 0xE8 + fpreg); +} + +static osal_inline void ffree_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDD); + put8(state, 0xC0 + fpreg); +} + +#endif /* M64P_R4300_ASSEMBLE_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/assemble_struct.h b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble_struct.h new file mode 100644 index 000000000..f936e3fd3 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/assemble_struct.h @@ -0,0 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble_struct.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_ASSEMBLE_STRUCT_H +#define M64P_R4300_ASSEMBLE_STRUCT_H + +typedef struct _reg_cache_struct +{ + int need_map; + void *needed_registers[8]; + unsigned char jump_wrapper[62]; + int need_cop1_check; +} reg_cache_struct; + +#endif /* M64P_R4300_ASSEMBLE_STRUCT_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gbc.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gbc.c new file mode 100644 index 000000000..c8d4dc210 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gbc.c @@ -0,0 +1,282 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gbc.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +static void genbc1f_test(usf_state_t * state) +{ + test_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); + jne_rj(state, 12); + mov_m32_imm32(state, (unsigned int*)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int*)(&state->branch_taken), 0); // 10 +} + +void genbc1f(usf_state_t * state) +{ +#ifdef INTERPRET_BC1F + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbc1f_out(usf_state_t * state) +{ +#ifdef INTERPRET_BC1F_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbc1f_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1F_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1F_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gentest_idle(state); + genbc1f(state); +#endif +} + +static void genbc1t_test(usf_state_t * state) +{ + test_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); + je_rj(state, 12); + mov_m32_imm32(state, (unsigned int*)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int*)(&state->branch_taken), 0); // 10 +} + +void genbc1t(usf_state_t * state) +{ +#ifdef INTERPRET_BC1T + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbc1t_out(usf_state_t * state) +{ +#ifdef INTERPRET_BC1T_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbc1t_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1T_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1T_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gentest_idle(state); + genbc1t(state); +#endif +} + +void genbc1fl(usf_state_t * state) +{ +#ifdef INTERPRET_BC1FL + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbc1fl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BC1FL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbc1fl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1FL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1FL_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gentest_idle(state); + genbc1fl(state); +#endif +} + +void genbc1tl(usf_state_t * state) +{ +#ifdef INTERPRET_BC1TL + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbc1tl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BC1TL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbc1tl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1TL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BC1TL_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gentest_idle(state); + genbc1tl(state); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop0.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop0.c new file mode 100644 index 000000000..ae0194964 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop0.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop0.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" + +//static unsigned int pMFC0 = (unsigned int)(MFC0); +void genmfc0(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.MFC0, 0); +} + +//static unsigned int pMTC0 = (unsigned int)(MTC0); +void genmtc0(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.MTC0, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1.c new file mode 100644 index 000000000..52f27928d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1.c @@ -0,0 +1,140 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/cp1.h" + +#include "memory/memory.h" + +void genmfc1(usf_state_t * state) +{ +#ifdef INTERPRET_MFC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.MFC1, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.r.nrd])); + mov_reg32_preg32(state, EBX, EAX); + mov_m32_reg32(state, (unsigned int*)state->dst->f.r.rt, EBX); + sar_reg32_imm8(state, EBX, 31); + mov_m32_reg32(state, ((unsigned int*)state->dst->f.r.rt)+1, EBX); +#endif +} + +void gendmfc1(usf_state_t * state) +{ +#ifdef INTERPRET_DMFC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.DMFC1, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.r.nrd])); + mov_reg32_preg32(state, EBX, EAX); + mov_reg32_preg32pimm32(state, ECX, EAX, 4); + mov_m32_reg32(state, (unsigned int*)state->dst->f.r.rt, EBX); + mov_m32_reg32(state, ((unsigned int*)state->dst->f.r.rt)+1, ECX); +#endif +} + +void gencfc1(usf_state_t * state) +{ +#ifdef INTERPRET_CFC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.CFC1, 0); +#else + gencheck_cop1_unusable(state); + if(state->dst->f.r.nrd == 31) mov_eax_memoffs32(state, (unsigned int*)&state->FCR31); + else mov_eax_memoffs32(state, (unsigned int*)&state->FCR0); + mov_memoffs32_eax(state, (unsigned int*)state->dst->f.r.rt); + sar_reg32_imm8(state, EAX, 31); + mov_memoffs32_eax(state, ((unsigned int*)state->dst->f.r.rt)+1); +#endif +} + +void genmtc1(usf_state_t * state) +{ +#ifdef INTERPRET_MTC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.MTC1, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_m32(state, EBX, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.r.nrd])); + mov_preg32_reg32(state, EBX, EAX); +#endif +} + +void gendmtc1(usf_state_t * state) +{ +#ifdef INTERPRET_DMTC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.DMTC1, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_m32(state, EBX, ((unsigned int*)state->dst->f.r.rt)+1); + mov_reg32_m32(state, EDX, (unsigned int*)(&state->reg_cop1_double[state->dst->f.r.nrd])); + mov_preg32_reg32(state, EDX, EAX); + mov_preg32pimm32_reg32(state, EDX, 4, EBX); +#endif +} + +void genctc1(usf_state_t * state) +{ +#ifdef INTERPRET_CTC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.CTC1, 0); +#else + gencheck_cop1_unusable(state); + + if (state->dst->f.r.nrd != 31) return; + mov_eax_memoffs32(state, (unsigned int*)state->dst->f.r.rt); + mov_memoffs32_eax(state, (unsigned int*)&state->FCR31); + and_eax_imm32(state, 3); + + cmp_eax_imm32(state, 0); + jne_rj(state, 12); + mov_m32_imm32(state, (unsigned int*)&state->rounding_mode, 0x33F); // 10 + jmp_imm_short(state, 48); // 2 + + cmp_eax_imm32(state, 1); // 5 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int*)&state->rounding_mode, 0xF3F); // 10 + jmp_imm_short(state, 29); // 2 + + cmp_eax_imm32(state, 2); // 5 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int*)&state->rounding_mode, 0xB3F); // 10 + jmp_imm_short(state, 10); // 2 + + mov_m32_imm32(state, (unsigned int*)&state->rounding_mode, 0x73F); // 10 + + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_d.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_d.c new file mode 100644 index 000000000..dee1296c7 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_d.c @@ -0,0 +1,609 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_d.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +void genadd_d(usf_state_t * state) +{ +#ifdef INTERPRET_ADD_D + gencallinterp(state, (unsigned int)state->current_instruction_table.ADD_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fadd_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void gensub_d(usf_state_t * state) +{ +#ifdef INTERPRET_SUB_D + gencallinterp(state, (unsigned int)state->current_instruction_table.SUB_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fsub_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void genmul_d(usf_state_t * state) +{ +#ifdef INTERPRET_MUL_D + gencallinterp(state, (unsigned int)state->current_instruction_table.MUL_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fmul_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void gendiv_d(usf_state_t * state) +{ +#ifdef INTERPRET_DIV_D + gencallinterp(state, (unsigned int)state->current_instruction_table.DIV_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fdiv_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void gensqrt_d(usf_state_t * state) +{ +#ifdef INTERPRET_SQRT_D + gencallinterp(state, (unsigned int)state->current_instruction_table.SQRT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fsqrt(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void genabs_d(usf_state_t * state) +{ +#ifdef INTERPRET_ABS_D + gencallinterp(state, (unsigned int)state->current_instruction_table.ABS_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fabs_(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void genmov_d(usf_state_t * state) +{ +#ifdef INTERPRET_MOV_D + gencallinterp(state, (unsigned int)state->current_instruction_table.MOV_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + mov_reg32_preg32(state, EBX, EAX); + mov_reg32_preg32pimm32(state, ECX, EAX, 4); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + mov_preg32_reg32(state, EAX, EBX); + mov_preg32pimm32_reg32(state, EAX, 4, ECX); +#endif +} + +void genneg_d(usf_state_t * state) +{ +#ifdef INTERPRET_NEG_D + gencallinterp(state, (unsigned int)state->current_instruction_table.NEG_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fchs(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void genround_l_d(usf_state_t * state) +{ +#ifdef INTERPRET_ROUND_L_D + gencallinterp(state, (unsigned int)state->current_instruction_table.ROUND_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->round_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_l_d(usf_state_t * state) +{ +#ifdef INTERPRET_TRUNC_L_D + gencallinterp(state, (unsigned int)state->current_instruction_table.TRUNC_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->trunc_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_l_d(usf_state_t * state) +{ +#ifdef INTERPRET_CEIL_L_D + gencallinterp(state, (unsigned int)state->current_instruction_table.CEIL_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->ceil_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_l_d(usf_state_t * state) +{ +#ifdef INTERPRET_FLOOR_L_D + gencallinterp(state, (unsigned int)state->current_instruction_table.FLOOR_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->floor_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genround_w_d(usf_state_t * state) +{ +#ifdef INTERPRET_ROUND_W_D + gencallinterp(state, (unsigned int)state->current_instruction_table.ROUND_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->round_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_w_d(usf_state_t * state) +{ +#ifdef INTERPRET_TRUNC_W_D + gencallinterp(state, (unsigned int)state->current_instruction_table.TRUNC_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->trunc_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_w_d(usf_state_t * state) +{ +#ifdef INTERPRET_CEIL_W_D + gencallinterp(state, (unsigned int)state->current_instruction_table.CEIL_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->ceil_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_w_d(usf_state_t * state) +{ +#ifdef INTERPRET_FLOOR_W_D + gencallinterp(state, (unsigned int)state->current_instruction_table.FLOOR_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->floor_mode); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gencvt_s_d(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_S_D + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_S_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gencvt_w_d(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_W_D + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_W_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); +#endif +} + +void gencvt_l_d(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_L_D + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_L_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); +#endif +} + +void genc_f_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_F_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_F_D, 0); +#else + gencheck_cop1_unusable(state); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_un_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_UN_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_UN_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 12); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 + jmp_imm_short(state, 10); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 +#endif +} + +void genc_eq_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_EQ_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_EQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ueq_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_UEQ_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_UEQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_olt_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_OLT_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_OLT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ult_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_ULT_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_ULT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jae_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ole_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_OLE_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_OLE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ule_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_ULE_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_ULE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + ja_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_sf_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_SF_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_SF_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_ngle_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGLE_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGLE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 12); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 + jmp_imm_short(state, 10); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 +#endif +} + +void genc_seq_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_SEQ_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_SEQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ngl_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGL_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGL_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_lt_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_LT_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_LT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_nge_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGE_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jae_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_le_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_LE_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_LE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ngt_d(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGT_D + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg32_qword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + ja_rj(state, 12); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_l.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_l.c new file mode 100644 index 000000000..8191c851b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_l.c @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_l.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +void gencvt_s_l(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_S_L + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_S_L, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fild_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gencvt_d_l(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_D_L + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_D_L, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fild_preg32_qword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_s.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_s.c new file mode 100644 index 000000000..26aca1115 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_s.c @@ -0,0 +1,608 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_s.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/cp1.h" + +void genadd_s(usf_state_t * state) +{ +#ifdef INTERPRET_ADD_S + gencallinterp(state, (unsigned int)state->current_instruction_table.ADD_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fadd_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gensub_s(usf_state_t * state) +{ +#ifdef INTERPRET_SUB_S + gencallinterp(state, (unsigned int)state->current_instruction_table.SUB_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fsub_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void genmul_s(usf_state_t * state) +{ +#ifdef INTERPRET_MUL_S + gencallinterp(state, (unsigned int)state->current_instruction_table.MUL_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fmul_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gendiv_s(usf_state_t * state) +{ +#ifdef INTERPRET_DIV_S + gencallinterp(state, (unsigned int)state->current_instruction_table.DIV_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fdiv_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gensqrt_s(usf_state_t * state) +{ +#ifdef INTERPRET_SQRT_S + gencallinterp(state, (unsigned int)state->current_instruction_table.SQRT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fsqrt(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void genabs_s(usf_state_t * state) +{ +#ifdef INTERPRET_ABS_S + gencallinterp(state, (unsigned int)state->current_instruction_table.ABS_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fabs_(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void genmov_s(usf_state_t * state) +{ +#ifdef INTERPRET_MOV_S + gencallinterp(state, (unsigned int)state->current_instruction_table.MOV_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + mov_reg32_preg32(state, EBX, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + mov_preg32_reg32(state, EAX, EBX); +#endif +} + +void genneg_s(usf_state_t * state) +{ +#ifdef INTERPRET_NEG_S + gencallinterp(state, (unsigned int)state->current_instruction_table.NEG_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fchs(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void genround_l_s(usf_state_t * state) +{ +#ifdef INTERPRET_ROUND_L_S + gencallinterp(state, (unsigned int)state->current_instruction_table.ROUND_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->round_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_l_s(usf_state_t * state) +{ +#ifdef INTERPRET_TRUNC_L_S + gencallinterp(state, (unsigned int)state->current_instruction_table.TRUNC_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->trunc_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_l_s(usf_state_t * state) +{ +#ifdef INTERPRET_CEIL_L_S + gencallinterp(state, (unsigned int)state->current_instruction_table.CEIL_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->ceil_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_l_s(usf_state_t * state) +{ +#ifdef INTERPRET_FLOOR_L_S + gencallinterp(state, (unsigned int)state->current_instruction_table.FLOOR_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->floor_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genround_w_s(usf_state_t * state) +{ +#ifdef INTERPRET_ROUND_W_S + gencallinterp(state, (unsigned int)state->current_instruction_table.ROUND_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->round_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_w_s(usf_state_t * state) +{ +#ifdef INTERPRET_TRUNC_W_S + gencallinterp(state, (unsigned int)state->current_instruction_table.TRUNC_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->trunc_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_w_s(usf_state_t * state) +{ +#ifdef INTERPRET_CEIL_W_S + gencallinterp(state, (unsigned int)state->current_instruction_table.CEIL_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->ceil_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_w_s(usf_state_t * state) +{ +#ifdef INTERPRET_FLOOR_W_S + gencallinterp(state, (unsigned int)state->current_instruction_table.FLOOR_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16(state, (unsigned short*)&state->floor_mode); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); + fldcw_m16(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gencvt_d_s(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_D_S + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_D_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + +void gencvt_w_s(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_W_S + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_W_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg32_dword(state, EAX); +#endif +} + +void gencvt_l_s(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_L_S + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_L_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg32_qword(state, EAX); +#endif +} + +void genc_f_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_F_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_F_S, 0); +#else + gencheck_cop1_unusable(state); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_un_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_UN_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_UN_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 12); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 + jmp_imm_short(state, 10); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 +#endif +} + +void genc_eq_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_EQ_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_EQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ueq_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_UEQ_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_UEQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_olt_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_OLT_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_OLT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ult_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_ULT_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_ULT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jae_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ole_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_OLE_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_OLE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ule_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_ULE_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_ULE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + ja_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_sf_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_SF_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_SF_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_ngle_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGLE_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGLE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 12); + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 + jmp_imm_short(state, 10); // 2 + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 +#endif +} + +void genc_seq_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_SEQ_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_SEQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ngl_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGL_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGL_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jne_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_lt_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_LT_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_LT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_nge_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGE_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + jae_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_le_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_LE_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_LE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + +void genc_ngt_s(usf_state_t * state) +{ +#ifdef INTERPRET_C_NGT_S + gencallinterp(state, (unsigned int)state->current_instruction_table.C_NGT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg32_dword(state, EAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 14); + ja_rj(state, 12); + or_m32_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 10 + jmp_imm_short(state, 10); // 2 + and_m32_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 10 +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_w.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_w.c new file mode 100644 index 000000000..8facaf2f6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gcop1_w.c @@ -0,0 +1,61 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_w.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +void gencvt_s_w(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_S_W + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_S_W, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fild_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg32_dword(state, EAX); +#endif +} + +void gencvt_d_w(usf_state_t * state) +{ +#ifdef INTERPRET_CVT_D_W + gencallinterp(state, (unsigned int)state->current_instruction_table.CVT_D_W, 0); +#else + gencheck_cop1_unusable(state); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fild_preg32_dword(state, EAX); + mov_eax_memoffs32(state, (unsigned int*)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg32_qword(state, EAX); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gr4300.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gr4300.c new file mode 100644 index 000000000..47f02e53e --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gr4300.c @@ -0,0 +1,2034 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gr4300.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "assemble.h" +#include "interpret.h" +#include "regcache.h" + +#include "main/main.h" +#include "memory/memory.h" +#include "r4300/r4300.h" +#include "r4300/cached_interp.h" +#include "r4300/cp0.h" +#include "r4300/cp1.h" +#include "r4300/interupt.h" +#include "r4300/ops.h" +#include "r4300/recomph.h" +#include "r4300/exception.h" + +/* static functions */ + +static void genupdate_count(usf_state_t * state, unsigned int addr) +{ + mov_reg32_imm32(state, EAX, addr); + sub_reg32_m32(state, EAX, (unsigned int*)(&state->last_addr)); + shr_reg32_imm8(state, EAX, 2); + mov_reg32_m32(state, EDX, &state->count_per_op); + mul_reg32(state, EDX); + add_m32_reg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); +} + +static void gencheck_interupt(usf_state_t * state, unsigned int instr_structure) +{ + free_register(state, ECX); + mov_eax_memoffs32(state, &state->next_interupt); + cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 19); + mov_m32_imm32(state, (unsigned int*)(&state->PC), instr_structure); // 10 + mov_reg32_imm32(state, EAX, (unsigned int)gen_interupt); // 5 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EAX); // 2 +} + +static void gencheck_interupt_out(usf_state_t * state, unsigned int addr) +{ + free_register(state, ECX); + mov_eax_memoffs32(state, &state->next_interupt); + cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 29); + mov_m32_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr); // 10 + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10 + mov_reg32_imm32(state, EAX, (unsigned int)gen_interupt); // 5 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EAX); // 2 +} + +static void genbeq_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + int rt_64bit = is64(state, (unsigned int *)state->dst->f.i.rt); + + if (!rs_64bit && !rt_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_reg32(state, rs, rt); + jne_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_m32(state, rt1, (unsigned int *)state->dst->f.i.rs); + jne_rj(state, 20); + cmp_reg32_m32(state, rt2, ((unsigned int *)state->dst->f.i.rs)+1); // 6 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rt_64bit == -1) + { + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_m32(state, rs1, (unsigned int *)state->dst->f.i.rt); + jne_rj(state, 20); + cmp_reg32_m32(state, rs2, ((unsigned int *)state->dst->f.i.rt)+1); // 6 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else + { + int rs1, rs2, rt1, rt2; + if (!rs_64bit) + { + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + } + else + { + rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + } + cmp_reg32_reg32(state, rs1, rt1); + jne_rj(state, 16); + cmp_reg32_reg32(state, rs2, rt2); // 2 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } +} + +static void genbne_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + int rt_64bit = is64(state, (unsigned int *)state->dst->f.i.rt); + + if (!rs_64bit && !rt_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_reg32(state, rs, rt); + je_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_m32(state, rt1, (unsigned int *)state->dst->f.i.rs); + jne_rj(state, 20); + cmp_reg32_m32(state, rt2, ((unsigned int *)state->dst->f.i.rs)+1); // 6 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } + else if (rt_64bit == -1) + { + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_m32(state, rs1, (unsigned int *)state->dst->f.i.rt); + jne_rj(state, 20); + cmp_reg32_m32(state, rs2, ((unsigned int *)state->dst->f.i.rt)+1); // 6 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } + else + { + int rs1, rs2, rt1, rt2; + if (!rs_64bit) + { + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + } + else + { + rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rt); + } + cmp_reg32_reg32(state, rs1, rt1); + jne_rj(state, 16); + cmp_reg32_reg32(state, rs2, rt2); // 2 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } +} + +static void genblez_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (!rs_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + jg_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + cmp_m32_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + jg_rj(state, 14); + jne_rj(state, 24); // 2 + cmp_m32_imm32(state, (unsigned int *)state->dst->f.i.rs, 0); // 10 + je_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } + else + { + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs2, 0); + jg_rj(state, 10); + jne_rj(state, 20); // 2 + cmp_reg32_imm32(state, rs1, 0); // 6 + je_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } +} + +static void genbgtz_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (!rs_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + jle_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + cmp_m32_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + jl_rj(state, 14); + jne_rj(state, 24); // 2 + cmp_m32_imm32(state, (unsigned int *)state->dst->f.i.rs, 0); // 10 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } + else + { + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs2, 0); + jl_rj(state, 10); + jne_rj(state, 20); // 2 + cmp_reg32_imm32(state, rs1, 0); // 6 + jne_rj(state, 12); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + } +} + + +/* global functions */ + +void gennotcompiled(usf_state_t * state) +{ + free_all_registers(state); + simplify_access(state); + + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst)); + mov_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); +} + +void genlink_subblock(usf_state_t * state) +{ + free_all_registers(state); + jmp(state, state->dst->addr+4); +} + +void gencallinterp(usf_state_t * state, unsigned long addr, int jump) +{ + free_all_registers(state); + simplify_access(state); + if (jump) + mov_m32_imm32(state, (unsigned int*)(&state->dyna_interp), 1); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst)); + mov_reg32_imm32(state, EAX, addr); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + if (jump) + { + mov_m32_imm32(state, (unsigned int*)(&state->dyna_interp), 0); + mov_reg32_imm32(state, EAX, (unsigned int)dyna_jump); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + } +} + +void gendelayslot(usf_state_t * state) +{ + mov_m32_imm32(state, &state->delay_slot, 1); + recompile_opcode(state); + + free_all_registers(state); + genupdate_count(state, state->dst->addr+4); + + mov_m32_imm32(state, &state->delay_slot, 0); +} + +void genni(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.NI, 0); +} + +void genreserved(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.RESERVED, 0); +} + +void genfin_block(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.FIN_BLOCK, 0); +} + +void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX +{ + free_register(state, ECX); + mov_reg32_m32(state, EBX, &state->next_interupt); + cmp_reg32_m32(state, EBX, &state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 24); + mov_memoffs32_eax(state, (unsigned int*)(&state->fake_instr.addr)); // 5 + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10 + mov_reg32_imm32(state, EAX, (unsigned int)gen_interupt); // 5 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EAX); // 2 +} + +void gennop(usf_state_t * state) +{ +} + +void genj(usf_state_t * state) +{ +#ifdef INTERPRET_J + gencallinterp(state, (unsigned int)state->current_instruction_table.J, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.J, 1); + return; + } + + gendelayslot(state); + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32_imm32(state, &state->last_addr, naddr); + gencheck_interupt(state, (unsigned int)&state->actual->block[(naddr-state->actual->start)/4]); + jmp(state, naddr); +#endif +} + +void genj_out(usf_state_t * state) +{ +#ifdef INTERPRET_J_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.J_OUT, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.J_OUT, 1); + return; + } + + gendelayslot(state); + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32_imm32(state, &state->last_addr, naddr); + gencheck_interupt_out(state, naddr); + mov_m32_imm32(state, &state->jump_to_address, naddr); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + free_register(state, ECX); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); +#endif +} + +void genj_idle(usf_state_t * state) +{ +#ifdef INTERPRET_J_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1); + return; + } + + mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt)); + sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, EAX, 3); + jbe_rj(state, 11); + + and_eax_imm32(state, 0xFFFFFFFC); // 5 + add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 6 + + genj(state); +#endif +} + +void genjal(usf_state_t * state) +{ +#ifdef INTERPRET_JAL + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL, 1); + return; + } + + gendelayslot(state); + + mov_m32_imm32(state, (unsigned int *)(state->reg + 31), state->dst->addr + 4); + if (((state->dst->addr + 4) & 0x80000000)) + mov_m32_imm32(state, (unsigned int *)(&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32_imm32(state, (unsigned int *)(&state->reg[31])+1, 0); + + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32_imm32(state, &state->last_addr, naddr); + gencheck_interupt(state, (unsigned int)&state->actual->block[(naddr-state->actual->start)/4]); + jmp(state, naddr); +#endif +} + +void genjal_out(usf_state_t * state) +{ +#ifdef INTERPRET_JAL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL_OUT, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL_OUT, 1); + return; + } + + gendelayslot(state); + + mov_m32_imm32(state, (unsigned int *)(state->reg + 31), state->dst->addr + 4); + if (((state->dst->addr + 4) & 0x80000000)) + mov_m32_imm32(state, (unsigned int *)(&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32_imm32(state, (unsigned int *)(&state->reg[31])+1, 0); + + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32_imm32(state, &state->last_addr, naddr); + gencheck_interupt_out(state, naddr); + mov_m32_imm32(state, &state->jump_to_address, naddr); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + free_register(state, ECX); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); +#endif +} + +void genjal_idle(usf_state_t * state) +{ +#ifdef INTERPRET_JAL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.JAL_IDLE, 1); + return; + } + + mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt)); + sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, EAX, 3); + jbe_rj(state, 11); + + and_eax_imm32(state, 0xFFFFFFFC); + add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); + + genjal(state); +#endif +} + +void gentest(usf_state_t * state) +{ + cmp_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32_imm32(state, &state->last_addr, state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt(state, (unsigned int)(state->dst + (state->dst-1)->f.i.immediate)); + jmp(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + + jump_end_rel32(state); + + mov_m32_imm32(state, &state->last_addr, state->dst->addr + 4); + gencheck_interupt(state, (unsigned int)(state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeq(usf_state_t * state) +{ +#ifdef INTERPRET_BEQ + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ, 1); + return; + } + + genbeq_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void gentest_out(usf_state_t * state) +{ + cmp_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32_imm32(state, &state->last_addr, state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt_out(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32_imm32(state, &state->jump_to_address, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + free_register(state, ECX); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + + jump_end_rel32(state); + + mov_m32_imm32(state, &state->last_addr, state->dst->addr + 4); + gencheck_interupt(state, (unsigned int)(state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeq_out(usf_state_t * state) +{ +#ifdef INTERPRET_BEQ_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ_OUT, 1); + return; + } + + genbeq_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void gentest_idle(usf_state_t * state) +{ + int reg; + + reg = lru_register(state); + free_register(state, reg); + + cmp_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_reg32_m32(state, reg, (unsigned int *)(&state->next_interupt)); + sub_reg32_m32(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, reg, 5); + jbe_rj(state, 18); + + sub_reg32_imm32(state, reg, 2); // 6 + and_reg32_imm32(state, reg, 0xFFFFFFFC); // 6 + add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); // 6 + + jump_end_rel32(state); +} + +void genbeq_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BEQ_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQ_IDLE, 1); + return; + } + + genbeq_test(state); + gentest_idle(state); + genbeq(state); +#endif +} + +void genbne(usf_state_t * state) +{ +#ifdef INTERPRET_BNE + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE, 1); + return; + } + + genbne_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbne_out(usf_state_t * state) +{ +#ifdef INTERPRET_BNE_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE_OUT, 1); + return; + } + + genbne_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbne_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BNE_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNE_IDLE, 1); + return; + } + + genbne_test(state); + gentest_idle(state); + genbne(state); +#endif +} + +void genblez(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZ + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ, 1); + return; + } + + genblez_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genblez_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZ_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ_OUT, 1); + return; + } + + genblez_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genblez_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZ_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZ_IDLE, 1); + return; + } + + genblez_test(state); + gentest_idle(state); + genblez(state); +#endif +} + +void genbgtz(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZ + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ, 1); + return; + } + + genbgtz_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgtz_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZ_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ_OUT, 1); + return; + } + + genbgtz_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgtz_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZ_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZ_IDLE, 1); + return; + } + + genbgtz_test(state); + gentest_idle(state); + genbgtz(state); +#endif +} + +void genaddi(usf_state_t * state) +{ +#ifdef INTERPRET_ADDI + gencallinterp(state, (unsigned int)state->current_instruction_table.ADDI, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt, rs); + add_reg32_imm32(state, rt,(int)state->dst->f.i.immediate); +#endif +} + +void genaddiu(usf_state_t * state) +{ +#ifdef INTERPRET_ADDIU + gencallinterp(state, (unsigned int)state->current_instruction_table.ADDIU, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt, rs); + add_reg32_imm32(state, rt,(int)state->dst->f.i.immediate); +#endif +} + +void genslti(usf_state_t * state) +{ +#ifdef INTERPRET_SLTI + gencallinterp(state, (unsigned int)state->current_instruction_table.SLTI, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + long long imm = (long long)state->dst->f.i.immediate; + + cmp_reg32_imm32(state, rs2, (unsigned int)(imm >> 32)); + jl_rj(state, 17); + jne_rj(state, 8); // 2 + cmp_reg32_imm32(state, rs1, (unsigned int)imm); // 6 + jl_rj(state, 7); // 2 + mov_reg32_imm32(state, rt, 0); // 5 + jmp_imm_short(state, 5); // 2 + mov_reg32_imm32(state, rt, 1); // 5 +#endif +} + +void gensltiu(usf_state_t * state) +{ +#ifdef INTERPRET_SLTIU + gencallinterp(state, (unsigned int)state->current_instruction_table.SLTIU, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + long long imm = (long long)state->dst->f.i.immediate; + + cmp_reg32_imm32(state, rs2, (unsigned int)(imm >> 32)); + jb_rj(state, 17); + jne_rj(state, 8); // 2 + cmp_reg32_imm32(state, rs1, (unsigned int)imm); // 6 + jb_rj(state, 7); // 2 + mov_reg32_imm32(state, rt, 0); // 5 + jmp_imm_short(state, 5); // 2 + mov_reg32_imm32(state, rt, 1); // 5 +#endif +} + +void genandi(usf_state_t * state) +{ +#ifdef INTERPRET_ANDI + gencallinterp(state, (unsigned int)state->current_instruction_table.ANDI, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt, rs); + and_reg32_imm32(state, rt, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genori(usf_state_t * state) +{ +#ifdef INTERPRET_ORI + gencallinterp(state, (unsigned int)state->current_instruction_table.ORI, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt1, rs1); + mov_reg32_reg32(state, rt2, rs2); + or_reg32_imm32(state, rt1, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genxori(usf_state_t * state) +{ +#ifdef INTERPRET_XORI + gencallinterp(state, (unsigned int)state->current_instruction_table.XORI, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt1, rs1); + mov_reg32_reg32(state, rt2, rs2); + xor_reg32_imm32(state, rt1, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genlui(usf_state_t * state) +{ +#ifdef INTERPRET_LUI + gencallinterp(state, (unsigned int)state->current_instruction_table.LUI, 0); +#else + int rt = allocate_register_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_imm32(state, rt, (unsigned int)state->dst->f.i.immediate << 16); +#endif +} + +void gentestl(usf_state_t * state) +{ + cmp_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + + jump_start_rel32(state); + + gendelayslot(state); + mov_m32_imm32(state, &state->last_addr, state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt(state, (unsigned int)(state->dst + (state->dst-1)->f.i.immediate)); + jmp(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + + jump_end_rel32(state); + + genupdate_count(state, state->dst->addr+4); + mov_m32_imm32(state, &state->last_addr, state->dst->addr + 4); + gencheck_interupt(state, (unsigned int)(state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeql(usf_state_t * state) +{ +#ifdef INTERPRET_BEQL + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL, 1); + return; + } + + genbeq_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void gentestl_out(usf_state_t * state) +{ + cmp_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + + jump_start_rel32(state); + + gendelayslot(state); + mov_m32_imm32(state, &state->last_addr, state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt_out(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32_imm32(state, &state->jump_to_address, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + free_register(state, ECX); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + + jump_end_rel32(state); + + genupdate_count(state, state->dst->addr+4); + mov_m32_imm32(state, &state->last_addr, state->dst->addr + 4); + gencheck_interupt(state, (unsigned int)(state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeql_out(usf_state_t * state) +{ +#ifdef INTERPRET_BEQL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL_OUT, 1); + return; + } + + genbeq_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbeql_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BEQL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BEQL_IDLE, 1); + return; + } + + genbeq_test(state); + gentest_idle(state); + genbeql(state); +#endif +} + +void genbnel(usf_state_t * state) +{ +#ifdef INTERPRET_BNEL + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL, 1); + return; + } + + genbne_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbnel_out(usf_state_t * state) +{ +#ifdef INTERPRET_BNEL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL_OUT, 1); + return; + } + + genbne_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbnel_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BNEL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BNEL_IDLE, 1); + return; + } + + genbne_test(state); + gentest_idle(state); + genbnel(state); +#endif +} + +void genblezl(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZL + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL, 1); + return; + } + + genblez_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genblezl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL_OUT, 1); + return; + } + + genblez_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genblezl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLEZL_IDLE, 1); + return; + } + + genblez_test(state); + gentest_idle(state); + genblezl(state); +#endif +} + +void genbgtzl(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZL + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL, 1); + return; + } + + genbgtz_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgtzl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL_OUT, 1); + return; + } + + genbgtz_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgtzl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGTZL_IDLE, 1); + return; + } + + genbgtz_test(state); + gentest_idle(state); + genbgtzl(state); +#endif +} + +void gendaddi(usf_state_t * state) +{ +#ifdef INTERPRET_DADDI + gencallinterp(state, (unsigned int)state->current_instruction_table.DADDI, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt1, rs1); + mov_reg32_reg32(state, rt2, rs2); + add_reg32_imm32(state, rt1, state->dst->f.i.immediate); + adc_reg32_imm32(state, rt2, (int)state->dst->f.i.immediate>>31); +#endif +} + +void gendaddiu(usf_state_t * state) +{ +#ifdef INTERPRET_DADDIU + gencallinterp(state, (unsigned int)state->current_instruction_table.DADDIU, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.i.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + int rt1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.i.rt); + int rt2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt1, rs1); + mov_reg32_reg32(state, rt2, rs2); + add_reg32_imm32(state, rt1, state->dst->f.i.immediate); + adc_reg32_imm32(state, rt2, (int)state->dst->f.i.immediate>>31); +#endif +} + +void genldl(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.LDL, 0); +} + +void genldr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.LDR, 0); +} + +void genlb(usf_state_t * state) +{ +#ifdef INTERPRET_LB + gencallinterp(state, (unsigned int)state->current_instruction_table.LB, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemb); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramb); + } + je_rj(state, 49); + + mov_m32_imm32(state, (unsigned int *)&state->PC, (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemb); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + movsx_reg32_m8(state, EAX, (unsigned char *)state->dst->f.i.rt); // 7 + jmp_imm_short(state, 16); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 3); // 3 + movsx_reg32_8preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 7 + + set_register_state(state, EAX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genlh(usf_state_t * state) +{ +#ifdef INTERPRET_LH + gencallinterp(state, (unsigned int)state->current_instruction_table.LH, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemh); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramh); + } + je_rj(state, 49); + + mov_m32_imm32(state, (unsigned int *)&state->PC, (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemh); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + movsx_reg32_m16(state, EAX, (unsigned short *)state->dst->f.i.rt); // 7 + jmp_imm_short(state, 16); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 2); // 3 + movsx_reg32_16preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 7 + + set_register_state(state, EAX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genlwl(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.LWL, 0); +} + +void genlw(usf_state_t * state) +{ +#ifdef INTERPRET_LW + gencallinterp(state, (unsigned int)state->current_instruction_table.LW, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmem); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdram); + } + je_rj(state, 47); + + mov_m32_imm32(state, (unsigned int *)&state->PC, (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmem); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(state->dst->f.i.rt)); // 5 + jmp_imm_short(state, 12); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 6 + + set_register_state(state, EAX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genlbu(usf_state_t * state) +{ +#ifdef INTERPRET_LBU + gencallinterp(state, (unsigned int)state->current_instruction_table.LBU, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemb); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramb); + } + je_rj(state, 48); + + mov_m32_imm32(state, (unsigned int *)&state->PC, (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemb); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_reg32_m32(state, EAX, (unsigned int *)state->dst->f.i.rt); // 6 + jmp_imm_short(state, 15); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 3); // 3 + mov_reg32_preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 6 + + and_eax_imm32(state, 0xFF); + + set_register_state(state, EAX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genlhu(usf_state_t * state) +{ +#ifdef INTERPRET_LHU + gencallinterp(state, (unsigned int)state->current_instruction_table.LHU, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemh); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramh); + } + je_rj(state, 48); + + mov_m32_imm32(state, (unsigned int *)&state->PC, (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemh); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_reg32_m32(state, EAX, (unsigned int *)state->dst->f.i.rt); // 6 + jmp_imm_short(state, 15); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 2); // 3 + mov_reg32_preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 6 + + and_eax_imm32(state, 0xFFFF); + + set_register_state(state, EAX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genlwr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.LWR, 0); +} + +void genlwu(usf_state_t * state) +{ +#ifdef INTERPRET_LWU + gencallinterp(state, (unsigned int)state->current_instruction_table.LWU, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmem); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdram); + } + je_rj(state, 47); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmem); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(state->dst->f.i.rt)); // 5 + jmp_imm_short(state, 12); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 6 + + xor_reg32_reg32(state, EBX, EBX); + + set_64_register_state(state, EAX, EBX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void gensb(usf_state_t * state) +{ +#ifdef INTERPRET_SB + gencallinterp(state, (unsigned int)state->current_instruction_table.SB, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_reg8_m8(state, CL, (unsigned char *)state->dst->f.i.rt); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writememb); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdramb); + } + je_rj(state, 43); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m8_reg8(state, (unsigned char *)(&state->cpu_byte), CL); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writememb); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 17); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 3); // 3 + mov_preg32pimm32_reg8(state, EBX, (unsigned int)state->g_rdram, CL); // 6 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void gensh(usf_state_t * state) +{ +#ifdef INTERPRET_SH + gencallinterp(state, (unsigned int)state->current_instruction_table.SH, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_reg16_m16(state, CX, (unsigned short *)state->dst->f.i.rt); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writememh); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdramh); + } + je_rj(state, 44); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m16_reg16(state, (unsigned short *)(&state->cpu_hword), CX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writememh); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 18); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 2); // 3 + mov_preg32pimm32_reg16(state, EBX, (unsigned int)state->g_rdram, CX); // 7 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void genswl(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.SWL, 0); +} + +void gensw(usf_state_t * state) +{ +#ifdef INTERPRET_SW + gencallinterp(state, (unsigned int)state->current_instruction_table.SW, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_reg32_m32(state, ECX, (unsigned int *)state->dst->f.i.rt); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writemem); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdram); + } + je_rj(state, 43); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_word), ECX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writemem); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 14); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg32pimm32_reg32(state, EBX, (unsigned int)state->g_rdram, ECX); // 6 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void gensdl(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.SDL, 0); +} + +void gensdr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.SDR, 0); +} + +void genswr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.SWR, 0); +} + +void gencheck_cop1_unusable(usf_state_t * state) +{ + free_all_registers(state); + simplify_access(state); + test_m32_imm32(state, (unsigned int*)&state->g_cp0_regs[CP0_STATUS_REG], 0x20000000); + jne_rj(state, 0); + + jump_start_rel8(state); + + gencallinterp(state, (unsigned int)check_cop1_unusable, 0); + + jump_end_rel8(state); +} + +void genlwc1(usf_state_t * state) +{ +#ifdef INTERPRET_LWC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.LWC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_eax_memoffs32(state, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmem); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdram); + } + je_rj(state, 44); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_reg32_m32(state, EDX, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.lf.ft])); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->rdword), EDX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmem); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + jmp_imm_short(state, 20); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg32pimm32(state, EAX, EBX, (unsigned int)state->g_rdram); // 6 + mov_reg32_m32(state, EBX, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.lf.ft])); // 6 + mov_preg32_reg32(state, EBX, EAX); // 2 +#endif +} + +void genldc1(usf_state_t * state) +{ +#ifdef INTERPRET_LDC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.LDC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_eax_memoffs32(state, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemd); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramd); + } + je_rj(state, 44); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_reg32_m32(state, EDX, (unsigned int*)(&state->reg_cop1_double[state->dst->f.lf.ft])); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->rdword), EDX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemd); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + jmp_imm_short(state, 32); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg32pimm32(state, EAX, EBX, ((unsigned int)state->g_rdram)+4); // 6 + mov_reg32_preg32pimm32(state, ECX, EBX, ((unsigned int)state->g_rdram)); // 6 + mov_reg32_m32(state, EBX, (unsigned int*)(&state->reg_cop1_double[state->dst->f.lf.ft])); // 6 + mov_preg32_reg32(state, EBX, EAX); // 2 + mov_preg32pimm32_reg32(state, EBX, 4, ECX); // 6 +#endif +} + +void gencache(usf_state_t * state) +{ +} + +void genld(usf_state_t * state) +{ +#ifdef INTERPRET_LD + gencallinterp(state, (unsigned int)state->current_instruction_table.LD, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->readmemd); + cmp_reg32_imm32(state, EAX, (unsigned int)read_rdramd); + } + je_rj(state, 53); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_imm32(state, (unsigned int *)(&state->rdword), (unsigned int)state->dst->f.i.rt); // 10 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->readmemd); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(state->dst->f.i.rt)); // 5 + mov_reg32_m32(state, ECX, (unsigned int *)(state->dst->f.i.rt)+1); // 6 + jmp_imm_short(state, 18); // 2 + + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg32pimm32(state, EAX, EBX, ((unsigned int)state->g_rdram)+4); // 6 + mov_reg32_preg32pimm32(state, ECX, EBX, ((unsigned int)state->g_rdram)); // 6 + + set_64_register_state(state, EAX, ECX, (unsigned int*)state->dst->f.i.rt, 1); +#endif +} + +void genswc1(usf_state_t * state) +{ +#ifdef INTERPRET_SWC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.SWC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_reg32_m32(state, EDX, (unsigned int*)(&state->reg_cop1_simple[state->dst->f.lf.ft])); + mov_reg32_preg32(state, ECX, EDX); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writemem); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdram); + } + je_rj(state, 43); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_word), ECX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writemem); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 14); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg32pimm32_reg32(state, EBX, (unsigned int)state->g_rdram, ECX); // 6 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void gensdc1(usf_state_t * state) +{ +#ifdef INTERPRET_SDC1 + gencallinterp(state, (unsigned int)state->current_instruction_table.SDC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_reg32_m32(state, EDI, (unsigned int*)(&state->reg_cop1_double[state->dst->f.lf.ft])); + mov_reg32_preg32(state, ECX, EDI); + mov_reg32_preg32pimm32(state, EDX, EDI, 4); + mov_eax_memoffs32(state, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writememd); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdramd); + } + je_rj(state, 49); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_dword), ECX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_dword)+1, EDX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writememd); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 20); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg32pimm32_reg32(state, EBX, ((unsigned int)state->g_rdram)+4, ECX); // 6 + mov_preg32pimm32_reg32(state, EBX, ((unsigned int)state->g_rdram)+0, EDX); // 6 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void gensd(usf_state_t * state) +{ +#ifdef INTERPRET_SD + gencallinterp(state, (unsigned int)state->current_instruction_table.SD, 0); +#else + free_all_registers(state); + simplify_access(state); + + mov_reg32_m32(state, ECX, (unsigned int *)state->dst->f.i.rt); + mov_reg32_m32(state, EDX, ((unsigned int *)state->dst->f.i.rt)+1); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + shr_reg32_imm8(state, EAX, 16); + mov_reg32_preg32x4pimm32(state, EAX, EAX, (unsigned int)state->writememd); + cmp_reg32_imm32(state, EAX, (unsigned int)write_rdramd); + } + je_rj(state, 49); + + mov_m32_imm32(state, (unsigned int *)(&state->PC), (unsigned int)(state->dst+1)); // 10 + mov_m32_reg32(state, (unsigned int *)(&state->address), EBX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_dword), ECX); // 6 + mov_m32_reg32(state, (unsigned int *)(&state->cpu_dword)+1, EDX); // 6 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg32_preg32x4pimm32(state, EBX, EBX, (unsigned int)state->writememd); // 7 + mov_reg32_reg32(state, ECX, ESI); // 2 + call_reg32(state, EBX); // 2 + mov_eax_memoffs32(state, (unsigned int *)(&state->address)); // 5 + jmp_imm_short(state, 20); // 2 + + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg32pimm32_reg32(state, EBX, ((unsigned int)state->g_rdram)+4, ECX); // 6 + mov_preg32pimm32_reg32(state, EBX, ((unsigned int)state->g_rdram)+0, EDX); // 6 + + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg32pimm32_imm8(state, EBX, (unsigned int)state->invalid_code, 0); + jne_rj(state, 54); + mov_reg32_reg32(state, ECX, EBX); // 2 + shl_reg32_imm8(state, EBX, 2); // 3 + mov_reg32_preg32pimm32(state, EBX, EBX, (unsigned int)state->blocks); // 6 + mov_reg32_preg32pimm32(state, EBX, EBX, (int)&state->actual->block - (int)state->actual); // 6 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg32_preg32preg32pimm32(state, EAX, EAX, EBX, (int)&state->dst->ops - (int)state->dst); // 7 + cmp_reg32_imm32(state, EAX, (unsigned int)state->current_instruction_table.NOTCOMPILED); // 6 + je_rj(state, 7); // 2 + mov_preg32pimm32_imm8(state, ECX, (unsigned int)state->invalid_code, 1); // 7 +#endif +} + +void genll(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.LL, 0); +} + +void gensc(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.SC, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gregimm.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gregimm.c new file mode 100644 index 000000000..fd38a2dae --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gregimm.c @@ -0,0 +1,582 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gregimm.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" + +#include "memory/memory.h" + +static void genbltz_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (!rs_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + jge_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + cmp_m32_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + jge_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else + { + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs2, 0); + jge_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } +} + +void genbltz(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZ + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ, 1); + return; + } + + genbltz_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbltz_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZ_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ_OUT, 1); + return; + } + + genbltz_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbltz_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZ_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZ_IDLE, 1); + return; + } + + genbltz_test(state); + gentest_idle(state); + genbltz(state); +#endif +} + +static void genbgez_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (!rs_64bit) + { + int rs = allocate_register(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + jl_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else if (rs_64bit == -1) + { + cmp_m32_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + jl_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } + else + { + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs2, 0); + jl_rj(state, 12); + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 1); // 10 + jmp_imm_short(state, 10); // 2 + mov_m32_imm32(state, (unsigned int *)(&state->branch_taken), 0); // 10 + } +} + +void genbgez(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZ + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ, 1); + return; + } + + genbgez_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgez_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZ_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ_OUT, 1); + return; + } + + genbgez_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgez_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZ_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZ_IDLE, 1); + return; + } + + genbgez_test(state); + gentest_idle(state); + genbgez(state); +#endif +} + +void genbltzl(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZL + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL, 1); + return; + } + + genbltz_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbltzl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL_OUT, 1); + return; + } + + genbltz_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbltzl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZL_IDLE, 1); + return; + } + + genbltz_test(state); + gentest_idle(state); + genbltzl(state); +#endif +} + +void genbgezl(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZL + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL, 1); + return; + } + + genbgez_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgezl_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL_OUT, 1); + return; + } + + genbgez_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgezl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZL_IDLE, 1); + return; + } + + genbgez_test(state); + gentest_idle(state); + genbgezl(state); +#endif +} + +static void genbranchlink(usf_state_t * state) +{ + int r31_64bit = is64(state, (unsigned int*)&state->reg[31]); + + if (!r31_64bit) + { + int r31 = allocate_register_w(state, (unsigned int *)&state->reg[31]); + + mov_reg32_imm32(state, r31, state->dst->addr+8); + } + else if (r31_64bit == -1) + { + mov_m32_imm32(state, (unsigned int *)&state->reg[31], state->dst->addr + 8); + if (state->dst->addr & 0x80000000) + mov_m32_imm32(state, ((unsigned int *)&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32_imm32(state, ((unsigned int *)&state->reg[31])+1, 0); + } + else + { + int r311 = allocate_64_register1_w(state, (unsigned int *)&state->reg[31]); + int r312 = allocate_64_register2_w(state, (unsigned int *)&state->reg[31]); + + mov_reg32_imm32(state, r311, state->dst->addr+8); + if (state->dst->addr & 0x80000000) + mov_reg32_imm32(state, r312, 0xFFFFFFFF); + else + mov_reg32_imm32(state, r312, 0); + } +} + +void genbltzal(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZAL + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbltzal_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZAL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL_OUT, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbltzal_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZAL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZAL_IDLE, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gentest_idle(state); + genbltzal(state); +#endif +} + +void genbgezal(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZAL + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgezal_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZAL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL_OUT, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgezal_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZAL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZAL_IDLE, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gentest_idle(state); + genbgezal(state); +#endif +} + +void genbltzall(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZALL + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbltzall_out(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZALL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL_OUT, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbltzall_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZALL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BLTZALL_IDLE, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gentest_idle(state); + genbltzall(state); +#endif +} + +void genbgezall(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZALL + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgezall_out(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZALL_OUT + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL_OUT, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgezall_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZALL_IDLE + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.BGEZALL_IDLE, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gentest_idle(state); + genbgezall(state); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gspecial.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gspecial.c new file mode 100644 index 000000000..1cc62c319 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gspecial.c @@ -0,0 +1,1167 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gspecial.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp0.h" +#include "r4300/exception.h" + +void gensll(usf_state_t * state) +{ +#ifdef INTERPRET_SLL + gencallinterp(state, (unsigned int)state->current_instruction_table.SLL, 0); +#else + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + shl_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensrl(usf_state_t * state) +{ +#ifdef INTERPRET_SRL + gencallinterp(state, (unsigned int)state->current_instruction_table.SRL, 0); +#else + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + shr_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensra(usf_state_t * state) +{ +#ifdef INTERPRET_SRA + gencallinterp(state, (unsigned int)state->current_instruction_table.SRA, 0); +#else + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + sar_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensllv(usf_state_t * state) +{ +#ifdef INTERPRET_SLLV + gencallinterp(state, (unsigned int)state->current_instruction_table.SLLV, 0); +#else + int rt, rd; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + shl_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + shl_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensrlv(usf_state_t * state) +{ +#ifdef INTERPRET_SRLV + gencallinterp(state, (unsigned int)state->current_instruction_table.SRLV, 0); +#else + int rt, rd; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + shr_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + shr_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensrav(usf_state_t * state) +{ +#ifdef INTERPRET_SRAV + gencallinterp(state, (unsigned int)state->current_instruction_table.SRAV, 0); +#else + int rt, rd; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + sar_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + sar_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void genjr(usf_state_t * state) +{ +#ifdef INTERPRET_JR + gencallinterp(state, (unsigned int)state->current_instruction_table.JR, 1); +#else + unsigned int diff = + (unsigned int)(&state->dst->local_addr) - (unsigned int)(state->dst); + unsigned int diff_need = + (unsigned int)(&state->dst->reg_cache_infos.need_map) - (unsigned int)(state->dst); + unsigned int diff_wrap = + (unsigned int)(&state->dst->reg_cache_infos.jump_wrapper) - (unsigned int)(state->dst); + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.JR, 1); + return; + } + + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.i.rs); + mov_memoffs32_eax(state, (unsigned int *)&state->local_rs); + + gendelayslot(state); + + mov_eax_memoffs32(state, (unsigned int *)&state->local_rs); + mov_memoffs32_eax(state, (unsigned int *)&state->last_addr); + + gencheck_interupt_reg(state); + + mov_eax_memoffs32(state, (unsigned int *)&state->local_rs); + mov_reg32_reg32(state, EBX, EAX); + and_eax_imm32(state, 0xFFFFF000); + cmp_eax_imm32(state, state->dst_block->start & 0xFFFFF000); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32_reg32(state, &state->jump_to_address, EBX); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + + jump_end_rel32(state); + + mov_reg32_reg32(state, EAX, EBX); + sub_eax_imm32(state, state->dst_block->start); + shr_reg32_imm8(state, EAX, 2); + mul_m32(state, (unsigned int *)(&state->precomp_instr_size)); + + mov_reg32_preg32pimm32(state, EBX, EAX, (unsigned int)(state->dst_block->block)+diff_need); + cmp_reg32_imm32(state, EBX, 1); + jne_rj(state, 7); + + add_eax_imm32(state, (unsigned int)(state->dst_block->block)+diff_wrap); // 5 + jmp_reg32(state, EAX); // 2 + + mov_reg32_preg32pimm32(state, EAX, EAX, (unsigned int)(state->dst_block->block)+diff); + add_reg32_m32(state, EAX, (unsigned int *)(&state->dst_block->code)); + + jmp_reg32(state, EAX); +#endif +} + +void genjalr(usf_state_t * state) +{ +#ifdef INTERPRET_JALR + gencallinterp(state, (unsigned int)state->current_instruction_table.JALR, 0); +#else + unsigned int diff = + (unsigned int)(&state->dst->local_addr) - (unsigned int)(state->dst); + unsigned int diff_need = + (unsigned int)(&state->dst->reg_cache_infos.need_map) - (unsigned int)(state->dst); + unsigned int diff_wrap = + (unsigned int)(&state->dst->reg_cache_infos.jump_wrapper) - (unsigned int)(state->dst); + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned int)state->current_instruction_table.JALR, 1); + return; + } + + free_all_registers(state); + simplify_access(state); + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.r.rs); + mov_memoffs32_eax(state, (unsigned int *)&state->local_rs); + + gendelayslot(state); + + mov_m32_imm32(state, (unsigned int *)(state->dst-1)->f.r.rd, state->dst->addr+4); + if ((state->dst->addr+4) & 0x80000000) + mov_m32_imm32(state, ((unsigned int *)(state->dst-1)->f.r.rd)+1, 0xFFFFFFFF); + else + mov_m32_imm32(state, ((unsigned int *)(state->dst-1)->f.r.rd)+1, 0); + + mov_eax_memoffs32(state, (unsigned int *)&state->local_rs); + mov_memoffs32_eax(state, (unsigned int *)&state->last_addr); + + gencheck_interupt_reg(state); + + mov_eax_memoffs32(state, (unsigned int *)&state->local_rs); + mov_reg32_reg32(state, EBX, EAX); + and_eax_imm32(state, 0xFFFFF000); + cmp_eax_imm32(state, state->dst_block->start & 0xFFFFF000); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32_reg32(state, &state->jump_to_address, EBX); + mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(state->dst+1)); + mov_reg32_imm32(state, EAX, (unsigned int)jump_to_func); + mov_reg32_reg32(state, ECX, ESI); + call_reg32(state, EAX); + + jump_end_rel32(state); + + mov_reg32_reg32(state, EAX, EBX); + sub_eax_imm32(state, state->dst_block->start); + shr_reg32_imm8(state, EAX, 2); + mul_m32(state, (unsigned int *)(&state->precomp_instr_size)); + + mov_reg32_preg32pimm32(state, EBX, EAX, (unsigned int)(state->dst_block->block)+diff_need); + cmp_reg32_imm32(state, EBX, 1); + jne_rj(state, 7); + + add_eax_imm32(state, (unsigned int)(state->dst_block->block)+diff_wrap); // 5 + jmp_reg32(state, EAX); // 2 + + mov_reg32_preg32pimm32(state, EAX, EAX, (unsigned int)(state->dst_block->block)+diff); + add_reg32_m32(state, EAX, (unsigned int *)(&state->dst_block->code)); + + jmp_reg32(state, EAX); +#endif +} + +void gensyscall(usf_state_t * state) +{ +#ifdef INTERPRET_SYSCALL + gencallinterp(state, (unsigned int)state->current_instruction_table.SYSCALL, 0); +#else + free_all_registers(state); + simplify_access(state); + mov_m32_imm32(state, &state->g_cp0_regs[CP0_CAUSE_REG], 8 << 2); + gencallinterp(state, (unsigned int)exception_general, 0); +#endif +} + +void gensync(usf_state_t * state) +{ +} + +void genmfhi(usf_state_t * state) +{ +#ifdef INTERPRET_MFHI + gencallinterp(state, (unsigned int)state->current_instruction_table.MFHI, 0); +#else + int rd1 = allocate_64_register1_w(state, (unsigned int*)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int*)state->dst->f.r.rd); + int hi1 = allocate_64_register1(state, (unsigned int*)&state->hi); + int hi2 = allocate_64_register2(state, (unsigned int*)&state->hi); + + mov_reg32_reg32(state, rd1, hi1); + mov_reg32_reg32(state, rd2, hi2); +#endif +} + +void genmthi(usf_state_t * state) +{ +#ifdef INTERPRET_MTHI + gencallinterp(state, (unsigned int)state->current_instruction_table.MTHI, 0); +#else + int hi1 = allocate_64_register1_w(state, (unsigned int*)&state->hi); + int hi2 = allocate_64_register2_w(state, (unsigned int*)&state->hi); + int rs1 = allocate_64_register1(state, (unsigned int*)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int*)state->dst->f.r.rs); + + mov_reg32_reg32(state, hi1, rs1); + mov_reg32_reg32(state, hi2, rs2); +#endif +} + +void genmflo(usf_state_t * state) +{ +#ifdef INTERPRET_MFLO + gencallinterp(state, (unsigned int)state->current_instruction_table.MFLO, 0); +#else + int rd1 = allocate_64_register1_w(state, (unsigned int*)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int*)state->dst->f.r.rd); + int lo1 = allocate_64_register1(state, (unsigned int*)&state->lo); + int lo2 = allocate_64_register2(state, (unsigned int*)&state->lo); + + mov_reg32_reg32(state, rd1, lo1); + mov_reg32_reg32(state, rd2, lo2); +#endif +} + +void genmtlo(usf_state_t * state) +{ +#ifdef INTERPRET_MTLO + gencallinterp(state, (unsigned int)state->current_instruction_table.MTLO, 0); +#else + int lo1 = allocate_64_register1_w(state, (unsigned int*)&state->lo); + int lo2 = allocate_64_register2_w(state, (unsigned int*)&state->lo); + int rs1 = allocate_64_register1(state, (unsigned int*)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int*)state->dst->f.r.rs); + + mov_reg32_reg32(state, lo1, rs1); + mov_reg32_reg32(state, lo2, rs2); +#endif +} + +void gendsllv(usf_state_t * state) +{ +#ifdef INTERPRET_DSLLV + gencallinterp(state, (unsigned int)state->current_instruction_table.DSLLV, 0); +#else + int rt1, rt2, rd1, rd2; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd1 != ECX && rd2 != ECX) + { + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shld_reg32_reg32_cl(state, rd2,rd1); + shl_reg32_cl(state, rd1); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 4); + mov_reg32_reg32(state, rd2, rd1); // 2 + xor_reg32_reg32(state, rd1, rd1); // 2 + } + else + { + int temp1, temp2; + force_32(state, ECX); + temp1 = lru_register(state); + temp2 = lru_register_exc1(state, temp1); + free_register(state, temp1); + free_register(state, temp2); + + mov_reg32_reg32(state, temp1, rt1); + mov_reg32_reg32(state, temp2, rt2); + shld_reg32_reg32_cl(state, temp2, temp1); + shl_reg32_cl(state, temp1); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 4); + mov_reg32_reg32(state, temp2, temp1); // 2 + xor_reg32_reg32(state, temp1, temp1); // 2 + + mov_reg32_reg32(state, rd1, temp1); + mov_reg32_reg32(state, rd2, temp2); + } +#endif +} + +void gendsrlv(usf_state_t * state) +{ +#ifdef INTERPRET_DSRLV + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRLV, 0); +#else + int rt1, rt2, rd1, rd2; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd1 != ECX && rd2 != ECX) + { + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shrd_reg32_reg32_cl(state, rd1,rd2); + shr_reg32_cl(state, rd2); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 4); + mov_reg32_reg32(state, rd1, rd2); // 2 + xor_reg32_reg32(state, rd2, rd2); // 2 + } + else + { + int temp1, temp2; + force_32(state, ECX); + temp1 = lru_register(state); + temp2 = lru_register_exc1(state, temp1); + free_register(state, temp1); + free_register(state, temp2); + + mov_reg32_reg32(state, temp1, rt1); + mov_reg32_reg32(state, temp2, rt2); + shrd_reg32_reg32_cl(state, temp1, temp2); + shr_reg32_cl(state, temp2); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 4); + mov_reg32_reg32(state, temp1, temp2); // 2 + xor_reg32_reg32(state, temp2, temp2); // 2 + + mov_reg32_reg32(state, rd1, temp1); + mov_reg32_reg32(state, rd2, temp2); + } +#endif +} + +void gendsrav(usf_state_t * state) +{ +#ifdef INTERPRET_DSRAV + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRAV, 0); +#else + int rt1, rt2, rd1, rd2; + allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd1 != ECX && rd2 != ECX) + { + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shrd_reg32_reg32_cl(state, rd1,rd2); + sar_reg32_cl(state, rd2); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 5); + mov_reg32_reg32(state, rd1, rd2); // 2 + sar_reg32_imm8(state, rd2, 31); // 3 + } + else + { + int temp1, temp2; + force_32(state, ECX); + temp1 = lru_register(state); + temp2 = lru_register_exc1(state, temp1); + free_register(state, temp1); + free_register(state, temp2); + + mov_reg32_reg32(state, temp1, rt1); + mov_reg32_reg32(state, temp2, rt2); + shrd_reg32_reg32_cl(state, temp1, temp2); + sar_reg32_cl(state, temp2); + test_reg32_imm32(state, ECX, 0x20); + je_rj(state, 5); + mov_reg32_reg32(state, temp1, temp2); // 2 + sar_reg32_imm8(state, temp2, 31); // 3 + + mov_reg32_reg32(state, rd1, temp1); + mov_reg32_reg32(state, rd2, temp2); + } +#endif +} + +void genmult(usf_state_t * state) +{ +#ifdef INTERPRET_MULT + gencallinterp(state, (unsigned int)state->current_instruction_table.MULT, 0); +#else + int rs, rt; + allocate_register_manually_w(state, EAX, (unsigned int *)&state->lo, 0); + allocate_register_manually_w(state, EDX, (unsigned int *)&state->hi, 0); + rs = allocate_register(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_reg32(state, EAX, rs); + imul_reg32(state, rt); +#endif +} + +void genmultu(usf_state_t * state) +{ +#ifdef INTERPRET_MULTU + gencallinterp(state, (unsigned int)state->current_instruction_table.MULTU, 0); +#else + int rs, rt; + allocate_register_manually_w(state, EAX, (unsigned int *)&state->lo, 0); + allocate_register_manually_w(state, EDX, (unsigned int *)&state->hi, 0); + rs = allocate_register(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_reg32(state, EAX, rs); + mul_reg32(state, rt); +#endif +} + +void gendiv(usf_state_t * state) +{ +#ifdef INTERPRET_DIV + gencallinterp(state, (unsigned int)state->current_instruction_table.DIV, 0); +#else + int rs, rt; + allocate_register_manually_w(state, EAX, (unsigned int *)&state->lo, 0); + allocate_register_manually_w(state, EDX, (unsigned int *)&state->hi, 0); + rs = allocate_register(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register(state, (unsigned int*)state->dst->f.r.rt); + cmp_reg32_imm32(state, rt, 0); + je_rj(state, (rs == EAX ? 0 : 2) + 1 + 2); + mov_reg32_reg32(state, EAX, rs); // 0 or 2 + cdq(state); // 1 + idiv_reg32(state, rt); // 2 +#endif +} + +void gendivu(usf_state_t * state) +{ +#ifdef INTERPRET_DIVU + gencallinterp(state, (unsigned int)state->current_instruction_table.DIVU, 0); +#else + int rs, rt; + allocate_register_manually_w(state, EAX, (unsigned int *)&state->lo, 0); + allocate_register_manually_w(state, EDX, (unsigned int *)&state->hi, 0); + rs = allocate_register(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register(state, (unsigned int*)state->dst->f.r.rt); + cmp_reg32_imm32(state, rt, 0); + je_rj(state, (rs == EAX ? 0 : 2) + 2 + 2); + mov_reg32_reg32(state, EAX, rs); // 0 or 2 + xor_reg32_reg32(state, EDX, EDX); // 2 + div_reg32(state, rt); // 2 +#endif +} + +void gendmult(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.DMULT, 0); +} + +void gendmultu(usf_state_t * state) +{ +#ifdef INTERPRET_DMULTU + gencallinterp(state, (unsigned int)state->current_instruction_table.DMULTU, 0); +#else + free_all_registers(state); + simplify_access(state); + + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.r.rs); + mul_m32(state, (unsigned int *)state->dst->f.r.rt); // EDX:EAX = temp1 + mov_memoffs32_eax(state, (unsigned int *)(&state->lo)); + + mov_reg32_reg32(state, EBX, EDX); // EBX = temp1>>32 + mov_eax_memoffs32(state, (unsigned int *)state->dst->f.r.rs); + mul_m32(state, (unsigned int *)(state->dst->f.r.rt)+1); + add_reg32_reg32(state, EBX, EAX); + adc_reg32_imm32(state, EDX, 0); + mov_reg32_reg32(state, ECX, EDX); // ECX:EBX = temp2 + + mov_eax_memoffs32(state, (unsigned int *)(state->dst->f.r.rs)+1); + mul_m32(state, (unsigned int *)state->dst->f.r.rt); // EDX:EAX = temp3 + + add_reg32_reg32(state, EBX, EAX); + adc_reg32_imm32(state, ECX, 0); // ECX:EBX = result2 + mov_m32_reg32(state, (unsigned int*)(&state->lo)+1, EBX); + + mov_reg32_reg32(state, EDI, EDX); // EDI = temp3>>32 + mov_eax_memoffs32(state, (unsigned int *)(state->dst->f.r.rs)+1); + mul_m32(state, (unsigned int *)(state->dst->f.r.rt)+1); + add_reg32_reg32(state, EAX, EDI); + adc_reg32_imm32(state, EDX, 0); // EDX:EAX = temp4 + + add_reg32_reg32(state, EAX, ECX); + adc_reg32_imm32(state, EDX, 0); // EDX:EAX = result3 + mov_memoffs32_eax(state,(unsigned int *)(&state->hi)); + mov_m32_reg32(state, (unsigned int *)(&state->hi)+1, EDX); +#endif +} + +void genddiv(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.DDIV, 0); +} + +void genddivu(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.DDIVU, 0); +} + +void genadd(usf_state_t * state) +{ +#ifdef INTERPRET_ADD + gencallinterp(state, (unsigned int)state->current_instruction_table.ADD, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt != rd && rs != rd) + { + mov_reg32_reg32(state, rd, rs); + add_reg32_reg32(state, rd, rt); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs); + add_reg32_reg32(state, temp, rt); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void genaddu(usf_state_t * state) +{ +#ifdef INTERPRET_ADDU + gencallinterp(state, (unsigned int)state->current_instruction_table.ADDU, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt != rd && rs != rd) + { + mov_reg32_reg32(state, rd, rs); + add_reg32_reg32(state, rd, rt); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs); + add_reg32_reg32(state, temp, rt); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensub(usf_state_t * state) +{ +#ifdef INTERPRET_SUB + gencallinterp(state, (unsigned int)state->current_instruction_table.SUB, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt != rd && rs != rd) + { + mov_reg32_reg32(state, rd, rs); + sub_reg32_reg32(state, rd, rt); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs); + sub_reg32_reg32(state, temp, rt); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensubu(usf_state_t * state) +{ +#ifdef INTERPRET_SUBU + gencallinterp(state, (unsigned int)state->current_instruction_table.SUBU, 0); +#else + int rs = allocate_register(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt != rd && rs != rd) + { + mov_reg32_reg32(state, rd, rs); + sub_reg32_reg32(state, rd, rt); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs); + sub_reg32_reg32(state, temp, rt); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void genand(usf_state_t * state) +{ +#ifdef INTERPRET_AND + gencallinterp((unsigned int)state->current_instruction_table.AND, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + and_reg32_reg32(state, rd1, rt1); + and_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + and_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + and_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void genor(usf_state_t * state) +{ +#ifdef INTERPRET_OR + gencallinterp(state, (unsigned int)state->current_instruction_table.OR, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + or_reg32_reg32(state, rd1, rt1); + or_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + or_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + or_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void genxor(usf_state_t * state) +{ +#ifdef INTERPRET_XOR + gencallinterp(state, (unsigned int)state->current_instruction_table.XOR, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + xor_reg32_reg32(state, rd1, rt1); + xor_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + xor_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + xor_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void gennor(usf_state_t * state) +{ +#ifdef INTERPRET_NOR + gencallinterp(state, (unsigned int)state->current_instruction_table.NOR, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + or_reg32_reg32(state, rd1, rt1); + or_reg32_reg32(state, rd2, rt2); + not_reg32(state, rd1); + not_reg32(state, rd2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + or_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + or_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + not_reg32(state, rd1); + not_reg32(state, rd2); + } +#endif +} + +void genslt(usf_state_t * state) +{ +#ifdef INTERPRET_SLT + gencallinterp(state, (unsigned int)state->current_instruction_table.SLT, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + cmp_reg32_reg32(state, rs2, rt2); + jl_rj(state, 13); + jne_rj(state, 4); // 2 + cmp_reg32_reg32(state, rs1, rt1); // 2 + jl_rj(state, 7); // 2 + mov_reg32_imm32(state, rd, 0); // 5 + jmp_imm_short(state, 5); // 2 + mov_reg32_imm32(state, rd, 1); // 5 +#endif +} + +void gensltu(usf_state_t * state) +{ +#ifdef INTERPRET_SLTU + gencallinterp(state, (unsigned int)state->current_instruction_table.SLTU, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + cmp_reg32_reg32(state, rs2, rt2); + jb_rj(state, 13); + jne_rj(state, 4); // 2 + cmp_reg32_reg32(state, rs1, rt1); // 2 + jb_rj(state, 7); // 2 + mov_reg32_imm32(state, rd, 0); // 5 + jmp_imm_short(state, 5); // 2 + mov_reg32_imm32(state, rd, 1); // 5 +#endif +} + +void gendadd(usf_state_t * state) +{ +#ifdef INTERPRET_DADD + gencallinterp(state, (unsigned int)state->current_instruction_table.DADD, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + add_reg32_reg32(state, rd1, rt1); + adc_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + add_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + adc_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void gendaddu(usf_state_t * state) +{ +#ifdef INTERPRET_DADDU + gencallinterp(state, (unsigned int)state->current_instruction_table.DADDU, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + add_reg32_reg32(state, rd1, rt1); + adc_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + add_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + adc_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void gendsub(usf_state_t * state) +{ +#ifdef INTERPRET_DSUB + gencallinterp(state, (unsigned int)state->current_instruction_table.DSUB, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + sub_reg32_reg32(state, rd1, rt1); + sbb_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + sub_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + sbb_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void gendsubu(usf_state_t * state) +{ +#ifdef INTERPRET_DSUBU + gencallinterp(state, (unsigned int)state->current_instruction_table.DSUBU, 0); +#else + int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); + int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(state, rd1, rs1); + mov_reg32_reg32(state, rd2, rs2); + sub_reg32_reg32(state, rd1, rt1); + sbb_reg32_reg32(state, rd2, rt2); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rs1); + sub_reg32_reg32(state, temp, rt1); + mov_reg32_reg32(state, rd1, temp); + mov_reg32_reg32(state, temp, rs2); + sbb_reg32_reg32(state, temp, rt2); + mov_reg32_reg32(state, rd2, temp); + } +#endif +} + +void genteq(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.TEQ, 0); +} + +void gendsll(usf_state_t * state) +{ +#ifdef INTERPRET_DSLL + gencallinterp(state, (unsigned int)state->current_instruction_table.DSLL, 0); +#else + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shld_reg32_reg32_imm8(state, rd2, rd1, state->dst->f.r.sa); + shl_reg32_imm8(state, rd1, state->dst->f.r.sa); + if (state->dst->f.r.sa & 0x20) + { + mov_reg32_reg32(state, rd2, rd1); + xor_reg32_reg32(state, rd1, rd1); + } +#endif +} + +void gendsrl(usf_state_t * state) +{ +#ifdef INTERPRET_DSRL + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRL, 0); +#else + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shrd_reg32_reg32_imm8(state, rd1, rd2, state->dst->f.r.sa); + shr_reg32_imm8(state, rd2, state->dst->f.r.sa); + if (state->dst->f.r.sa & 0x20) + { + mov_reg32_reg32(state, rd1, rd2); + xor_reg32_reg32(state, rd2, rd2); + } +#endif +} + +void gendsra(usf_state_t * state) +{ +#ifdef INTERPRET_DSRA + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRA, 0); +#else + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd1, rt1); + mov_reg32_reg32(state, rd2, rt2); + shrd_reg32_reg32_imm8(state, rd1, rd2, state->dst->f.r.sa); + sar_reg32_imm8(state, rd2, state->dst->f.r.sa); + if (state->dst->f.r.sa & 0x20) + { + mov_reg32_reg32(state, rd1, rd2); + sar_reg32_imm8(state, rd2, 31); + } +#endif +} + +void gendsll32(usf_state_t * state) +{ +#ifdef INTERPRET_DSLL32 + gencallinterp(state, (unsigned int)state->current_instruction_table.DSLL32, 0); +#else + int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd2, rt1); + shl_reg32_imm8(state, rd2, state->dst->f.r.sa); + xor_reg32_reg32(state, rd1, rd1); +#endif +} + +void gendsrl32(usf_state_t * state) +{ +#ifdef INTERPRET_DSRL32 + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRL32, 0); +#else + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); + int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd1, rt2); + shr_reg32_imm8(state, rd1, state->dst->f.r.sa); + xor_reg32_reg32(state, rd2, rd2); +#endif +} + +void gendsra32(usf_state_t * state) +{ +#ifdef INTERPRET_DSRA32 + gencallinterp(state, (unsigned int)state->current_instruction_table.DSRA32, 0); +#else + int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt2); + sar_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void genbreak(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.BREAK, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/gtlb.c b/Frameworks/lazyusf/lazyusf/r4300/x86/gtlb.c new file mode 100644 index 000000000..d6baa1839 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/gtlb.c @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gtlb.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" + +void gentlbwi(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.TLBWI, 0); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBWI)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void gentlbp(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.TLBP, 0); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBP)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void gentlbr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.TLBR, 0); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBR)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void generet(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.ERET, 1); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + genupdate_system(0); + mov_reg32_imm32(EAX, (unsigned int)(ERET)); + call_reg32(EAX); + mov_reg32_imm32(EAX, (unsigned int)(jump_code)); + jmp_reg32(EAX);*/ +} + +void gentlbwr(usf_state_t * state) +{ + gencallinterp(state, (unsigned int)state->current_instruction_table.TLBWR, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/interpret.h b/Frameworks/lazyusf/lazyusf/r4300/x86/interpret.h new file mode 100644 index 000000000..69f0fd633 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/interpret.h @@ -0,0 +1,239 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpret.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_INTERPRET_H +#define M64P_R4300_INTERPRET_H + +//#define INTERPRET_J +//#define INTERPRET_J_OUT +//#define INTERPRET_J_IDLE +//#define INTERPRET_JAL +//#define INTERPRET_JAL_OUT +//#define INTERPRET_JAL_IDLE +//#define INTERPRET_BEQ +//#define INTERPRET_BEQ_OUT +//#define INTERPRET_BEQ_IDLE +//#define INTERPRET_BNE +//#define INTERPRET_BNE_OUT +//#define INTERPRET_BNE_IDLE +//#define INTERPRET_BLEZ +//#define INTERPRET_BLEZ_OUT +//#define INTERPRET_BLEZ_IDLE +//#define INTERPRET_BGTZ +//#define INTERPRET_BGTZ_OUT +//#define INTERPRET_BGTZ_IDLE +//#define INTERPRET_ADDI +//#define INTERPRET_ADDIU +//#define INTERPRET_SLTI +//#define INTERPRET_SLTIU +//#define INTERPRET_ANDI +//#define INTERPRET_ORI +//#define INTERPRET_XORI +//#define INTERPRET_LUI +//#define INTERPRET_BEQL +//#define INTERPRET_BEQL_OUT +//#define INTERPRET_BEQL_IDLE +//#define INTERPRET_BNEL +//#define INTERPRET_BNEL_OUT +//#define INTERPRET_BNEL_IDLE +//#define INTERPRET_BLEZL +//#define INTERPRET_BLEZL_OUT +//#define INTERPRET_BLEZL_IDLE +//#define INTERPRET_BGTZL +//#define INTERPRET_BGTZL_OUT +//#define INTERPRET_BGTZL_IDLE +//#define INTERPRET_DADDI +//#define INTERPRET_DADDIU +//#define INTERPRET_LB +//#define INTERPRET_LH +//#define INTERPRET_LW +//#define INTERPRET_LBU +//#define INTERPRET_LHU +//#define INTERPRET_LWU +//#define INTERPRET_SB +//#define INTERPRET_SH +//#define INTERPRET_SW +//#define INTERPRET_LWC1 +//#define INTERPRET_LDC1 +//#define INTERPRET_LD +//#define INTERPRET_SWC1 +//#define INTERPRET_SDC1 +//#define INTERPRET_SD +//#define INTERPRET_SLL +//#define INTERPRET_SRL +//#define INTERPRET_SRA +//#define INTERPRET_SLLV +//#define INTERPRET_SRLV +//#define INTERPRET_SRAV +//#define INTERPRET_JR +//#define INTERPRET_JALR +//#define INTERPRET_SYSCALL +//#define INTERPRET_MFHI +//#define INTERPRET_MTHI +//#define INTERPRET_MFLO +//#define INTERPRET_MTLO +//#define INTERPRET_DSLLV +//#define INTERPRET_DSRLV +//#define INTERPRET_DSRAV +//#define INTERPRET_MULT +//#define INTERPRET_MULTU +//#define INTERPRET_DIV +//#define INTERPRET_DIVU +//#define INTERPRET_DMULTU +//#define INTERPRET_ADD +//#define INTERPRET_ADDU +//#define INTERPRET_SUB +//#define INTERPRET_SUBU +//#define INTERPRET_AND +//#define INTERPRET_OR +//#define INTERPRET_XOR +//#define INTERPRET_NOR +//#define INTERPRET_SLT +//#define INTERPRET_SLTU +//#define INTERPRET_DADD +//#define INTERPRET_DADDU +//#define INTERPRET_DSUB +//#define INTERPRET_DSUBU +//#define INTERPRET_DSLL +//#define INTERPRET_DSRL +//#define INTERPRET_DSRA +//#define INTERPRET_DSLL32 +//#define INTERPRET_DSRL32 +//#define INTERPRET_DSRA32 +//#define INTERPRET_BLTZ +//#define INTERPRET_BLTZ_OUT +//#define INTERPRET_BLTZ_IDLE +//#define INTERPRET_BGEZ +//#define INTERPRET_BGEZ_OUT +//#define INTERPRET_BGEZ_IDLE +//#define INTERPRET_BLTZL +//#define INTERPRET_BLTZL_OUT +//#define INTERPRET_BLTZL_IDLE +//#define INTERPRET_BGEZL +//#define INTERPRET_BGEZL_OUT +//#define INTERPRET_BGEZL_IDLE +//#define INTERPRET_BLTZAL +//#define INTERPRET_BLTZAL_OUT +//#define INTERPRET_BLTZAL_IDLE +//#define INTERPRET_BGEZAL +//#define INTERPRET_BGEZAL_OUT +//#define INTERPRET_BGEZAL_IDLE +//#define INTERPRET_BLTZALL +//#define INTERPRET_BLTZALL_OUT +//#define INTERPRET_BLTZALL_IDLE +//#define INTERPRET_BGEZALL +//#define INTERPRET_BGEZALL_OUT +//#define INTERPRET_BGEZALL_IDLE +//#define INTERPRET_BC1F +//#define INTERPRET_BC1F_OUT +//#define INTERPRET_BC1F_IDLE +//#define INTERPRET_BC1T +//#define INTERPRET_BC1T_OUT +//#define INTERPRET_BC1T_IDLE +//#define INTERPRET_BC1FL +//#define INTERPRET_BC1FL_OUT +//#define INTERPRET_BC1FL_IDLE +//#define INTERPRET_BC1TL +//#define INTERPRET_BC1TL_OUT +//#define INTERPRET_BC1TL_IDLE +//#define INTERPRET_MFC1 +//#define INTERPRET_DMFC1 +//#define INTERPRET_CFC1 +//#define INTERPRET_MTC1 +//#define INTERPRET_DMTC1 +//#define INTERPRET_CTC1 +//#define INTERPRET_ADD_D +//#define INTERPRET_SUB_D +//#define INTERPRET_MUL_D +//#define INTERPRET_DIV_D +//#define INTERPRET_SQRT_D +//#define INTERPRET_ABS_D +//#define INTERPRET_MOV_D +//#define INTERPRET_NEG_D +//#define INTERPRET_ROUND_L_D +//#define INTERPRET_TRUNC_L_D +//#define INTERPRET_CEIL_L_D +//#define INTERPRET_FLOOR_L_D +//#define INTERPRET_ROUND_W_D +//#define INTERPRET_TRUNC_W_D +//#define INTERPRET_CEIL_W_D +//#define INTERPRET_FLOOR_W_D +//#define INTERPRET_CVT_S_D +//#define INTERPRET_CVT_W_D +//#define INTERPRET_CVT_L_D +//#define INTERPRET_C_F_D +//#define INTERPRET_C_UN_D +//#define INTERPRET_C_EQ_D +//#define INTERPRET_C_UEQ_D +//#define INTERPRET_C_OLT_D +//#define INTERPRET_C_ULT_D +//#define INTERPRET_C_OLE_D +//#define INTERPRET_C_ULE_D +//#define INTERPRET_C_SF_D +//#define INTERPRET_C_NGLE_D +//#define INTERPRET_C_SEQ_D +//#define INTERPRET_C_NGL_D +//#define INTERPRET_C_LT_D +//#define INTERPRET_C_NGE_D +//#define INTERPRET_C_LE_D +//#define INTERPRET_C_NGT_D +//#define INTERPRET_CVT_S_L +//#define INTERPRET_CVT_D_L +//#define INTERPRET_CVT_S_W +//#define INTERPRET_CVT_D_W +//#define INTERPRET_ADD_S +//#define INTERPRET_SUB_S +//#define INTERPRET_MUL_S +//#define INTERPRET_DIV_S +//#define INTERPRET_SQRT_S +//#define INTERPRET_ABS_S +//#define INTERPRET_MOV_S +//#define INTERPRET_NEG_S +//#define INTERPRET_ROUND_L_S +//#define INTERPRET_TRUNC_L_S +//#define INTERPRET_CEIL_L_S +//#define INTERPRET_FLOOR_L_S +//#define INTERPRET_ROUND_W_S +//#define INTERPRET_TRUNC_W_S +//#define INTERPRET_CEIL_W_S +//#define INTERPRET_FLOOR_W_S +//#define INTERPRET_CVT_D_S +//#define INTERPRET_CVT_W_S +//#define INTERPRET_CVT_L_S +//#define INTERPRET_C_F_S +//#define INTERPRET_C_UN_S +//#define INTERPRET_C_EQ_S +//#define INTERPRET_C_UEQ_S +//#define INTERPRET_C_OLT_S +//#define INTERPRET_C_ULT_S +//#define INTERPRET_C_OLE_S +//#define INTERPRET_C_ULE_S +//#define INTERPRET_C_SF_S +//#define INTERPRET_C_NGLE_S +//#define INTERPRET_C_SEQ_S +//#define INTERPRET_C_NGL_S +//#define INTERPRET_C_LT_S +//#define INTERPRET_C_NGE_S +//#define INTERPRET_C_LE_S +//#define INTERPRET_C_NGT_S + +#endif /* M64P_R4300_INTERPRET_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.c b/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.c new file mode 100644 index 000000000..95a47fe0b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.c @@ -0,0 +1,843 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - regcache.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "regcache.h" + +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/recomph.h" + +void init_cache(usf_state_t * state, precomp_instr* start) +{ + int i; + for (i=0; i<8; i++) + { + state->last_access[i] = NULL; + state->free_since[i] = start; + } + state->r0 = (unsigned int*)state->reg; +} + +void free_all_registers(usf_state_t * state) +{ + int i; + for (i=0; i<8; i++) + { + if (state->last_access[i]) free_register(state, i); + else + { + while (state->free_since[i] <= state->dst) + { + state->free_since[i]->reg_cache_infos.needed_registers[i] = NULL; + state->free_since[i]++; + } + } + } +} + +// this function frees a specific X86 GPR +void free_register(usf_state_t * state, int reg) +{ + precomp_instr *last; + + if (state->last_access[reg] != NULL && + state->r64[reg] != -1 && (int)state->reg_content[reg] != (int)state->reg_content[state->r64[reg]]-4) + { + free_register(state, state->r64[reg]); + return; + } + + if (state->last_access[reg] != NULL) last = state->last_access[reg]+1; + else last = state->free_since[reg]; + + while (last <= state->dst) + { + if (state->last_access[reg] != NULL && state->dirty[reg]) + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + else + last->reg_cache_infos.needed_registers[reg] = NULL; + + if (state->last_access[reg] != NULL && state->r64[reg] != -1) + { + if (state->dirty[state->r64[reg]]) + last->reg_cache_infos.needed_registers[state->r64[reg]] = state->reg_content[state->r64[reg]]; + else + last->reg_cache_infos.needed_registers[state->r64[reg]] = NULL; + } + + last++; + } + if (state->last_access[reg] == NULL) + { + state->free_since[reg] = state->dst+1; + return; + } + + if (state->dirty[reg]) + { + mov_m32_reg32(state, state->reg_content[reg], reg); + if (state->r64[reg] == -1) + { + sar_reg32_imm8(state, reg, 31); + mov_m32_reg32(state, (unsigned int*)state->reg_content[reg]+1, reg); + } + else mov_m32_reg32(state, state->reg_content[state->r64[reg]], state->r64[reg]); + } + state->last_access[reg] = NULL; + state->free_since[reg] = state->dst+1; + if (state->r64[reg] != -1) + { + state->last_access[state->r64[reg]] = NULL; + state->free_since[state->r64[reg]] = state->dst+1; + } +} + +int lru_register(usf_state_t * state) +{ + unsigned int oldest_access = 0xFFFFFFFF; + int i, reg = 0; + for (i=0; i<8; i++) + { + if (i != ESP && i != ESI && (unsigned int)state->last_access[i] < oldest_access) + { + oldest_access = (int)state->last_access[i]; + reg = i; + } + } + if (oldest_access == 0xFFFFFFFF) + { + int i = rand(); + } + return reg; +} + +int lru_register_exc1(usf_state_t * state, int exc1) +{ + unsigned int oldest_access = 0xFFFFFFFF; + int i, reg = 0; + for (i=0; i<8; i++) + { + if (i != ESP && i != ESI && i != exc1 && (unsigned int)state->last_access[i] < oldest_access) + { + oldest_access = (int)state->last_access[i]; + reg = i; + } + } + if (oldest_access == 0xFFFFFFFF) + { + int i = rand(); + } + return reg; +} + +// this function finds a register to put the data contained in addr, +// if there was another value before it's cleanly removed of the +// register cache. After that, the register number is returned. +// If data are already cached, the function only returns the register number +int allocate_register(usf_state_t * state, unsigned int *addr) +{ + unsigned int oldest_access = 0xFFFFFFFF; + int reg = 0, i; + + // is it already cached ? + if (addr != NULL) + { + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + if (state->r64[i] != -1) + { + last = state->last_access[state->r64[i]]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[i]] = state->reg_content[state->r64[i]]; + last++; + } + state->last_access[state->r64[i]] = state->dst; + } + + return i; + } + } + } + + // if it's not cached, we take the least recently used register + for (i=0; i<8; i++) + { + if (i != ESP && i != ESI && (unsigned int)state->last_access[i] < oldest_access) + { + oldest_access = (int)state->last_access[i]; + reg = i; + } + } + + if (oldest_access == 0xFFFFFFFF) + { + int i = rand(); + } + if (state->last_access[reg]) free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 0; + state->r64[reg] = -1; + + if (addr != NULL) + { + if (addr == state->r0 || addr == state->r0+1) + xor_reg32_reg32(state, reg, reg); + else + mov_reg32_m32(state, reg, addr); + } + + return reg; +} + +// this function is similar to allocate_register except it loads +// a 64 bits value, and return the register number of the LSB part +int allocate_64_register1(usf_state_t * state, unsigned int *addr) +{ + int reg1, reg2, i; + + // is it already cached as a 32 bits value ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + if (state->r64[i] == -1) + { + allocate_register(state, addr); + reg2 = allocate_register(state, state->dirty[i] ? NULL : addr+1); + state->r64[i] = reg2; + state->r64[reg2] = i; + + if (state->dirty[i]) + { + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + mov_reg32_reg32(state, reg2, i); + sar_reg32_imm8(state, reg2, 31); + } + + return i; + } + } + } + + reg1 = allocate_register(state, addr); + reg2 = allocate_register(state, addr+1); + state->r64[reg1] = reg2; + state->r64[reg2] = reg1; + + return reg1; +} + +// this function is similar to allocate_register except it loads +// a 64 bits value, and return the register number of the MSB part +int allocate_64_register2(usf_state_t * state, unsigned int *addr) +{ + int reg1, reg2, i; + + // is it already cached as a 32 bits value ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + if (state->r64[i] == -1) + { + allocate_register(state, addr); + reg2 = allocate_register(state, state->dirty[i] ? NULL : addr+1); + state->r64[i] = reg2; + state->r64[reg2] = i; + + if (state->dirty[i]) + { + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + mov_reg32_reg32(state, reg2, i); + sar_reg32_imm8(state, reg2, 31); + } + + return reg2; + } + } + } + + reg1 = allocate_register(state, addr); + reg2 = allocate_register(state, addr+1); + state->r64[reg1] = reg2; + state->r64[reg2] = reg1; + + return reg2; +} + +// this function checks if the data located at addr are cached in a register +// and then, it returns 1 if it's a 64 bit value +// 0 if it's a 32 bit value +// -1 if it's not cached +int is64(usf_state_t * state, unsigned int *addr) +{ + int i; + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + if (state->r64[i] == -1) return 0; + return 1; + } + } + return -1; +} + +int allocate_register_w(usf_state_t * state, unsigned int *addr) +{ + unsigned int oldest_access = 0xFFFFFFFF; + int reg = 0, i; + + // is it already cached ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = NULL; + last++; + } + state->last_access[i] = state->dst; + state->dirty[i] = 1; + if (state->r64[i] != -1) + { + last = state->last_access[state->r64[i]]+1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[i]] = NULL; + last++; + } + state->free_since[state->r64[i]] = state->dst+1; + state->last_access[state->r64[i]] = NULL; + state->r64[i] = -1; + } + + return i; + } + } + + // if it's not cached, we take the least recently used register + for (i=0; i<8; i++) + { + if (i != ESP && i != ESI && (unsigned int)state->last_access[i] < oldest_access) + { + oldest_access = (int)state->last_access[i]; + reg = i; + } + } + + if (oldest_access == 0xFFFFFFFF) + { + int i = rand(); + } + + if (state->last_access[reg]) free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 1; + state->r64[reg] = -1; + + return reg; +} + +int allocate_64_register1_w(usf_state_t * state, unsigned int *addr) +{ + int reg1, reg2, i; + + // is it already cached as a 32 bits value ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + if (state->r64[i] == -1) + { + allocate_register_w(state, addr); + reg2 = lru_register(state); + if (state->last_access[reg2]) free_register(state, reg2); + else + { + while (state->free_since[reg2] <= state->dst) + { + state->free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; + state->free_since[reg2]++; + } + } + state->r64[i] = reg2; + state->r64[reg2] = i; + state->last_access[reg2] = state->dst; + + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + mov_reg32_reg32(state, reg2, i); + sar_reg32_imm8(state, reg2, 31); + + return i; + } + else + { + state->last_access[i] = state->dst; + state->last_access[state->r64[i]] = state->dst; + state->dirty[i] = state->dirty[state->r64[i]] = 1; + return i; + } + } + } + + reg1 = allocate_register_w(state, addr); + reg2 = lru_register(state); + if (state->last_access[reg2]) free_register(state, reg2); + else + { + while (state->free_since[reg2] <= state->dst) + { + state->free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; + state->free_since[reg2]++; + } + } + state->r64[reg1] = reg2; + state->r64[reg2] = reg1; + state->last_access[reg2] = state->dst; + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + + return reg1; +} + +int allocate_64_register2_w(usf_state_t * state, unsigned int *addr) +{ + int reg1, reg2, i; + + // is it already cached as a 32 bits value ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + if (state->r64[i] == -1) + { + allocate_register_w(state, addr); + reg2 = lru_register(state); + if (state->last_access[reg2]) free_register(state, reg2); + else + { + while (state->free_since[reg2] <= state->dst) + { + state->free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; + state->free_since[reg2]++; + } + } + state->r64[i] = reg2; + state->r64[reg2] = i; + state->last_access[reg2] = state->dst; + + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + mov_reg32_reg32(state, reg2, i); + sar_reg32_imm8(state, reg2, 31); + + return reg2; + } + else + { + state->last_access[i] = state->dst; + state->last_access[state->r64[i]] = state->dst; + state->dirty[i] = state->dirty[state->r64[i]] = 1; + return state->r64[i]; + } + } + } + + reg1 = allocate_register_w(state, addr); + reg2 = lru_register(state); + if (state->last_access[reg2]) free_register(state, reg2); + else + { + while (state->free_since[reg2] <= state->dst) + { + state->free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; + state->free_since[reg2]++; + } + } + state->r64[reg1] = reg2; + state->r64[reg2] = reg1; + state->last_access[reg2] = state->dst; + state->reg_content[reg2] = addr+1; + state->dirty[reg2] = 1; + + return reg2; +} + +void set_register_state(usf_state_t * state, int reg, unsigned int *addr, int d) +{ + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->r64[reg] = -1; + state->dirty[reg] = d; +} + +void set_64_register_state(usf_state_t * state, int reg1, int reg2, unsigned int *addr, int d) +{ + state->last_access[reg1] = state->dst; + state->last_access[reg2] = state->dst; + state->reg_content[reg1] = addr; + state->reg_content[reg2] = addr+1; + state->r64[reg1] = reg2; + state->r64[reg2] = reg1; + state->dirty[reg1] = d; + state->dirty[reg2] = d; +} + +void force_32(usf_state_t * state, int reg) +{ + if (state->r64[reg] != -1) + { + precomp_instr *last = state->last_access[reg]+1; + + while (last <= state->dst) + { + if (state->dirty[reg]) + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + else + last->reg_cache_infos.needed_registers[reg] = NULL; + + if (state->dirty[state->r64[reg]]) + last->reg_cache_infos.needed_registers[state->r64[reg]] = state->reg_content[state->r64[reg]]; + else + last->reg_cache_infos.needed_registers[state->r64[reg]] = NULL; + + last++; + } + + if (state->dirty[reg]) + { + mov_m32_reg32(state, state->reg_content[reg], reg); + mov_m32_reg32(state, state->reg_content[state->r64[reg]], state->r64[reg]); + state->dirty[reg] = 0; + } + state->last_access[state->r64[reg]] = NULL; + state->free_since[state->r64[reg]] = state->dst+1; + state->r64[reg] = -1; + } +} + +void allocate_register_manually(usf_state_t * state, int reg, unsigned int *addr) +{ + int i; + + if (state->last_access[reg] != NULL && state->reg_content[reg] == addr) + { + precomp_instr *last = state->last_access[reg]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + last++; + } + state->last_access[reg] = state->dst; + if (state->r64[reg] != -1) + { + last = state->last_access[state->r64[reg]]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[reg]] = state->reg_content[state->r64[reg]]; + last++; + } + state->last_access[state->r64[reg]] = state->dst; + } + return; + } + + if (state->last_access[reg]) free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + // is it already cached ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + if (state->r64[i] != -1) + { + last = state->last_access[state->r64[i]]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[i]] = state->reg_content[state->r64[i]]; + last++; + } + state->last_access[state->r64[i]] = state->dst; + } + + mov_reg32_reg32(state, reg, i); + state->last_access[reg] = state->dst; + state->r64[reg] = state->r64[i]; + if (state->r64[reg] != -1) state->r64[state->r64[reg]] = reg; + state->dirty[reg] = state->dirty[i]; + state->reg_content[reg] = state->reg_content[i]; + state->free_since[i] = state->dst+1; + state->last_access[i] = NULL; + + return; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 0; + state->r64[reg] = -1; + + if (addr != NULL) + { + if (addr == state->r0 || addr == state->r0+1) + xor_reg32_reg32(state, reg, reg); + else + mov_reg32_m32(state, reg, addr); + } +} + +void allocate_register_manually_w(usf_state_t * state, int reg, unsigned int *addr, int load) +{ + int i; + + if (state->last_access[reg] != NULL && state->reg_content[reg] == addr) + { + precomp_instr *last = state->last_access[reg]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + last++; + } + state->last_access[reg] = state->dst; + + if (state->r64[reg] != -1) + { + last = state->last_access[state->r64[reg]]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[reg]] = state->reg_content[state->r64[reg]]; + last++; + } + state->last_access[state->r64[reg]] = NULL; + state->free_since[state->r64[reg]] = state->dst+1; + state->r64[reg] = -1; + } + state->dirty[reg] = 1; + return; + } + + if (state->last_access[reg]) free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + // is it already cached ? + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + if (state->r64[i] != -1) + { + last = state->last_access[state->r64[i]]+1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[state->r64[i]] = NULL; + last++; + } + state->free_since[state->r64[i]] = state->dst+1; + state->last_access[state->r64[i]] = NULL; + state->r64[i] = -1; + } + + if (load) + mov_reg32_reg32(state, reg, i); + state->last_access[reg] = state->dst; + state->dirty[reg] = 1; + state->r64[reg] = -1; + state->reg_content[reg] = state->reg_content[i]; + state->free_since[i] = state->dst+1; + state->last_access[i] = NULL; + + return; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 1; + state->r64[reg] = -1; + + if (addr != NULL && load) + { + if (addr == state->r0 || addr == state->r0+1) + xor_reg32_reg32(state, reg, reg); + else + mov_reg32_m32(state, reg, addr); + } +} + +// 0x81 0xEC 0x4 0x0 0x0 0x0 sub esp, 4 +// 0xA1 0xXXXXXXXX mov eax, XXXXXXXX (&code start) +// 0x05 0xXXXXXXXX add eax, XXXXXXXX (local_addr) +// 0x89 0x04 0x24 mov [esp], eax +// 0x8B (reg<<3)|5 0xXXXXXXXX mov eax, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov ebx, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov ecx, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov edx, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov ebp, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov esi, [XXXXXXXX] +// 0x8B (reg<<3)|5 0xXXXXXXXX mov edi, [XXXXXXXX] +// 0xC3 ret +// total : 62 bytes +static void build_wrapper(usf_state_t * state, precomp_instr *instr, unsigned char* code, precomp_block* block) +{ + int i; + int j=0; + + code[j++] = 0x81; + code[j++] = 0xEC; + code[j++] = 0x04; + code[j++] = 0x00; + code[j++] = 0x00; + code[j++] = 0x00; + + code[j++] = 0xA1; + *((unsigned int*)&code[j]) = (unsigned int)(&block->code); + j+=4; + + code[j++] = 0x05; + *((unsigned int*)&code[j]) = (unsigned int)instr->local_addr; + j+=4; + + code[j++] = 0x89; + code[j++] = 0x04; + code[j++] = 0x24; + + for (i=0; i<8; i++) + { + if (instr->reg_cache_infos.needed_registers[i] != NULL) + { + code[j++] = 0x8B; + code[j++] = (i << 3) | 5; + *((unsigned int*)&code[j]) = + (unsigned int)instr->reg_cache_infos.needed_registers[i]; + j+=4; + } + } + + code[j++] = 0xC3; +} + +void build_wrappers(usf_state_t * state, precomp_instr *instr, int start, int end, precomp_block* block) +{ + int i, reg;; + for (i=start; idst->local_addr = state->code_length; + for(i=0; i<8; i++) state->dst->reg_cache_infos.needed_registers[i] = NULL; +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.h b/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.h new file mode 100644 index 000000000..877c709fa --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/regcache.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - regcache.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_REGCACHE_H +#define M64P_R4300_REGCACHE_H + +#include "r4300/recomp.h" + +void init_cache(usf_state_t *, precomp_instr* start); +void free_all_registers(usf_state_t *); +void free_register(usf_state_t *, int reg); +int allocate_register(usf_state_t *, unsigned int *addr); +int allocate_64_register1(usf_state_t *, unsigned int *addr); +int allocate_64_register2(usf_state_t *, unsigned int *addr); +int is64(usf_state_t *, unsigned int *addr); +void build_wrappers(usf_state_t *, precomp_instr*, int, int, precomp_block*); +int lru_register(usf_state_t *); +int allocate_register_w(usf_state_t *, unsigned int *addr); +int allocate_64_register1_w(usf_state_t *, unsigned int *addr); +int allocate_64_register2_w(usf_state_t *, unsigned int *addr); +void set_register_state(usf_state_t *, int reg, unsigned int *addr, int dirty); +void set_64_register_state(usf_state_t *, int reg1, int reg2, unsigned int *addr, int dirty); +void allocate_register_manually(usf_state_t *, int reg, unsigned int *addr); +void allocate_register_manually_w(usf_state_t *, int reg, unsigned int *addr, int load); +void force_32(usf_state_t *, int reg); +int lru_register_exc1(usf_state_t *, int exc1); +void simplify_access(usf_state_t *); + +#endif /* M64P_R4300_REGCACHE_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86/rjump.c b/Frameworks/lazyusf/lazyusf/r4300/x86/rjump.c new file mode 100644 index 000000000..a5e315408 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86/rjump.c @@ -0,0 +1,164 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rjump.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "r4300/cached_interp.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/macros.h" +#include "r4300/ops.h" +#include "r4300/recomph.h" + +void dyna_jump(usf_state_t * state) +{ + if (state->stop == 1) + { + dyna_stop(state); + return; + } + + if (state->PC->reg_cache_infos.need_map) + *state->return_address = (unsigned long) (state->PC->reg_cache_infos.jump_wrapper); + else + *state->return_address = (unsigned long) (state->actual->code + state->PC->local_addr); +} + +#if defined(WIN32) && !defined(__GNUC__) /* this warning disable only works if placed outside of the scope of a function */ +#pragma warning(disable:4731) /* frame pointer register 'ebp' modified by inline assembly code */ +#endif + +void dyna_start(usf_state_t * state, void *code) +{ + /* save the base and stack pointers */ + /* make a call and a pop to retrieve the instruction pointer and save it too */ + /* then call the code(), which should theoretically never return. */ + /* When dyna_stop() sets the *return_address to the saved EIP, the emulator thread will come back here. */ + /* It will jump to label 2, restore the base and stack pointers, and exit this function */ +#if defined(WIN32) && !defined(__GNUC__) + __asm + { + push ebp + push ebx + push esi + push edi + mov ebx, code + mov esi, state + mov [esi].save_esp, esp + call point1 + jmp point2 + point1: + pop eax + mov [esi].save_eip, eax + + sub esp, 0x10 + and esp, 0xfffffff0 + mov [esi].return_address, esp + sub [esi].return_address, 4 + + call ebx + + point2: + mov esp, [esi].save_esp + pop edi + pop esi + pop ebx + pop ebp + } +#elif defined(__GNUC__) && defined(__i386__) + #if defined(__PIC__) + /* for -fPIC (shared libraries) */ + #ifndef __GNUC_PREREQ + # if defined __GNUC__ && defined __GNUC_MINOR__ + # define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) + # else + # define __GNUC_PREREQ(maj, min) 0 + # endif + #endif + + #if __GNUC_PREREQ (4, 7) + # define GET_PC_THUNK_STR(reg) "__x86.get_pc_thunk." #reg + #else + # define GET_PC_THUNK_STR(reg) "__i686.get_pc_thunk." #reg + #endif + #define STORE_EBX + #define LOAD_EBX "call " GET_PC_THUNK_STR(bx) " \n" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx \n" + #else + /* for non-PIC binaries */ + #define STORE_EBX "pushl %%ebx \n" + #define LOAD_EBX "popl %%ebx \n" + #endif + + asm volatile + (" pushl %%ebp \n" + STORE_EBX + " pushl %%esi \n" + " pushl %%edi \n" + " movl %[state], %%esi \n" + " movl %%esp, %c[save_esp](%%esi) \n" + " call 1f \n" + " jmp 2f \n" + "1: \n" + " popl %%eax \n" + " movl %%eax, %c[save_eip](%%esi) \n" + + " subl $16, %%esp \n" /* save 16 bytes of padding just in case */ + " andl $-16, %%esp \n" /* align stack on 16-byte boundary for OSX */ + " movl %%esp, %c[return_address](%%esi) \n" + " subl $4, %c[return_address](%%esi) \n" + + " call *%[codeptr] \n" + "2: \n" + " movl %c[save_esp](%%esi), %%esp \n" + " popl %%edi \n" + " popl %%esi \n" + LOAD_EBX + " popl %%ebp \n" + : + : [save_esp]"i"(offsetof(usf_state_t,save_esp)), [save_eip]"i"(offsetof(usf_state_t,save_eip)), [return_address]"i"(offsetof(usf_state_t,return_address)), [codeptr]"r"(code), [state]"r"(state) + : "eax", "ecx", "edx", "memory" + ); +#endif + + /* clear the registers so we don't return here a second time; that would be a bug */ + /* this is also necessary to prevent compiler from optimizing out the static variables */ + state->save_esp=0; + state->save_eip=0; +} + +void dyna_stop(usf_state_t * state) +{ + if (state->save_eip == 0) + DebugMessage(state, M64MSG_WARNING, "instruction pointer is 0 at dyna_stop()"); + else + { + *state->return_address = (unsigned long) state->save_eip; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.c new file mode 100644 index 000000000..26d388a5d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.c @@ -0,0 +1,201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "osal/preproc.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" + +/* Placeholder for RIP-relative offsets is maxmimum 32-bit signed value. + * So, if recompiled code is run without running passe2() first, it will + * cause an exception. +*/ +#define REL_PLACEHOLDER 0x7fffffff + +/* Static Functions */ + +void add_jump(usf_state_t * state, unsigned int pc_addr, unsigned int mi_addr, unsigned int absolute64) +{ + if (state->jumps_number == state->max_jumps_number) + { + state->max_jumps_number += 512; + state->jumps_table = realloc(state->jumps_table, state->max_jumps_number*sizeof(jump_table)); + } + state->jumps_table[state->jumps_number].pc_addr = pc_addr; + state->jumps_table[state->jumps_number].mi_addr = mi_addr; + state->jumps_table[state->jumps_number].absolute64 = absolute64; + state->jumps_number++; +} + +/* Global Functions */ + +void init_assembler(usf_state_t * state, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number) +{ + if (block_jumps_table) + { + state->jumps_table = block_jumps_table; + state->jumps_number = block_jumps_number; + if (state->jumps_number <= 512) + state->max_jumps_number = 512; + else + state->max_jumps_number = (state->jumps_number + 511) & 0xfffffe00; + } + else + { + state->jumps_table = malloc(512*sizeof(jump_table)); + state->jumps_number = 0; + state->max_jumps_number = 512; + } + + if (block_riprel_table) + { + state->riprel_table = block_riprel_table; + state->riprel_number = block_riprel_number; + if (state->riprel_number <= 512) + state->max_riprel_number = 512; + else + state->max_riprel_number = (state->riprel_number + 511) & 0xfffffe00; + } + else + { + state->riprel_table = malloc(512 * sizeof(riprelative_table)); + state->riprel_number = 0; + state->max_riprel_number = 512; + } +} + +void free_assembler(usf_state_t * state, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number) +{ + *block_jumps_table = state->jumps_table; + *block_jumps_number = state->jumps_number; + *block_riprel_table = state->riprel_table; + *block_riprel_number = state->riprel_number; +} + +void passe2(usf_state_t * state, precomp_instr *dest, int start, int end, precomp_block *block) +{ + unsigned int i; + + build_wrappers(state, dest, start, end, block); + + /* First, fix up all the jumps. This involves a table lookup to find the offset into the block of x86_64 code for + * for start of a recompiled r4300i instruction corresponding to the given jump destination address in the N64 + * address space. Next, the relative offset between this destination and the location of the jump instruction is + * computed and stored in memory, so that the jump will branch to the right place in the recompiled code. + */ + for (i = 0; i < state->jumps_number; i++) + { + precomp_instr *jump_instr = dest + ((state->jumps_table[i].mi_addr - dest[0].addr) / 4); + unsigned int jmp_offset_loc = state->jumps_table[i].pc_addr; + unsigned char *addr_dest = NULL; + /* calculate the destination address to jump to */ + if (jump_instr->reg_cache_infos.need_map) + { + addr_dest = jump_instr->reg_cache_infos.jump_wrapper; + } + else + { + addr_dest = block->code + jump_instr->local_addr; + } + /* write either a 32-bit IP-relative offset or a 64-bit absolute address */ + if (state->jumps_table[i].absolute64) + { + *((unsigned long long *) (block->code + jmp_offset_loc)) = (unsigned long long) addr_dest; + } + else + { + long jump_rel_offset = (long) (addr_dest - (block->code + jmp_offset_loc + 4)); + *((int *) (block->code + jmp_offset_loc)) = (int) jump_rel_offset; + if (jump_rel_offset >= 0x7fffffffLL || jump_rel_offset < -0x80000000LL) + { + DebugMessage(state, M64MSG_ERROR, "assembler pass2 error: offset too big for relative jump from %p to %p", + (block->code + jmp_offset_loc + 4), addr_dest); + OSAL_BREAKPOINT_INTERRUPT + } + } + } + + /* Next, fix up all of the RIP-relative memory accesses. This is unique to the x86_64 architecture, because + * the 32-bit absolute displacement addressing mode is not available (and there's no 64-bit absolute displacement + * mode either). + */ + for (i = 0; i < state->riprel_number; i++) + { + unsigned char *rel_offset_ptr = block->code + state->riprel_table[i].pc_addr; + long rip_rel_offset = (long) (state->riprel_table[i].global_dst - (rel_offset_ptr + 4 + state->riprel_table[i].extra_bytes)); + if (rip_rel_offset >= 0x7fffffffLL || rip_rel_offset < -0x80000000LL) + { + DebugMessage(state, M64MSG_ERROR, "assembler pass2 error: offset too big between mem target: %p and code position: %p", + state->riprel_table[i].global_dst, rel_offset_ptr); + OSAL_BREAKPOINT_INTERRUPT + } + *((int *) rel_offset_ptr) = (int) rip_rel_offset; + } + +} + +void jump_start_rel8(usf_state_t * state) +{ + state->g_jump_start8 = state->code_length; +} + +void jump_start_rel32(usf_state_t * state) +{ + state->g_jump_start32 = state->code_length; +} + +void jump_end_rel8(usf_state_t * state) +{ + unsigned int jump_end = state->code_length; + int jump_vec = jump_end - state->g_jump_start8; + + if (jump_vec > 127 || jump_vec < -128) + { + DebugMessage(state, M64MSG_ERROR, "Error: 8-bit relative jump too long! From %x to %x", state->g_jump_start8, jump_end); + OSAL_BREAKPOINT_INTERRUPT + } + + state->code_length = state->g_jump_start8 - 1; + put8(state, jump_vec); + state->code_length = jump_end; +} + +void jump_end_rel32(usf_state_t * state) +{ + unsigned int jump_end = state->code_length; + int jump_vec = jump_end - state->g_jump_start32; + + state->code_length = state->g_jump_start32 - 4; + put32(state, jump_vec); + state->code_length = jump_end; +} diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.h b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.h new file mode 100644 index 000000000..074757974 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble.h @@ -0,0 +1,1197 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_ASSEMBLE_H +#define M64P_R4300_ASSEMBLE_H + +#include "r4300/recomph.h" +#include "api/callbacks.h" +#include "osal/preproc.h" + +#include + +#define RAX 0 +#define RCX 1 +#define RDX 2 +#define RBX 3 +#define RSP 4 +#define RBP 5 +#define RSI 6 +#define RDI 7 + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 1 +#define DX 2 +#define BX 3 +#define SP 4 +#define BP 5 +#define SI 6 +#define DI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 +#define AH 4 +#define CH 5 +#define DH 6 +#define BH 7 + +#ifdef _WIN32 +#define RP0 RCX +#define RP1 RDX +#define RP2 8 +#define RP3 9 +#else +#define RP0 RDI +#define RP1 RSI +#define RP2 RDX +#define RP3 RCX +#endif + +void jump_start_rel8(usf_state_t *); +void jump_end_rel8(usf_state_t *); +void jump_start_rel32(usf_state_t *); +void jump_end_rel32(usf_state_t *); +void add_jump(usf_state_t *, unsigned int pc_addr, unsigned int mi_addr, unsigned int absolute64); + +static inline void put8(usf_state_t * state, unsigned char octet) +{ + (*state->inst_pointer)[state->code_length] = octet; + state->code_length++; + if (state->code_length == state->max_code_length) + { + *state->inst_pointer = realloc_exec(state, *state->inst_pointer, state->max_code_length, state->max_code_length+8192); + state->max_code_length += 8192; + } +} + +static inline void put32(usf_state_t * state, unsigned int dword) +{ + if ((state->code_length + 4) >= state->max_code_length) + { + *state->inst_pointer = realloc_exec(state, *state->inst_pointer, state->max_code_length, state->max_code_length+8192); + state->max_code_length += 8192; + } + *((unsigned int *) (*state->inst_pointer + state->code_length)) = dword; + state->code_length += 4; +} + +static inline void put64(usf_state_t * state, unsigned long long qword) +{ + if ((state->code_length + 8) >= state->max_code_length) + { + *state->inst_pointer = realloc_exec(state, *state->inst_pointer, state->max_code_length, state->max_code_length+8192); + state->max_code_length += 8192; + } + *((unsigned long long *) (*state->inst_pointer + state->code_length)) = qword; + state->code_length += 8; +} + +static inline int rel_r15_offset(usf_state_t * state, void *dest, const char *op_name) +{ + /* calculate the destination pointer's offset from the base of the r4300 registers */ + long long rel_offset = (long long) ((unsigned char *) dest - (unsigned char *) state); + + if (llabs(rel_offset) > 0x7fffffff) + { + DebugMessage(state, M64MSG_ERROR, "Error: destination %p more than 2GB away from r15 base %p in %s()", dest, state, op_name); + OSAL_BREAKPOINT_INTERRUPT; + } + + return (int) rel_offset; +} + +static inline void mov_memoffs32_eax(usf_state_t * state, unsigned int *memoffs32) +{ + put8(state, 0xA3); + put64(state, (unsigned long long) memoffs32); +} + +static inline void mov_rax_memoffs64(usf_state_t * state, unsigned long long *memoffs64) +{ + put8(state, 0x48); + put8(state, 0xA1); + put64(state, (unsigned long long) memoffs64); +} + +static inline void mov_memoffs64_rax(usf_state_t * state, unsigned long long *memoffs64) +{ + put8(state, 0x48); + put8(state, 0xA3); + put64(state, (unsigned long long) memoffs64); +} + +static inline void mov_m8rel_xreg8(usf_state_t * state, unsigned char *m8, int xreg8) +{ + int offset = rel_r15_offset(state, m8, "mov_m8rel_xreg8"); + + put8(state, 0x41 | ((xreg8 & 8) >> 1)); + put8(state, 0x88); + put8(state, 0x87 | ((xreg8 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_xreg16_m16rel(usf_state_t * state, int xreg16, unsigned short *m16) +{ + int offset = rel_r15_offset(state, m16, "mov_xreg16_m16rel"); + + put8(state, 0x66); + put8(state, 0x41 | ((xreg16 & 8) >> 1)); + put8(state, 0x8B); + put8(state, 0x87 | ((xreg16 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_m16rel_xreg16(usf_state_t * state, unsigned short *m16, int xreg16) +{ + int offset = rel_r15_offset(state, m16, "mov_m16rel_xreg16"); + + put8(state, 0x66); + put8(state, 0x41 | ((xreg16 & 8) >> 1)); + put8(state, 0x89); + put8(state, 0x87 | ((xreg16 & 7) << 3)); + put32(state, offset); +} + +static inline void cmp_xreg32_m32rel(usf_state_t * state, int xreg32, unsigned int *m32) +{ + int offset = rel_r15_offset(state, m32, "cmp_xreg32_m32rel"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x3B); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void cmp_xreg64_m64rel(usf_state_t * state, int xreg64, unsigned long long *m64) +{ + int offset = rel_r15_offset(state, m64, "cmp_xreg64_m64rel"); + + put8(state, 0x49 | ((xreg64 & 8) >> 1)); + put8(state, 0x3B); + put8(state, 0x87 | ((xreg64 & 7) << 3)); + put32(state, offset); +} + +static inline void cmp_reg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x39); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static inline void cmp_reg64_reg64(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x48); + put8(state, 0x39); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static inline void cmp_reg32_imm8(usf_state_t * state, int reg32, unsigned char imm8) +{ + put8(state, 0x83); + put8(state, 0xF8 + reg32); + put8(state, imm8); +} + +static inline void cmp_reg64_imm8(usf_state_t * state, int reg64, unsigned char imm8) +{ + put8(state, 0x48); + put8(state, 0x83); + put8(state, 0xF8 + reg64); + put8(state, imm8); +} + +static inline void cmp_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xF8 + reg32); + put32(state, imm32); +} + +static inline void cmp_reg64_imm32(usf_state_t * state, int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xF8 + reg64); + put32(state, imm32); +} + +static inline void cmp_preg64preg64_imm8(usf_state_t * state, int reg1, int reg2, unsigned char imm8) +{ + put8(state, 0x80); + put8(state, 0x3C); + put8(state, (reg1 << 3) | reg2); + put8(state, imm8); +} + +static inline void sete_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "sete_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x94); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setne_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "setne_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x95); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setl_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "setl_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x9C); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setle_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "setle_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x9E); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setg_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "setg_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x9F); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setge_m8rel(usf_state_t * state, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "setge_m8rel"); + + put8(state, 0x41); + put8(state, 0x0F); + put8(state, 0x9D); + put8(state, 0x87); + put32(state, offset); +} + +static inline void setl_reg8(usf_state_t * state, unsigned int reg8) +{ + put8(state, 0x40); /* we need an REX prefix to use the uniform byte registers */ + put8(state, 0x0F); + put8(state, 0x9C); + put8(state, 0xC0 | reg8); +} + +static inline void setb_reg8(usf_state_t * state, unsigned int reg8) +{ + put8(state, 0x40); /* we need an REX prefix to use the uniform byte registers */ + put8(state, 0x0F); + put8(state, 0x92); + put8(state, 0xC0 | reg8); +} + +static inline void test_m32rel_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + int offset = rel_r15_offset(state, m32, "test_m32rel_imm32"); + + put8(state, 0x41); + put8(state, 0xF7); + put8(state, 0x87); + put32(state, offset); + put32(state, imm32); +} + +static inline void add_m32rel_xreg32(usf_state_t * state, unsigned int *m32, int xreg32) +{ + int offset = rel_r15_offset(state, m32, "add_m32rel_xreg32"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x01); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void sub_xreg32_m32rel(usf_state_t * state, int xreg32, unsigned int *m32) +{ + int offset = rel_r15_offset(state, m32, "sub_xreg32_m32rel"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x2B); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void sub_reg32_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x29); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static inline void sub_reg64_reg64(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x48); + put8(state, 0x29); + put8(state, (reg2 << 3) | reg1 | 0xC0); +} + +static inline void sub_reg64_imm32(usf_state_t * state, int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xE8 + reg64); + put32(state, imm32); +} + +static inline void sub_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x2D); + put32(state, imm32); +} + +static inline void jne_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x75); + put8(state, saut); +} + +static inline void je_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x74); + put8(state, saut); +} + +static inline void jbe_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x76); + put8(state, saut); +} + +static inline void ja_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x77); + put8(state, saut); +} + +static inline void jb_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x72); + put8(state, saut); +} + +static inline void jae_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x73); + put8(state, saut); +} + +static inline void jp_rj(usf_state_t * state, unsigned char saut) +{ + put8(state, 0x7A); + put8(state, saut); +} + +static inline void je_near_rj(usf_state_t * state, unsigned int saut) +{ + put8(state, 0x0F); + put8(state, 0x84); + put32(state, saut); +} + +static inline void mov_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0xB8+reg32); + put32(state, imm32); +} + +static inline void mov_reg64_imm64(usf_state_t * state, int reg64, unsigned long long imm64) +{ + put8(state, 0x48); + put8(state, 0xB8+reg64); + put64(state, imm64); +} + +static inline void jmp_imm_short(usf_state_t * state, char saut) +{ + put8(state, 0xEB); + put8(state, saut); +} + +static inline void or_m32rel_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + int offset = rel_r15_offset(state, m32, "or_m32rel_imm32"); + + put8(state, 0x41); + put8(state, 0x81); + put8(state, 0x8F); + put32(state, offset); + put32(state, imm32); +} + +static inline void or_reg64_reg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x48); + put8(state, 0x09); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void and_reg64_reg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x48); + put8(state, 0x21); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void and_m32rel_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + int offset = rel_r15_offset(state, m32, "and_m32rel_imm32"); + + put8(state, 0x41); + put8(state, 0x81); + put8(state, 0xA7); + put32(state, offset); + put32(state, imm32); +} + +static inline void xor_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x31); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void xor_reg64_reg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x48); + put8(state, 0x31); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void add_reg64_imm32(usf_state_t * state, unsigned int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xC0+reg64); + put32(state, imm32); +} + +static inline void add_reg32_imm32(usf_state_t * state, unsigned int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xC0+reg32); + put32(state, imm32); +} + +static inline void inc_m32rel(usf_state_t * state, unsigned int *m32) +{ + int offset = rel_r15_offset(state, m32, "inc_m32rel"); + + put8(state, 0x41); + put8(state, 0xFF); + put8(state, 0x87); + put32(state, offset); +} + +static inline void cmp_m32rel_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + int offset = rel_r15_offset(state, m32, "cmp_m32rel_imm32"); + + put8(state, 0x41); + put8(state, 0x81); + put8(state, 0xBF); + put32(state, offset); + put32(state, imm32); +} + +static inline void cmp_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x3D); + put32(state, imm32); +} + +static inline void mov_m32rel_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) +{ + int offset = rel_r15_offset(state, m32, "mov_m32rel_imm32"); + + put8(state, 0x41); + put8(state, 0xC7); + put8(state, 0x87); + put32(state, offset); + put32(state, imm32); +} + +static inline void jmp(usf_state_t * state, unsigned int mi_addr) +{ + put8(state, 0xFF); + put8(state, 0x25); + put32(state, 0); + put64(state, 0); + add_jump(state, state->code_length-8, mi_addr, 1); +} + +static inline void cdq(usf_state_t * state) +{ + put8(state, 0x99); +} + +static inline void call_reg64(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0xFF); + put8(state, 0xD0+reg64); +} + +static inline void shr_reg64_imm8(usf_state_t * state, unsigned int reg64, unsigned char imm8) +{ + put8(state, 0x48); + put8(state, 0xC1); + put8(state, 0xE8+reg64); + put8(state, imm8); +} + +static inline void shr_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xE8+reg32); + put8(state, imm8); +} + +static inline void shr_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xE8+reg32); +} + +static inline void shr_reg64_cl(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xD3); + put8(state, 0xE8+reg64); +} + +static inline void sar_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xF8+reg32); +} + +static inline void sar_reg64_cl(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xD3); + put8(state, 0xF8+reg64); +} + +static inline void shl_reg32_cl(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xD3); + put8(state, 0xE0+reg32); +} + +static inline void shl_reg64_cl(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xD3); + put8(state, 0xE0+reg64); +} + +static inline void sar_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xF8+reg32); + put8(state, imm8); +} + +static inline void sar_reg64_imm8(usf_state_t * state, unsigned int reg64, unsigned char imm8) +{ + put8(state, 0x48); + put8(state, 0xC1); + put8(state, 0xF8+reg64); + put8(state, imm8); +} + +static inline void mul_m32rel(usf_state_t * state, unsigned int *m32) +{ + int offset = rel_r15_offset(state, m32, "mul_m32rel"); + + put8(state, 0x41); + put8(state, 0xF7); + put8(state, 0xA7); + put32(state, offset); +} + +static inline void imul_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xE8+reg32); +} + +static inline void mul_reg64(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xF7); + put8(state, 0xE0+reg64); +} + +static inline void mul_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xE0+reg32); +} + +static inline void idiv_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xF8+reg32); +} + +static inline void div_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xF0+reg32); +} + +static inline void add_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x01); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void add_reg64_reg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x48); + put8(state, 0x01); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void jmp_reg64(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0xFF); + put8(state, 0xE0 + reg64); +} + +static inline void mov_reg32_preg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | reg2); +} + +static inline void mov_preg64_reg32(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x89); + put8(state, (reg2 << 3) | reg1); +} + +static inline void mov_reg64_preg64(usf_state_t * state, int reg1, int reg2) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, (reg1 << 3) | reg2); +} + +static inline void mov_reg32_preg64preg64pimm32(usf_state_t * state, int reg1, int reg2, int reg3, unsigned int imm32) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | 0x84); + put8(state, reg2 | (reg3 << 3)); + put32(state, imm32); +} + +static inline void mov_preg64preg64pimm32_reg32(usf_state_t * state, int reg1, int reg2, unsigned int imm32, int reg3) +{ + put8(state, 0x89); + put8(state, (reg3 << 3) | 0x84); + put8(state, reg1 | (reg2 << 3)); + put32(state, imm32); +} + +static inline void mov_reg64_preg64preg64pimm32(usf_state_t * state, int reg1, int reg2, int reg3, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, (reg1 << 3) | 0x84); + put8(state, reg2 | (reg3 << 3)); + put32(state, imm32); +} + +static inline void mov_reg32_preg64preg64(usf_state_t * state, int reg1, int reg2, int reg3) +{ + put8(state, 0x8B); + put8(state, (reg1 << 3) | 0x04); + put8(state, (reg2 << 3) | reg3); +} + +static inline void mov_reg64_preg64preg64(usf_state_t * state, int reg1, int reg2, int reg3) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, (reg1 << 3) | 0x04); + put8(state, reg2 | (reg3 << 3)); +} + +static inline void mov_reg32_preg64pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x8B); + put8(state, 0x80 | (reg1 << 3) | reg2); + put32(state, imm32); +} + +static inline void mov_reg64_preg64pimm32(usf_state_t * state, int reg1, int reg2, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, 0x80 | (reg1 << 3) | reg2); + put32(state, imm32); +} + +static inline void mov_reg64_preg64pimm8(usf_state_t * state, int reg1, int reg2, unsigned int imm8) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, 0x40 | (reg1 << 3) | reg2); + put8(state, imm8); +} + +static inline void mov_reg64_preg64x8preg64(usf_state_t * state, int reg1, int reg2, int reg3) +{ + put8(state, 0x48); + put8(state, 0x8B); + put8(state, (reg1 << 3) | 4); + put8(state, 0xC0 | (reg2 << 3) | reg3); +} + +static inline void mov_preg64preg64_reg8(usf_state_t * state, int reg1, int reg2, int reg8) +{ + put8(state, 0x88); + put8(state, 0x04 | (reg8 << 3)); + put8(state, (reg1 << 3) | reg2); +} + +static inline void mov_preg64preg64_imm8(usf_state_t * state, int reg1, int reg2, unsigned char imm8) +{ + put8(state, 0xC6); + put8(state, 0x04); + put8(state, (reg1 << 3) | reg2); + put8(state, imm8); +} + +static inline void mov_preg64preg64_reg16(usf_state_t * state, int reg1, int reg2, int reg16) +{ + put8(state, 0x66); + put8(state, 0x89); + put8(state, 0x04 | (reg16 << 3)); + put8(state, (reg1 << 3) | reg2); +} + +static inline void mov_preg64preg64_reg32(usf_state_t * state, int reg1, int reg2, int reg32) +{ + put8(state, 0x89); + put8(state, 0x04 | (reg32 << 3)); + put8(state, (reg1 << 3) | reg2); +} + +static inline void mov_preg64pimm32_reg32(usf_state_t * state, int reg1, unsigned int imm32, int reg2) +{ + put8(state, 0x89); + put8(state, 0x80 | reg1 | (reg2 << 3)); + put32(state, imm32); +} + +static inline void mov_preg64pimm8_reg64(usf_state_t * state, int reg1, unsigned int imm8, int reg2) +{ + put8(state, 0x48); + put8(state, 0x89); + put8(state, 0x40 | (reg2 << 3) | reg1); + put8(state, imm8); +} + +static inline void add_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x05); + put32(state, imm32); +} + +static inline void shl_reg32_imm8(usf_state_t * state, unsigned int reg32, unsigned char imm8) +{ + put8(state, 0xC1); + put8(state, 0xE0 + reg32); + put8(state, imm8); +} + +static inline void shl_reg64_imm8(usf_state_t * state, unsigned int reg64, unsigned char imm8) +{ + put8(state, 0x48); + put8(state, 0xC1); + put8(state, 0xE0 + reg64); + put8(state, imm8); +} + +static inline void mov_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + if (reg1 == reg2) return; + put8(state, 0x89); + put8(state, 0xC0 | (reg2 << 3) | reg1); +} + +static inline void mov_reg64_reg64(usf_state_t * state, unsigned int reg1, unsigned int reg2) +{ + if (reg1 == reg2) return; + put8(state, 0x48 | ((reg1 & 8) >> 3) | ((reg2 & 8) >> 1)); + put8(state, 0x89); + put8(state, 0xC0 | ((reg2 & 7) << 3) | (reg1 & 7)); +} + +static inline void mov_xreg32_m32rel(usf_state_t * state, unsigned int xreg32, unsigned int *m32) +{ + int offset = rel_r15_offset(state, m32, "mov_xreg32_m32rel"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x8B); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_m32rel_xreg32(usf_state_t * state, unsigned int *m32, unsigned int xreg32) +{ + int offset = rel_r15_offset(state, m32, "mov_m32rel_xreg32"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x89); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_xreg64_m64rel(usf_state_t * state, unsigned int xreg64, unsigned long long* m64) +{ + int offset = rel_r15_offset(state, m64, "mov_xreg64_m64rel"); + + put8(state, 0x49 | ((xreg64 & 8) >> 1)); + put8(state, 0x8B); + put8(state, 0x87 | ((xreg64 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_m64rel_xreg64(usf_state_t * state, unsigned long long *m64, unsigned int xreg64) +{ + int offset = rel_r15_offset(state, m64, "mov_m64rel_xreg64"); + + put8(state, 0x49 | ((xreg64 & 8) >> 1)); + put8(state, 0x89); + put8(state, 0x87 | ((xreg64 & 7) << 3)); + put32(state, offset); +} + +static inline void mov_xreg8_m8rel(usf_state_t * state, int xreg8, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "mov_xreg8_m8rel"); + + put8(state, 0x41 | ((xreg8 & 8) >> 1)); + put8(state, 0x8A); + put8(state, 0x87 | ((xreg8 & 7) << 3)); + put32(state, offset); +} + +static inline void and_eax_imm32(usf_state_t * state, unsigned int imm32) +{ + put8(state, 0x25); + put32(state, imm32); +} + +static inline void or_reg64_imm32(usf_state_t * state, int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xC8 + reg64); + put32(state, imm32); +} + +static inline void and_reg32_imm32(usf_state_t * state, int reg32, unsigned int imm32) +{ + put8(state, 0x81); + put8(state, 0xE0 + reg32); + put32(state, imm32); +} + +static inline void and_reg64_imm32(usf_state_t * state, int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xE0 + reg64); + put32(state, imm32); +} + +static inline void and_reg64_imm8(usf_state_t * state, int reg64, unsigned char imm8) +{ + put8(state, 0x48); + put8(state, 0x83); + put8(state, 0xE0 + reg64); + put8(state, imm8); +} + +static inline void xor_reg64_imm32(usf_state_t * state, int reg64, unsigned int imm32) +{ + put8(state, 0x48); + put8(state, 0x81); + put8(state, 0xF0 + reg64); + put32(state, imm32); +} + +static inline void xor_reg8_imm8(usf_state_t * state, int reg8, unsigned char imm8) +{ + put8(state, 0x40); /* we need an REX prefix to use the uniform byte registers */ + put8(state, 0x80); + put8(state, 0xF0 + reg8); + put8(state, imm8); +} + +static inline void not_reg64(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xF7); + put8(state, 0xD0 + reg64); +} + +static inline void neg_reg32(usf_state_t * state, unsigned int reg32) +{ + put8(state, 0xF7); + put8(state, 0xD8 + reg32); +} + +static inline void neg_reg64(usf_state_t * state, unsigned int reg64) +{ + put8(state, 0x48); + put8(state, 0xF7); + put8(state, 0xD8 + reg64); +} + +static inline void movsx_xreg32_m8rel(usf_state_t * state, int xreg32, unsigned char *m8) +{ + int offset = rel_r15_offset(state, m8, "movsx_xreg32_m8rel"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x0F); + put8(state, 0xBE); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void movsx_reg32_8preg64preg64(usf_state_t * state, int reg1, int reg2, int reg3) +{ + put8(state, 0x0F); + put8(state, 0xBE); + put8(state, (reg1 << 3) | 0x04); + put8(state, (reg2 << 3) | reg3); +} + +static inline void movsx_reg32_16preg64preg64(usf_state_t * state, int reg1, int reg2, int reg3) +{ + put8(state, 0x0F); + put8(state, 0xBF); + put8(state, (reg1 << 3) | 0x04); + put8(state, (reg2 << 3) | reg3); +} + +static inline void movsx_xreg32_m16rel(usf_state_t * state, int xreg32, unsigned short *m16) +{ + int offset = rel_r15_offset(state, m16, "movsx_xreg32_m16rel"); + + put8(state, 0x41 | ((xreg32 & 8) >> 1)); + put8(state, 0x0F); + put8(state, 0xBF); + put8(state, 0x87 | ((xreg32 & 7) << 3)); + put32(state, offset); +} + +static inline void movsxd_reg64_reg32(usf_state_t * state, int reg64, int reg32) +{ + put8(state, 0x48); + put8(state, 0x63); + put8(state, (reg64 << 3) | reg32 | 0xC0); +} + +static inline void fldcw_m16rel(usf_state_t * state, unsigned short *m16) +{ + int offset = rel_r15_offset(state, m16, "fldcw_m16rel"); + + put8(state, 0x41); + put8(state, 0xD9); + put8(state, 0xAF); + put32(state, offset); +} + +static inline void fld_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD9); + put8(state, reg64); +} + +static inline void fdiv_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD8); + put8(state, 0x30 + reg64); +} + +static inline void fstp_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD9); + put8(state, 0x18 + reg64); +} + +static inline void fchs(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xE0); +} + +static inline void fstp_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDD); + put8(state, 0x18 + reg64); +} + +static inline void fadd_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD8); + put8(state, reg64); +} + +static inline void fsub_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD8); + put8(state, 0x20 + reg64); +} + +static inline void fmul_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xD8); + put8(state, 0x08 + reg64); +} + +static inline void fistp_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xDB); + put8(state, 0x18 + reg64); +} + +static inline void fistp_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDF); + put8(state, 0x38 + reg64); +} + +static inline void fld_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDD); + put8(state, reg64); +} + +static inline void fild_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDF); + put8(state, 0x28+reg64); +} + +static inline void fild_preg64_dword(usf_state_t * state, int reg64) +{ + put8(state, 0xDB); + put8(state, reg64); +} + +static inline void fadd_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDC); + put8(state, reg64); +} + +static inline void fdiv_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDC); + put8(state, 0x30 + reg64); +} + +static inline void fsub_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDC); + put8(state, 0x20 + reg64); +} + +static inline void fmul_preg64_qword(usf_state_t * state, int reg64) +{ + put8(state, 0xDC); + put8(state, 0x08 + reg64); +} + +static inline void fsqrt(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xFA); +} + +static inline void fabs_(usf_state_t * state) +{ + put8(state, 0xD9); + put8(state, 0xE1); +} + +static inline void fcomip_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDF); + put8(state, 0xF0 + fpreg); +} + +static inline void fucomip_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDF); + put8(state, 0xE8 + fpreg); +} + +static inline void ffree_fpreg(usf_state_t * state, int fpreg) +{ + put8(state, 0xDD); + put8(state, 0xC0 + fpreg); +} + +#endif /* M64P_R4300_ASSEMBLE_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble_struct.h b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble_struct.h new file mode 100644 index 000000000..46e59ff53 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/assemble_struct.h @@ -0,0 +1,34 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - assemble_struct.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_ASSEMBLE_STRUCT_H +#define M64P_R4300_ASSEMBLE_STRUCT_H + +typedef struct _reg_cache_struct +{ + int need_map; + void *needed_registers[8]; + unsigned char jump_wrapper[84]; + int need_cop1_check; +} reg_cache_struct; + +#endif /* M64P_R4300_ASSEMBLE_STRUCT_H */ diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gbc.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gbc.c new file mode 100644 index 000000000..001627109 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gbc.c @@ -0,0 +1,305 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gbc.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +static void genbc1f_test(usf_state_t * state) +{ + test_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); + sete_m8rel(state, (unsigned char *) &state->branch_taken); +} + +void genbc1f(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[100]); +#endif +#ifdef INTERPRET_BC1F + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbc1f_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[100]); +#endif +#ifdef INTERPRET_BC1F_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbc1f_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1F_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1F_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gentest_idle(state); + genbc1f(state); +#endif +} + +static void genbc1t_test(usf_state_t * state) +{ + test_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); + setne_m8rel(state, (unsigned char *) &state->branch_taken); +} + +void genbc1t(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[101]); +#endif +#ifdef INTERPRET_BC1T + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbc1t_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[101]); +#endif +#ifdef INTERPRET_BC1T_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbc1t_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1T_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1T_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gentest_idle(state); + genbc1t(state); +#endif +} + +void genbc1fl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[102]); +#endif +#ifdef INTERPRET_BC1FL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbc1fl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[102]); +#endif +#ifdef INTERPRET_BC1FL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbc1fl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1FL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1FL_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1f_test(state); + gentest_idle(state); + genbc1fl(state); +#endif +} + +void genbc1tl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[103]); +#endif +#ifdef INTERPRET_BC1TL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbc1tl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[103]); +#endif +#ifdef INTERPRET_BC1TL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL_OUT, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbc1tl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BC1TL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BC1TL_IDLE, 1); + return; + } + + gencheck_cop1_unusable(state); + genbc1t_test(state); + gentest_idle(state); + genbc1tl(state); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop0.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop0.c new file mode 100644 index 000000000..86be49e00 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop0.c @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop0.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void genmfc0(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[109]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.MFC0, 0); +} + +void genmtc0(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[110]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.MTC0, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1.c new file mode 100644 index 000000000..14d1f7fe8 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1.c @@ -0,0 +1,163 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/cp1.h" + +#include "memory/memory.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void genmfc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[111]); +#endif +#ifdef INTERPRET_MFC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.MFC1, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.r.nrd])); + mov_reg32_preg64(state, EBX, RAX); + mov_m32rel_xreg32(state, (unsigned int*)state->dst->f.r.rt, EBX); + sar_reg32_imm8(state, EBX, 31); + mov_m32rel_xreg32(state, ((unsigned int*)state->dst->f.r.rt)+1, EBX); +#endif +} + +void gendmfc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[112]); +#endif +#ifdef INTERPRET_DMFC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.DMFC1, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *) (&state->reg_cop1_double[state->dst->f.r.nrd])); + mov_reg32_preg64(state, EBX, RAX); + mov_reg32_preg64pimm32(state, ECX, RAX, 4); + mov_m32rel_xreg32(state, (unsigned int*)state->dst->f.r.rt, EBX); + mov_m32rel_xreg32(state, ((unsigned int*)state->dst->f.r.rt)+1, ECX); +#endif +} + +void gencfc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[113]); +#endif +#ifdef INTERPRET_CFC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.CFC1, 0); +#else + gencheck_cop1_unusable(state); + if(state->dst->f.r.nrd == 31) mov_xreg32_m32rel(state, EAX, (unsigned int*)&state->FCR31); + else mov_xreg32_m32rel(state, EAX, (unsigned int*)&state->FCR0); + mov_m32rel_xreg32(state, (unsigned int*)state->dst->f.r.rt, EAX); + sar_reg32_imm8(state, EAX, 31); + mov_m32rel_xreg32(state, ((unsigned int*)state->dst->f.r.rt)+1, EAX); +#endif +} + +void genmtc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[114]); +#endif +#ifdef INTERPRET_MTC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.MTC1, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg32_m32rel(state, EAX, (unsigned int*)state->dst->f.r.rt); + mov_xreg64_m64rel(state, RBX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.r.nrd])); + mov_preg64_reg32(state, RBX, EAX); +#endif +} + +void gendmtc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[115]); +#endif +#ifdef INTERPRET_DMTC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.DMTC1, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg32_m32rel(state, EAX, (unsigned int*)state->dst->f.r.rt); + mov_xreg32_m32rel(state, EBX, ((unsigned int*)state->dst->f.r.rt)+1); + mov_xreg64_m64rel(state, RDX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.r.nrd])); + mov_preg64_reg32(state, RDX, EAX); + mov_preg64pimm32_reg32(state, RDX, 4, EBX); +#endif +} + +void genctc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[116]); +#endif +#ifdef INTERPRET_CTC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.CTC1, 0); +#else + gencheck_cop1_unusable(state); + + if (state->dst->f.r.nrd != 31) return; + mov_xreg32_m32rel(state, EAX, (unsigned int*)state->dst->f.r.rt); + mov_m32rel_xreg32(state, (unsigned int*)&state->FCR31, EAX); + and_eax_imm32(state, 3); + + cmp_eax_imm32(state, 0); + jne_rj(state, 13); + mov_m32rel_imm32(state, (unsigned int*)&state->rounding_mode, 0x33F); // 11 + jmp_imm_short(state, 51); // 2 + + cmp_eax_imm32(state, 1); // 5 + jne_rj(state, 13); // 2 + mov_m32rel_imm32(state, (unsigned int*)&state->rounding_mode, 0xF3F); // 11 + jmp_imm_short(state, 31); // 2 + + cmp_eax_imm32(state, 2); // 5 + jne_rj(state, 13); // 2 + mov_m32rel_imm32(state, (unsigned int*)&state->rounding_mode, 0xB3F); // 11 + jmp_imm_short(state, 11); // 2 + + mov_m32rel_imm32(state, (unsigned int*)&state->rounding_mode, 0x73F); // 11 + + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_d.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_d.c new file mode 100644 index 000000000..b3215822f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_d.c @@ -0,0 +1,719 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_d.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void genadd_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[119]); +#endif +#ifdef INTERPRET_ADD_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADD_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fadd_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void gensub_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[120]); +#endif +#ifdef INTERPRET_SUB_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.SUB_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fsub_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void genmul_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[121]); +#endif +#ifdef INTERPRET_MUL_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.MUL_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fmul_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void gendiv_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[122]); +#endif +#ifdef INTERPRET_DIV_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.DIV_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fdiv_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void gensqrt_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[123]); +#endif +#ifdef INTERPRET_SQRT_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.SQRT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fsqrt(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void genabs_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[124]); +#endif +#ifdef INTERPRET_ABS_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.ABS_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fabs_(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void genmov_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[125]); +#endif +#ifdef INTERPRET_MOV_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.MOV_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + mov_reg32_preg64(state, EBX, RAX); + mov_reg32_preg64pimm32(state, ECX, RAX, 4); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + mov_preg64_reg32(state, RAX, EBX); + mov_preg64pimm32_reg32(state, RAX, 4, ECX); +#endif +} + +void genneg_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[126]); +#endif +#ifdef INTERPRET_NEG_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.NEG_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fchs(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void genround_l_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[127]); +#endif +#ifdef INTERPRET_ROUND_L_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.ROUND_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->round_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_l_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[128]); +#endif +#ifdef INTERPRET_TRUNC_L_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.TRUNC_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->trunc_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_l_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[129]); +#endif +#ifdef INTERPRET_CEIL_L_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.CEIL_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->ceil_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_l_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[130]); +#endif +#ifdef INTERPRET_FLOOR_L_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.FLOOR_L_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->floor_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genround_w_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[127]); +#endif +#ifdef INTERPRET_ROUND_W_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.ROUND_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->round_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_w_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[128]); +#endif +#ifdef INTERPRET_TRUNC_W_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.TRUNC_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->trunc_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_w_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[129]); +#endif +#ifdef INTERPRET_CEIL_W_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.CEIL_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->ceil_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_w_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[130]); +#endif +#ifdef INTERPRET_FLOOR_W_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.FLOOR_W_D, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->floor_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gencvt_s_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_S_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_S_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gencvt_w_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_W_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_W_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); +#endif +} + +void gencvt_l_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_L_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_L_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); +#endif +} + +void genc_f_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_F_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_F_D, 0); +#else + gencheck_cop1_unusable(state); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_un_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_UN_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_UN_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 13); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 + jmp_imm_short(state, 11); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 +#endif +} + +void genc_eq_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_EQ_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_EQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ueq_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_UEQ_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_UEQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_olt_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_OLT_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_OLT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ult_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_ULT_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_ULT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jae_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ole_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_OLE_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_OLE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ule_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_ULE_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_ULE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + ja_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_sf_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_SF_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_SF_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_ngle_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGLE_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGLE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 13); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 + jmp_imm_short(state, 11); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 +#endif +} + +void genc_seq_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_SEQ_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_SEQ_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ngl_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGL_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGL_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_lt_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_LT_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_LT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_nge_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGE_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jae_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_le_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_LE_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_LE_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ngt_d(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGT_D + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGT_D, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.ft])); + fld_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fld_preg64_qword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + ja_rj(state, 13); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_l.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_l.c new file mode 100644 index 000000000..ac81153f0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_l.c @@ -0,0 +1,70 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - g_cop1_l.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void gencvt_s_l(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_S_L + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_S_L, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fild_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gencvt_d_l(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_D_L + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_D_L, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fs])); + fild_preg64_qword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_s.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_s.c new file mode 100644 index 000000000..75f8617f8 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_s.c @@ -0,0 +1,718 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_s.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/cp1.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void genadd_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[119]); +#endif +#ifdef INTERPRET_ADD_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADD_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fadd_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gensub_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[120]); +#endif +#ifdef INTERPRET_SUB_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.SUB_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fsub_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void genmul_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[121]); +#endif +#ifdef INTERPRET_MUL_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.MUL_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fmul_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gendiv_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[122]); +#endif +#ifdef INTERPRET_DIV_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.DIV_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fdiv_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gensqrt_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[123]); +#endif +#ifdef INTERPRET_SQRT_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.SQRT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fsqrt(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void genabs_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[124]); +#endif +#ifdef INTERPRET_ABS_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.ABS_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fabs_(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void genmov_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[125]); +#endif +#ifdef INTERPRET_MOV_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.MOV_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + mov_reg32_preg64(state, EBX, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + mov_preg64_reg32(state, RAX, EBX); +#endif +} + +void genneg_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[126]); +#endif +#ifdef INTERPRET_NEG_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.NEG_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fchs(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void genround_l_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[127]); +#endif +#ifdef INTERPRET_ROUND_L_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.ROUND_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->round_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_l_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[128]); +#endif +#ifdef INTERPRET_TRUNC_L_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.TRUNC_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->trunc_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_l_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[129]); +#endif +#ifdef INTERPRET_CEIL_L_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.CEIL_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->ceil_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_l_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[130]); +#endif +#ifdef INTERPRET_FLOOR_L_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.FLOOR_L_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->floor_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genround_w_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[127]); +#endif +#ifdef INTERPRET_ROUND_W_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.ROUND_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->round_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gentrunc_w_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[128]); +#endif +#ifdef INTERPRET_TRUNC_W_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.TRUNC_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->trunc_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genceil_w_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[129]); +#endif +#ifdef INTERPRET_CEIL_W_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.CEIL_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->ceil_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void genfloor_w_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[130]); +#endif +#ifdef INTERPRET_FLOOR_W_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.FLOOR_W_S, 0); +#else + gencheck_cop1_unusable(state); + fldcw_m16rel(state, (unsigned short*)&state->floor_mode); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); + fldcw_m16rel(state, (unsigned short*)&state->rounding_mode); +#endif +} + +void gencvt_d_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_D_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_D_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + +void gencvt_w_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_W_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_W_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fistp_preg64_dword(state, RAX); +#endif +} + +void gencvt_l_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_L_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_L_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fistp_preg64_qword(state, RAX); +#endif +} + +void genc_f_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_F_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_F_S, 0); +#else + gencheck_cop1_unusable(state); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_un_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_UN_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_UN_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 13); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 + jmp_imm_short(state, 11); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 +#endif +} + +void genc_eq_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_EQ_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_EQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ueq_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_UEQ_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_UEQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_olt_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_OLT_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_OLT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ult_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_ULT_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_ULT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jae_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ole_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_OLE_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_OLE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ule_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_ULE_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_ULE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fucomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + ja_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_sf_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_SF_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_SF_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); +#endif +} + +void genc_ngle_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGLE_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGLE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 13); + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 + jmp_imm_short(state, 11); // 2 + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 +#endif +} + +void genc_seq_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_SEQ_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_SEQ_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ngl_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGL_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGL_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jne_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_lt_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_LT_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_LT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jae_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_nge_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGE_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + jae_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_le_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_LE_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_LE_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + ja_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + +void genc_ngt_s(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[118]); +#endif +#ifdef INTERPRET_C_NGT_S + gencallinterp(state, (unsigned long long)state->current_instruction_table.C_NGT_S, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.ft])); + fld_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fld_preg64_dword(state, RAX); + fcomip_fpreg(state, 1); + ffree_fpreg(state, 0); + jp_rj(state, 15); + ja_rj(state, 13); + or_m32rel_imm32(state, (unsigned int*)&state->FCR31, 0x800000); // 11 + jmp_imm_short(state, 11); // 2 + and_m32rel_imm32(state, (unsigned int*)&state->FCR31, ~0x800000); // 11 +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_w.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_w.c new file mode 100644 index 000000000..55efd2dc4 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gcop1_w.c @@ -0,0 +1,72 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gcop1_w.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp1.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void gencvt_s_w(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_S_W + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_S_W, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fild_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fd])); + fstp_preg64_dword(state, RAX); +#endif +} + +void gencvt_d_w(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[117]); +#endif +#ifdef INTERPRET_CVT_D_W + gencallinterp(state, (unsigned long long)state->current_instruction_table.CVT_D_W, 0); +#else + gencheck_cop1_unusable(state); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.cf.fs])); + fild_preg64_dword(state, RAX); + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.cf.fd])); + fstp_preg64_qword(state, RAX); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gr4300.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gr4300.c new file mode 100644 index 000000000..6449150b6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gr4300.c @@ -0,0 +1,2260 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gr4300.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "regcache.h" +#include "interpret.h" + +#include "main/main.h" +#include "memory/memory.h" +#include "r4300/r4300.h" +#include "r4300/cached_interp.h" +#include "r4300/cp0.h" +#include "r4300/cp1.h" +#include "r4300/interupt.h" +#include "r4300/ops.h" +#include "r4300/recomph.h" +#include "r4300/exception.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +#if !defined(offsetof) +# define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) +#endif + +/* static functions */ + +static void genupdate_count(usf_state_t * state, unsigned int addr) +{ + mov_reg32_imm32(state, EAX, addr); + sub_xreg32_m32rel(state, EAX, (unsigned int*)(&state->last_addr)); + shr_reg32_imm8(state, EAX, 2); + mov_xreg32_m32rel(state, EDX, (void*)&state->count_per_op); + mul_reg32(state, EDX); + add_m32rel_xreg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); +} + +static void gencheck_interupt(usf_state_t * state, unsigned long long instr_structure) +{ + mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt)); + cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, RAX, (unsigned long long) instr_structure); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) gen_interupt); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + + jump_end_rel8(state); +} + +static void gencheck_interupt_out(usf_state_t * state, unsigned int addr) +{ + mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt)); + cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 0); + jump_start_rel8(state); + + mov_m32rel_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr); + mov_reg64_imm64(state, RAX, (unsigned long long) (&state->fake_instr)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) gen_interupt); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + + jump_end_rel8(state); +} + +static void genbeq_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + int rt_64bit = is64(state, (unsigned int *)state->dst->f.i.rt); + + if (rs_64bit == 0 && rt_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_reg32(state, rs, rt); + sete_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rs_64bit == -1) + { + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rt); + + cmp_xreg64_m64rel(state, rt, (unsigned long long *) state->dst->f.i.rs); + sete_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rt_64bit == -1) + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + + cmp_xreg64_m64rel(state, rs, (unsigned long long *)state->dst->f.i.rt); + sete_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rt); + cmp_reg64_reg64(state, rs, rt); + sete_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +static void genbne_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + int rt_64bit = is64(state, (unsigned int *)state->dst->f.i.rt); + + if (rs_64bit == 0 && rt_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.i.rt); + + cmp_reg32_reg32(state, rs, rt); + setne_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rs_64bit == -1) + { + int rt = allocate_register_64(state, (unsigned long long *) state->dst->f.i.rt); + + cmp_xreg64_m64rel(state, rt, (unsigned long long *)state->dst->f.i.rs); + setne_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rt_64bit == -1) + { + int rs = allocate_register_64(state, (unsigned long long *) state->dst->f.i.rs); + + cmp_xreg64_m64rel(state, rs, (unsigned long long *)state->dst->f.i.rt); + setne_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rt); + + cmp_reg64_reg64(state, rs, rt); + setne_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +static void genblez_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (rs_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + setle_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + + cmp_reg64_imm8(state, rs, 0); + setle_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +static void genbgtz_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (rs_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + setg_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + + cmp_reg64_imm8(state, rs, 0); + setg_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +static void ld_register_alloc(usf_state_t * state, int *pGpr1, int *pGpr2, int *pBase1, int *pBase2) +{ + int gpr1, gpr2, base1, base2 = 0; + + if (state->dst->f.i.rs == state->dst->f.i.rt) + { + allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); // tell regcache we need to read RS register here + gpr1 = allocate_register_32_w(state, (unsigned int*)state->dst->f.r.rt); // tell regcache we will modify RT register during this instruction + gpr2 = lock_register(state, lru_register(state)); // free and lock least recently used register for usage here + add_reg32_imm32(state, gpr1, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, gpr2, gpr1); + } + else + { + gpr2 = allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); // tell regcache we need to read RS register here + gpr1 = allocate_register_32_w(state, (unsigned int*)state->dst->f.r.rt); // tell regcache we will modify RT register during this instruction + free_register(state, gpr2); // write out gpr2 if dirty because I'm going to trash it right now + add_reg32_imm32(state, gpr2, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, gpr1, gpr2); + lock_register(state, gpr2); // lock the freed gpr2 it so it doesn't get returned in the lru query + } + base1 = lock_register(state, lru_base_register(state)); // get another lru register + if (!state->fast_memory) + { + base2 = lock_register(state, lru_base_register(state)); // and another one if necessary + unlock_register(state, base2); + } + unlock_register(state, base1); // unlock the locked registers (they are + unlock_register(state, gpr2); + set_register_state(state, gpr1, NULL, 0, 0); // clear gpr1 state because it hasn't been written yet - + // we don't want it to be pushed/popped around read_rdramX call + *pGpr1 = gpr1; + *pGpr2 = gpr2; + *pBase1 = base1; + *pBase2 = base2; +} + + +/* global functions */ + +void gennotcompiled(usf_state_t * state) +{ + free_registers_move_start(state); + + mov_reg64_imm64(state, RAX, (unsigned long long) state->dst); + mov_memoffs64_rax(state, (unsigned long long *) &state->PC); /* RIP-relative will not work here */ + mov_reg64_imm64(state, RAX, (unsigned long long) state->current_instruction_table.NOTCOMPILED); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); +} + +void genlink_subblock(usf_state_t * state) +{ + free_all_registers(state); + jmp(state, state->dst->addr+4); +} + +void gencallinterp(usf_state_t * state, unsigned long long addr, int jump) +{ + free_registers_move_start(state); + + if (jump) + mov_m32rel_imm32(state, (unsigned int*)(&state->dyna_interp), 1); + + mov_reg64_imm64(state, RAX, (unsigned long long) state->dst); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, addr); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + + if (jump) + { + mov_m32rel_imm32(state, (unsigned int*)(&state->dyna_interp), 0); + mov_reg64_imm64(state, RAX, (unsigned long long)dyna_jump); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + } +} + +void gendelayslot(usf_state_t * state) +{ + mov_m32rel_imm32(state, (void*)(&state->delay_slot), 1); + recompile_opcode(state); + + free_all_registers(state); + genupdate_count(state, state->dst->addr+4); + + mov_m32rel_imm32(state, (void*)(&state->delay_slot), 0); +} + +void genni(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[1]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.NI, 0); +} + +void genreserved(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[0]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.RESERVED, 0); +} + +void genfin_block(usf_state_t * state) +{ + gencallinterp(state, (unsigned long long)state->current_instruction_table.FIN_BLOCK, 0); +} + +void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX +{ + mov_xreg32_m32rel(state, EBX, (void*)&state->next_interupt); + cmp_xreg32_m32rel(state, EBX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); + ja_rj(state, 0); + jump_start_rel8(state); + + mov_m32rel_xreg32(state, (unsigned int*)(&state->fake_instr.addr), EAX); + mov_reg64_imm64(state, RAX, (unsigned long long) (&state->fake_instr)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) gen_interupt); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + + jump_end_rel8(state); +} + +void gennop(usf_state_t * state) +{ + (void)state; +} + +void genj(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[2]); +#endif +#ifdef INTERPRET_J + gencallinterp(state, (unsigned long long)state->current_instruction_table.J, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.J, 1); + return; + } + + gendelayslot(state); + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), naddr); + gencheck_interupt(state, (unsigned long long) &state->actual->block[(naddr-state->actual->start)/4]); + jmp(state, naddr); +#endif +} + +void genj_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[2]); +#endif +#ifdef INTERPRET_J_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.J_OUT, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.J_OUT, 1); + return; + } + + gendelayslot(state); + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), naddr); + gencheck_interupt_out(state, naddr); + mov_m32rel_imm32(state, &state->jump_to_address, naddr); + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long)jump_to_func); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); +#endif +} + +void genj_idle(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[2]); +#endif +#ifdef INTERPRET_J_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.J_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.J_IDLE, 1); + return; + } + + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt)); + sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, EAX, 3); + jbe_rj(state, 12); + + and_eax_imm32(state, 0xFFFFFFFC); // 5 + add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7 + + genj(state); +#endif +} + +void genjal(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[3]); +#endif +#ifdef INTERPRET_JAL + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL, 1); + return; + } + + gendelayslot(state); + + mov_m32rel_imm32(state, (unsigned int *)(state->reg + 31), state->dst->addr + 4); + if (((state->dst->addr + 4) & 0x80000000)) + mov_m32rel_imm32(state, (unsigned int *)(&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32rel_imm32(state, (unsigned int *)(&state->reg[31])+1, 0); + + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), naddr); + gencheck_interupt(state, (unsigned long long) &state->actual->block[(naddr-state->actual->start)/4]); + jmp(state, naddr); +#endif +} + +void genjal_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[3]); +#endif +#ifdef INTERPRET_JAL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL_OUT, 1); +#else + unsigned int naddr; + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL_OUT, 1); + return; + } + + gendelayslot(state); + + mov_m32rel_imm32(state, (unsigned int *)(state->reg + 31), state->dst->addr + 4); + if (((state->dst->addr + 4) & 0x80000000)) + mov_m32rel_imm32(state, (unsigned int *)(&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32rel_imm32(state, (unsigned int *)(&state->reg[31])+1, 0); + + naddr = ((state->dst-1)->f.j.inst_index<<2) | (state->dst->addr & 0xF0000000); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), naddr); + gencheck_interupt_out(state, naddr); + mov_m32rel_imm32(state, &state->jump_to_address, naddr); + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) jump_to_func); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); +#endif +} + +void genjal_idle(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[3]); +#endif +#ifdef INTERPRET_JAL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.JAL_IDLE, 1); + return; + } + + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt)); + sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, EAX, 3); + jbe_rj(state, 12); + + and_eax_imm32(state, 0xFFFFFFFC); // 5 + add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7 + + genjal(state); +#endif +} + +void gentest(usf_state_t * state) +{ + cmp_m32rel_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + jump_start_rel32(state); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt(state, (unsigned long long) (state->dst + (state->dst-1)->f.i.immediate)); + jmp(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + + jump_end_rel32(state); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + 4); + gencheck_interupt(state, (unsigned long long)(state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeq(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[4]); +#endif +#ifdef INTERPRET_BEQ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ, 1); + return; + } + + genbeq_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void gentest_out(usf_state_t * state) +{ + cmp_m32rel_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + jump_start_rel32(state); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt_out(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32rel_imm32(state, &state->jump_to_address, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) jump_to_func); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + jump_end_rel32(state); + + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + 4); + gencheck_interupt(state, (unsigned long long) (state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeq_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[4]); +#endif +#ifdef INTERPRET_BEQ_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ_OUT, 1); + return; + } + + genbeq_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void gentest_idle(usf_state_t * state) +{ + int reg; + + reg = lru_register(state); + free_register(state, reg); + + cmp_m32rel_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + jump_start_rel32(state); + + mov_xreg32_m32rel(state, reg, (unsigned int *)(&state->next_interupt)); + sub_xreg32_m32rel(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); + cmp_reg32_imm8(state, reg, 3); + jbe_rj(state, 0); + jump_start_rel8(state); + + and_reg32_imm32(state, reg, 0xFFFFFFFC); + add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); + + jump_end_rel8(state); + jump_end_rel32(state); +} + +void genbeq_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BEQ_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQ_IDLE, 1); + return; + } + + genbeq_test(state); + gentest_idle(state); + genbeq(state); +#endif +} + +void genbne(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[5]); +#endif +#ifdef INTERPRET_BNE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE, 1); + return; + } + + genbne_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbne_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[5]); +#endif +#ifdef INTERPRET_BNE_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE_OUT, 1); + return; + } + + genbne_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbne_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BNE_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNE_IDLE, 1); + return; + } + + genbne_test(state); + gentest_idle(state); + genbne(state); +#endif +} + +void genblez(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[6]); +#endif +#ifdef INTERPRET_BLEZ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ, 1); + return; + } + + genblez_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genblez_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[6]); +#endif +#ifdef INTERPRET_BLEZ_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ_OUT, 1); + return; + } + + genblez_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genblez_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZ_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZ_IDLE, 1); + return; + } + + genblez_test(state); + gentest_idle(state); + genblez(state); +#endif +} + +void genbgtz(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[7]); +#endif +#ifdef INTERPRET_BGTZ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ, 1); + return; + } + + genbgtz_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgtz_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[7]); +#endif +#ifdef INTERPRET_BGTZ_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ_OUT, 1); + return; + } + + genbgtz_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgtz_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZ_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZ_IDLE, 1); + return; + } + + genbgtz_test(state); + gentest_idle(state); + genbgtz(state); +#endif +} + +void genaddi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[8]); +#endif +#ifdef INTERPRET_ADDI + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADDI, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_32_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt, rs); + add_reg32_imm32(state, rt,(int)state->dst->f.i.immediate); +#endif +} + +void genaddiu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[9]); +#endif +#ifdef INTERPRET_ADDIU + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADDIU, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + int rt = allocate_register_32_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_reg32(state, rt, rs); + add_reg32_imm32(state, rt,(int)state->dst->f.i.immediate); +#endif +} + +void genslti(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[10]); +#endif +#ifdef INTERPRET_SLTI + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLTI, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *) state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *) state->dst->f.i.rt); + int imm = (int) state->dst->f.i.immediate; + + cmp_reg64_imm32(state, rs, imm); + setl_reg8(state, rt); + and_reg64_imm8(state, rt, 1); +#endif +} + +void gensltiu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[11]); +#endif +#ifdef INTERPRET_SLTIU + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLTIU, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *)state->dst->f.i.rt); + int imm = (int) state->dst->f.i.immediate; + + cmp_reg64_imm32(state, rs, imm); + setb_reg8(state, rt); + and_reg64_imm8(state, rt, 1); +#endif +} + +void genandi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[12]); +#endif +#ifdef INTERPRET_ANDI + gencallinterp(state, (unsigned long long)state->current_instruction_table.ANDI, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *)state->dst->f.i.rt); + + mov_reg64_reg64(state, rt, rs); + and_reg64_imm32(state, rt, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genori(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[13]); +#endif +#ifdef INTERPRET_ORI + gencallinterp(state, (unsigned long long)state->current_instruction_table.ORI, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *) state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *) state->dst->f.i.rt); + + mov_reg64_reg64(state, rt, rs); + or_reg64_imm32(state, rt, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genxori(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[14]); +#endif +#ifdef INTERPRET_XORI + gencallinterp(state, (unsigned long long)state->current_instruction_table.XORI, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *)state->dst->f.i.rt); + + mov_reg64_reg64(state, rt, rs); + xor_reg64_imm32(state, rt, (unsigned short)state->dst->f.i.immediate); +#endif +} + +void genlui(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[15]); +#endif +#ifdef INTERPRET_LUI + gencallinterp(state, (unsigned long long)state->current_instruction_table.LUI, 0); +#else + int rt = allocate_register_32_w(state, (unsigned int *)state->dst->f.i.rt); + + mov_reg32_imm32(state, rt, (unsigned int)state->dst->f.i.immediate << 16); +#endif +} + +void gentestl(usf_state_t * state) +{ + cmp_m32rel_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + jump_start_rel32(state); + + gendelayslot(state); + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt(state, (unsigned long long) (state->dst + (state->dst-1)->f.i.immediate)); + jmp(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + + jump_end_rel32(state); + + genupdate_count(state, state->dst->addr-4); + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + 4); + gencheck_interupt(state, (unsigned long long) (state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeql(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[16]); +#endif +#ifdef INTERPRET_BEQL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL, 1); + return; + } + + genbeq_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void gentestl_out(usf_state_t * state) +{ + cmp_m32rel_imm32(state, (unsigned int *)(&state->branch_taken), 0); + je_near_rj(state, 0); + jump_start_rel32(state); + + gendelayslot(state); + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + (state->dst-1)->f.i.immediate*4); + gencheck_interupt_out(state, state->dst->addr + (state->dst-1)->f.i.immediate*4); + mov_m32rel_imm32(state, &state->jump_to_address, state->dst->addr + (state->dst-1)->f.i.immediate*4); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) jump_to_func); + free_register(state, RP0); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); + + jump_end_rel32(state); + + genupdate_count(state, state->dst->addr-4); + mov_m32rel_imm32(state, (void*)(&state->last_addr), state->dst->addr + 4); + gencheck_interupt(state, (unsigned long long) (state->dst + 1)); + jmp(state, state->dst->addr + 4); +} + +void genbeql_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[16]); +#endif +#ifdef INTERPRET_BEQL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL_OUT, 1); + return; + } + + genbeq_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbeql_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BEQL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BEQL_IDLE, 1); + return; + } + + genbeq_test(state); + gentest_idle(state); + genbeql(state); +#endif +} + +void genbnel(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[17]); +#endif +#ifdef INTERPRET_BNEL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL, 1); + return; + } + + genbne_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbnel_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[17]); +#endif +#ifdef INTERPRET_BNEL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL_OUT, 1); + return; + } + + genbne_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbnel_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BNEL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BNEL_IDLE, 1); + return; + } + + genbne_test(state); + gentest_idle(state); + genbnel(state); +#endif +} + +void genblezl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[18]); +#endif +#ifdef INTERPRET_BLEZL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL, 1); + return; + } + + genblez_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genblezl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[18]); +#endif +#ifdef INTERPRET_BLEZL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL_OUT, 1); + return; + } + + genblez_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genblezl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLEZL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLEZL_IDLE, 1); + return; + } + + genblez_test(state); + gentest_idle(state); + genblezl(state); +#endif +} + +void genbgtzl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[19]); +#endif +#ifdef INTERPRET_BGTZL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL, 1); + return; + } + + genbgtz_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgtzl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[19]); +#endif +#ifdef INTERPRET_BGTZL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL_OUT, 1); + return; + } + + genbgtz_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgtzl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGTZL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGTZL_IDLE, 1); + return; + } + + genbgtz_test(state); + gentest_idle(state); + genbgtzl(state); +#endif +} + +void gendaddi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[20]); +#endif +#ifdef INTERPRET_DADDI + gencallinterp(state, (unsigned long long)state->current_instruction_table.DADDI, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *)state->dst->f.i.rt); + + mov_reg64_reg64(state, rt, rs); + add_reg64_imm32(state, rt, (int) state->dst->f.i.immediate); +#endif +} + +void gendaddiu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[21]); +#endif +#ifdef INTERPRET_DADDIU + gencallinterp(state, (unsigned long long)state->current_instruction_table.DADDIU, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + int rt = allocate_register_64_w(state, (unsigned long long *)state->dst->f.i.rt); + + mov_reg64_reg64(state, rt, rs); + add_reg64_imm32(state, rt, (int) state->dst->f.i.immediate); +#endif +} + +void genldl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[22]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.LDL, 0); +} + +void genldr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[23]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.LDR, 0); +} + +void genlb(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[24]); +#endif + int gpr1, gpr2, base1, base2 = 0; +#ifdef INTERPRET_LB + gencallinterp(state, (unsigned long long)state->current_instruction_table.LB, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmemb); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdramb); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + je_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr2, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr2); + unlock_register(state, RP0); + movsx_xreg32_m8rel(state, gpr1, (unsigned char *)state->dst->f.i.rt); + jmp_imm_short(state, 24); + + jump_end_rel8(state); + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + xor_reg8_imm8(state, gpr2, 3); // 4 + movsx_reg32_8preg64preg64(state, gpr1, gpr2, base1); // 4 + + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 0); +#endif +} + +void genlh(usf_state_t * state) +{ + int gpr1, gpr2, base1, base2 = 0; +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[25]); +#endif +#ifdef INTERPRET_LH + gencallinterp(state, (unsigned long long)state->current_instruction_table.LH, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmemh); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdramh); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + je_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr2, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr2); + unlock_register(state, RP0); + movsx_xreg32_m16rel(state, gpr1, (unsigned short *)state->dst->f.i.rt); + jmp_imm_short(state, 24); + + jump_end_rel8(state); + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + xor_reg8_imm8(state, gpr2, 2); // 4 + movsx_reg32_16preg64preg64(state, gpr1, gpr2, base1); // 4 + + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 0); +#endif +} + +void genlwl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[27]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.LWL, 0); +} + +void genlw(usf_state_t * state) +{ + int gpr1, gpr2, base1, base2 = 0; +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[26]); +#endif +#ifdef INTERPRET_LW + gencallinterp(state, (unsigned long long)state->current_instruction_table.LW, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmem); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdram); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + jne_rj(state, 21); + + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + mov_reg32_preg64preg64(state, gpr1, gpr2, base1); // 3 + jmp_imm_short(state, 0); // 2 + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr1); + unlock_register(state, RP0); + mov_xreg32_m32rel(state, gpr1, (unsigned int *)(state->dst->f.i.rt)); + + jump_end_rel8(state); + + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 0); // set gpr1 state as dirty, and bound to r4300 reg RT +#endif +} + +void genlbu(usf_state_t * state) +{ + int gpr1, gpr2, base1, base2 = 0; +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[28]); +#endif +#ifdef INTERPRET_LBU + gencallinterp(state, (unsigned long long)state->current_instruction_table.LBU, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmemb); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdramb); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + je_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr2, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr2); + unlock_register(state, RP0); + mov_xreg32_m32rel(state, gpr1, (unsigned int *)state->dst->f.i.rt); + jmp_imm_short(state, 23); + + jump_end_rel8(state); + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + xor_reg8_imm8(state, gpr2, 3); // 4 + mov_reg32_preg64preg64(state, gpr1, gpr2, base1); // 3 + + and_reg32_imm32(state, gpr1, 0xFF); + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 0); +#endif +} + +void genlhu(usf_state_t * state) +{ + int gpr1, gpr2, base1, base2 = 0; +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[29]); +#endif +#ifdef INTERPRET_LHU + gencallinterp(state, (unsigned long long)state->current_instruction_table.LHU, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmemh); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdramh); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + je_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr2, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr2); + mov_xreg32_m32rel(state, gpr1, (unsigned int *)state->dst->f.i.rt); + jmp_imm_short(state, 23); + + jump_end_rel8(state); + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + xor_reg8_imm8(state, gpr2, 2); // 4 + mov_reg32_preg64preg64(state, gpr1, gpr2, base1); // 3 + + and_reg32_imm32(state, gpr1, 0xFFFF); + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 0); +#endif +} + +void genlwr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[31]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.LWR, 0); +} + +void genlwu(usf_state_t * state) +{ + int gpr1, gpr2, base1, base2 = 0; +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[30]); +#endif +#ifdef INTERPRET_LWU + gencallinterp(state, (unsigned long long)state->current_instruction_table.LWU, 0); +#else + free_registers_move_start(state); + + lock_register(state, RP0); + + ld_register_alloc(state, &gpr1, &gpr2, &base1, &base2); + + mov_reg64_imm64(state, base1, (unsigned long long) state->readmem); + if(state->fast_memory) + { + and_reg32_imm32(state, gpr1, 0xDF800000); + cmp_reg32_imm32(state, gpr1, 0x80000000); + } + else + { + mov_reg64_imm64(state, base2, (unsigned long long) read_rdram); + shr_reg32_imm8(state, gpr1, 16); + mov_reg64_preg64x8preg64(state, gpr1, gpr1, base1); + cmp_reg64_reg64(state, gpr1, base2); + } + je_rj(state, 0); + jump_start_rel8(state); + + mov_reg64_imm64(state, gpr1, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), gpr1); + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), gpr2); + mov_reg64_imm64(state, gpr1, (unsigned long long) state->dst->f.i.rt); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), gpr1); + shr_reg32_imm8(state, gpr2, 16); + mov_reg64_preg64x8preg64(state, gpr2, gpr2, base1); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, gpr2); + unlock_register(state, RP0); + mov_xreg32_m32rel(state, gpr1, (unsigned int *)state->dst->f.i.rt); + jmp_imm_short(state, 19); + + jump_end_rel8(state); + mov_reg64_imm64(state, base1, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, gpr2, 0x7FFFFF); // 6 + mov_reg32_preg64preg64(state, gpr1, gpr2, base1); // 3 + + set_register_state(state, gpr1, (unsigned int*)state->dst->f.i.rt, 1, 1); +#endif +} + +void gensb(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[32]); +#endif +#ifdef INTERPRET_SB + gencallinterp(state, (unsigned long long)state->current_instruction_table.SB, 0); +#else + free_registers_move_start(state); + + mov_xreg8_m8rel(state, CL, (unsigned char *)state->dst->f.i.rt); + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writememb); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdramb); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 52); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m8rel_xreg8(state, (unsigned char *)(&state->cpu_byte), CL); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 25); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 3); // 4 + mov_preg64preg64_reg8(state, RBX, RSI, CL); // 3 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void gensh(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[33]); +#endif +#ifdef INTERPRET_SH + gencallinterp(state, (unsigned long long)state->current_instruction_table.SH, 0); +#else + free_registers_move_start(state); + + mov_xreg16_m16rel(state, CX, (unsigned short *)state->dst->f.i.rt); + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writememh); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdramh); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 53); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m16rel_xreg16(state, (unsigned short *)(&state->cpu_hword), CX); // 8 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 26); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + xor_reg8_imm8(state, BL, 2); // 4 + mov_preg64preg64_reg16(state, RBX, RSI, CX); // 4 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void genswl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[35]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.SWL, 0); +} + +void gensw(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[34]); +#endif +#ifdef INTERPRET_SW + gencallinterp(state, (unsigned long long)state->current_instruction_table.SW, 0); +#else + free_registers_move_start(state); + + mov_xreg32_m32rel(state, ECX, (unsigned int *)state->dst->f.i.rt); + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writemem); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdram); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 52); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_word), ECX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 21); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg64preg64_reg32(state, RBX, RSI, ECX); // 3 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void gensdl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[37]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.SDL, 0); +} + +void gensdr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[38]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.SDR, 0); +} + +void genswr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[36]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.SWR, 0); +} + +void gencheck_cop1_unusable(usf_state_t * state) +{ + free_registers_move_start(state); + + test_m32rel_imm32(state, (unsigned int*)&state->g_cp0_regs[CP0_STATUS_REG], 0x20000000); + jne_rj(state, 0); + jump_start_rel8(state); + + gencallinterp(state, (unsigned long long)check_cop1_unusable, 0); + + jump_end_rel8(state); +} + +void genlwc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[39]); +#endif +#ifdef INTERPRET_LWC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.LWC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->readmem); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) read_rdram); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 52); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_xreg64_m64rel(state, RDX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.lf.ft])); // 7 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), RDX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + jmp_imm_short(state, 28); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg32_preg64preg64(state, EAX, RBX, RSI); // 3 + mov_xreg64_m64rel(state, RBX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.lf.ft])); // 7 + mov_preg64_reg32(state, RBX, EAX); // 2 +#endif +} + +void genldc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[40]); +#endif +#ifdef INTERPRET_LDC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.LDC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->readmemd); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) read_rdramd); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 52); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_xreg64_m64rel(state, RDX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.lf.ft])); // 7 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), RDX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + jmp_imm_short(state, 39); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_reg64_preg64preg64(state, RAX, RBX, RSI); // 4 + mov_xreg64_m64rel(state, RBX, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.lf.ft])); // 7 + mov_preg64pimm32_reg32(state, RBX, 4, EAX); // 6 + shr_reg64_imm8(state, RAX, 32); // 4 + mov_preg64_reg32(state, RBX, EAX); // 2 +#endif +} + +void gencache(usf_state_t * state) +{ + (void)state; +} + +void genld(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[41]); +#endif +#ifdef INTERPRET_LD + gencallinterp(state, (unsigned long long)state->current_instruction_table.LD, 0); +#else + free_registers_move_start(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->readmemd); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) read_rdramd); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 62); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_reg64_imm64(state, RAX, (unsigned long long) state->dst->f.i.rt); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->rdword), RAX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg64_m64rel(state, RAX, (unsigned long long *)(state->dst->f.i.rt)); // 7 + jmp_imm_short(state, 33); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + + mov_reg32_preg64preg64(state, EAX, RBX, RSI); // 3 + mov_reg32_preg64preg64pimm32(state, EBX, RBX, RSI, 4); // 7 + shl_reg64_imm8(state, RAX, 32); // 4 + or_reg64_reg64(state, RAX, RBX); // 3 + + set_register_state(state, RAX, (unsigned int*)state->dst->f.i.rt, 1, 1); +#endif +} + +void genswc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[43]); +#endif +#ifdef INTERPRET_SWC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.SWC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_xreg64_m64rel(state, RDX, (unsigned long long *)(&state->reg_cop1_simple[state->dst->f.lf.ft])); + mov_reg32_preg64(state, ECX, RDX); + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writemem); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdram); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 52); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_word), ECX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 21); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg64preg64_reg32(state, RBX, RSI, ECX); // 3 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void gensdc1(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[44]); +#endif +#ifdef INTERPRET_SDC1 + gencallinterp(state, (unsigned long long)state->current_instruction_table.SDC1, 0); +#else + gencheck_cop1_unusable(state); + + mov_xreg64_m64rel(state, RSI, (unsigned long long *)(&state->reg_cop1_double[state->dst->f.lf.ft])); + mov_reg32_preg64(state, ECX, RSI); + mov_reg32_preg64pimm32(state, EDX, RSI, 4); + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->reg[state->dst->f.lf.base])); + add_eax_imm32(state, (int)state->dst->f.lf.offset); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writememd); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdramd); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 59); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_dword), ECX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_dword)+1, EDX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 28); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg64preg64pimm32_reg32(state, RBX, RSI, 4, ECX); // 7 + mov_preg64preg64_reg32(state, RBX, RSI, EDX); // 3 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void gensd(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[45]); +#endif +#ifdef INTERPRET_SD + gencallinterp(state, (unsigned long long)state->current_instruction_table.SD, 0); +#else + free_registers_move_start(state); + + mov_xreg32_m32rel(state, ECX, (unsigned int *)state->dst->f.i.rt); + mov_xreg32_m32rel(state, EDX, ((unsigned int *)state->dst->f.i.rt)+1); + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + add_eax_imm32(state, (int)state->dst->f.i.immediate); + mov_reg32_reg32(state, EBX, EAX); + mov_reg64_imm64(state, RSI, (unsigned long long) state->writememd); + if(state->fast_memory) + { + and_eax_imm32(state, 0xDF800000); + cmp_eax_imm32(state, 0x80000000); + } + else + { + mov_reg64_imm64(state, RDI, (unsigned long long) write_rdramd); + shr_reg32_imm8(state, EAX, 16); + mov_reg64_preg64x8preg64(state, RAX, RAX, RSI); + cmp_reg64_reg64(state, RAX, RDI); + } + je_rj(state, 59); + + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); // 10 + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->address), EBX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_dword), ECX); // 7 + mov_m32rel_xreg32(state, (unsigned int *)(&state->cpu_dword)+1, EDX); // 7 + shr_reg32_imm8(state, EBX, 16); // 3 + mov_reg64_preg64x8preg64(state, RBX, RBX, RSI); // 4 + mov_reg64_reg64(state, RP0, 15); // 3 + call_reg64(state, RBX); // 2 + mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->address)); // 7 + jmp_imm_short(state, 28); // 2 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->g_rdram); // 10 + mov_reg32_reg32(state, EAX, EBX); // 2 + and_reg32_imm32(state, EBX, 0x7FFFFF); // 6 + mov_preg64preg64pimm32_reg32(state, RBX, RSI, 4, ECX); // 7 + mov_preg64preg64_reg32(state, RBX, RSI, EDX); // 3 + + mov_reg64_imm64(state, RSI, (unsigned long long) state->invalid_code); + mov_reg32_reg32(state, EBX, EAX); + shr_reg32_imm8(state, EBX, 12); + cmp_preg64preg64_imm8(state, RBX, RSI, 0); + jne_rj(state, 65); + + mov_reg64_imm64(state, RDI, (unsigned long long) state->blocks); // 10 + mov_reg32_reg32(state, ECX, EBX); // 2 + mov_reg64_preg64x8preg64(state, RBX, RBX, RDI); // 4 + mov_reg64_preg64pimm32(state, RBX, RBX, (int) offsetof(precomp_block, block)); // 7 + mov_reg64_imm64(state, RDI, (unsigned long long) state->current_instruction_table.NOTCOMPILED); // 10 + and_eax_imm32(state, 0xFFF); // 5 + shr_reg32_imm8(state, EAX, 2); // 3 + mov_reg32_imm32(state, EDX, sizeof(precomp_instr)); // 5 + mul_reg32(state, EDX); // 2 + mov_reg64_preg64preg64pimm32(state, RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8 + cmp_reg64_reg64(state, RAX, RDI); // 3 + je_rj(state, 4); // 2 + mov_preg64preg64_imm8(state, RCX, RSI, 1); // 4 +#endif +} + +void genll(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[42]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.LL, 0); +} + +void gensc(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[46]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.SC, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gregimm.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gregimm.c new file mode 100644 index 000000000..bb74308bf --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gregimm.c @@ -0,0 +1,611 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gregimm.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" + +#include "memory/memory.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +static void genbltz_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (rs_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + + cmp_reg32_imm32(state, rs, 0); + setl_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rs_64bit == -1) + { + cmp_m32rel_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + setl_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + + cmp_reg64_imm8(state, rs, 0); + setl_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +void genbltz(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[47]); +#endif +#ifdef INTERPRET_BLTZ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ, 1); + return; + } + + genbltz_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbltz_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[47]); +#endif +#ifdef INTERPRET_BLTZ_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ_OUT, 1); + return; + } + + genbltz_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbltz_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZ_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZ_IDLE, 1); + return; + } + + genbltz_test(state); + gentest_idle(state); + genbltz(state); +#endif +} + +static void genbgez_test(usf_state_t * state) +{ + int rs_64bit = is64(state, (unsigned int *)state->dst->f.i.rs); + + if (rs_64bit == 0) + { + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.i.rs); + cmp_reg32_imm32(state, rs, 0); + setge_m8rel(state, (unsigned char *) &state->branch_taken); + } + else if (rs_64bit == -1) + { + cmp_m32rel_imm32(state, ((unsigned int *)state->dst->f.i.rs)+1, 0); + setge_m8rel(state, (unsigned char *) &state->branch_taken); + } + else + { + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.i.rs); + cmp_reg64_imm8(state, rs, 0); + setge_m8rel(state, (unsigned char *) &state->branch_taken); + } +} + +void genbgez(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[48]); +#endif +#ifdef INTERPRET_BGEZ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ, 1); + return; + } + + genbgez_test(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgez_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[48]); +#endif +#ifdef INTERPRET_BGEZ_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ_OUT, 1); + return; + } + + genbgez_test(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgez_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZ_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZ_IDLE, 1); + return; + } + + genbgez_test(state); + gentest_idle(state); + genbgez(state); +#endif +} + +void genbltzl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[49]); +#endif +#ifdef INTERPRET_BLTZL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL, 1); + return; + } + + genbltz_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbltzl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[49]); +#endif +#ifdef INTERPRET_BLTZL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL_OUT, 1); + return; + } + + genbltz_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbltzl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZL_IDLE, 1); + return; + } + + genbltz_test(state); + gentest_idle(state); + genbltzl(state); +#endif +} + +void genbgezl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[50]); +#endif +#ifdef INTERPRET_BGEZL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL, 1); + return; + } + + genbgez_test(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgezl_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[50]); +#endif +#ifdef INTERPRET_BGEZL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL_OUT, 1); + return; + } + + genbgez_test(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgezl_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZL_IDLE, 1); + return; + } + + genbgez_test(state); + gentest_idle(state); + genbgezl(state); +#endif +} + +static void genbranchlink(usf_state_t * state) +{ + int r31_64bit = is64(state, (unsigned int*)&state->reg[31]); + + if (r31_64bit == 0) + { + int r31 = allocate_register_32_w(state, (unsigned int *)&state->reg[31]); + + mov_reg32_imm32(state, r31, state->dst->addr+8); + } + else if (r31_64bit == -1) + { + mov_m32rel_imm32(state, (unsigned int *)&state->reg[31], state->dst->addr + 8); + if (state->dst->addr & 0x80000000) + mov_m32rel_imm32(state, ((unsigned int *)&state->reg[31])+1, 0xFFFFFFFF); + else + mov_m32rel_imm32(state, ((unsigned int *)&state->reg[31])+1, 0); + } + else + { + int r31 = allocate_register_64_w(state, (unsigned long long *)&state->reg[31]); + + mov_reg32_imm32(state, r31, state->dst->addr+8); + movsxd_reg64_reg32(state, r31, r31); + } +} + +void genbltzal(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[51]); +#endif +#ifdef INTERPRET_BLTZAL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbltzal_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[51]); +#endif +#ifdef INTERPRET_BLTZAL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL_OUT, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbltzal_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZAL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZAL_IDLE, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gentest_idle(state); + genbltzal(state); +#endif +} + +void genbgezal(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[52]); +#endif +#ifdef INTERPRET_BGEZAL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gendelayslot(state); + gentest(state); +#endif +} + +void genbgezal_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[52]); +#endif +#ifdef INTERPRET_BGEZAL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL_OUT, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gendelayslot(state); + gentest_out(state); +#endif +} + +void genbgezal_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZAL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZAL_IDLE, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gentest_idle(state); + genbgezal(state); +#endif +} + +void genbltzall(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[53]); +#endif +#ifdef INTERPRET_BLTZALL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbltzall_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[53]); +#endif +#ifdef INTERPRET_BLTZALL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL_OUT, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbltzall_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BLTZALL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BLTZALL_IDLE, 1); + return; + } + + genbltz_test(state); + genbranchlink(state); + gentest_idle(state); + genbltzall(state); +#endif +} + +void genbgezall(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[54]); +#endif +#ifdef INTERPRET_BGEZALL + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl(state); +#endif +} + +void genbgezall_out(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[54]); +#endif +#ifdef INTERPRET_BGEZALL_OUT + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL_OUT, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL_OUT, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + free_all_registers(state); + gentestl_out(state); +#endif +} + +void genbgezall_idle(usf_state_t * state) +{ +#ifdef INTERPRET_BGEZALL_IDLE + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL_IDLE, 1); +#else + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.BGEZALL_IDLE, 1); + return; + } + + genbgez_test(state); + genbranchlink(state); + gentest_idle(state); + genbgezall(state); +#endif +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gspecial.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gspecial.c new file mode 100644 index 000000000..bdfe3aa53 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gspecial.c @@ -0,0 +1,1078 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gspecial.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/cp0.h" +#include "r4300/exception.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +#if !defined(offsetof) +# define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) +#endif + +void gensll(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[55]); +#endif +#ifdef INTERPRET_SLL + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLL, 0); +#else + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + shl_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensrl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[56]); +#endif +#ifdef INTERPRET_SRL + gencallinterp(state, (unsigned long long)state->current_instruction_table.SRL, 0); +#else + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + shr_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensra(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[57]); +#endif +#ifdef INTERPRET_SRA + gencallinterp(state, (unsigned long long)state->current_instruction_table.SRA, 0); +#else + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + mov_reg32_reg32(state, rd, rt); + sar_reg32_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gensllv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[58]); +#endif +#ifdef INTERPRET_SLLV + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLLV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + shl_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + shl_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensrlv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[59]); +#endif +#ifdef INTERPRET_SRLV + gencallinterp(state, (unsigned long long)state->current_instruction_table.SRLV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + shr_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + shr_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void gensrav(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[60]); +#endif +#ifdef INTERPRET_SRAV + gencallinterp(state, (unsigned long long)state->current_instruction_table.SRAV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(state, rd, rt); + sar_reg32_cl(state, rd); + } + else + { + int temp = lru_register(state); + free_register(state, temp); + mov_reg32_reg32(state, temp, rt); + sar_reg32_cl(state, temp); + mov_reg32_reg32(state, rd, temp); + } +#endif +} + +void genjr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[61]); +#endif +#ifdef INTERPRET_JR + gencallinterp(state, (unsigned long long)state->current_instruction_table.JR, 1); +#else + unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); + unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); + unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.JR, 1); + return; + } + + free_registers_move_start(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.i.rs); + mov_m32rel_xreg32(state, (unsigned int *)&state->local_rs, EAX); + + gendelayslot(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)&state->local_rs); + mov_m32rel_xreg32(state, (unsigned int *)&state->last_addr, EAX); + + gencheck_interupt_reg(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)&state->local_rs); + mov_reg32_reg32(state, EBX, EAX); + and_eax_imm32(state, 0xFFFFF000); + cmp_eax_imm32(state, state->dst_block->start & 0xFFFFF000); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32rel_xreg32(state, &state->jump_to_address, EBX); + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) jump_to_func); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); /* will never return from call */ + + jump_end_rel32(state); + + mov_reg64_imm64(state, RSI, (unsigned long long) state->dst_block->block); + mov_reg32_reg32(state, EAX, EBX); + sub_eax_imm32(state, state->dst_block->start); + shr_reg32_imm8(state, EAX, 2); + mul_m32rel(state, (unsigned int *)(&state->precomp_instr_size)); + + mov_reg32_preg64preg64pimm32(state, EBX, RAX, RSI, diff_need); + cmp_reg32_imm32(state, EBX, 1); + jne_rj(state, 11); + + add_reg32_imm32(state, EAX, diff_wrap); // 6 + add_reg64_reg64(state, RAX, RSI); // 3 + jmp_reg64(state, RAX); // 2 + + mov_reg32_preg64preg64pimm32(state, EBX, RAX, RSI, diff); + mov_rax_memoffs64(state, (unsigned long long *) &state->dst_block->code); + add_reg64_reg64(state, RAX, RBX); + jmp_reg64(state, RAX); +#endif +} + +void genjalr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[62]); +#endif +#ifdef INTERPRET_JALR + gencallinterp(state, (unsigned long long)state->current_instruction_table.JALR, 0); +#else + unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); + unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); + unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); + + if (((state->dst->addr & 0xFFF) == 0xFFC && + (state->dst->addr < 0x80000000 || state->dst->addr >= 0xC0000000))||state->no_compiled_jump) + { + gencallinterp(state, (unsigned long long)state->current_instruction_table.JALR, 1); + return; + } + + free_registers_move_start(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)state->dst->f.r.rs); + mov_m32rel_xreg32(state, (unsigned int *)&state->local_rs, EAX); + + gendelayslot(state); + + mov_m32rel_imm32(state, (unsigned int *)(state->dst-1)->f.r.rd, state->dst->addr+4); + if ((state->dst->addr+4) & 0x80000000) + mov_m32rel_imm32(state, ((unsigned int *)(state->dst-1)->f.r.rd)+1, 0xFFFFFFFF); + else + mov_m32rel_imm32(state, ((unsigned int *)(state->dst-1)->f.r.rd)+1, 0); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)&state->local_rs); + mov_m32rel_xreg32(state, (unsigned int *)&state->last_addr, EAX); + + gencheck_interupt_reg(state); + + mov_xreg32_m32rel(state, EAX, (unsigned int *)&state->local_rs); + mov_reg32_reg32(state, EBX, EAX); + and_eax_imm32(state, 0xFFFFF000); + cmp_eax_imm32(state, state->dst_block->start & 0xFFFFF000); + je_near_rj(state, 0); + + jump_start_rel32(state); + + mov_m32rel_xreg32(state, &state->jump_to_address, EBX); + mov_reg64_imm64(state, RAX, (unsigned long long) (state->dst+1)); + mov_m64rel_xreg64(state, (unsigned long long *)(&state->PC), RAX); + mov_reg64_imm64(state, RAX, (unsigned long long) jump_to_func); + mov_reg64_reg64(state, RP0, 15); + call_reg64(state, RAX); /* will never return from call */ + + jump_end_rel32(state); + + mov_reg64_imm64(state, RSI, (unsigned long long) state->dst_block->block); + mov_reg32_reg32(state, EAX, EBX); + sub_eax_imm32(state, state->dst_block->start); + shr_reg32_imm8(state, EAX, 2); + mul_m32rel(state, (unsigned int *)(&state->precomp_instr_size)); + + mov_reg32_preg64preg64pimm32(state, EBX, RAX, RSI, diff_need); + cmp_reg32_imm32(state, EBX, 1); + jne_rj(state, 11); + + add_reg32_imm32(state, EAX, diff_wrap); // 6 + add_reg64_reg64(state, RAX, RSI); // 3 + jmp_reg64(state, RAX); // 2 + + mov_reg32_preg64preg64pimm32(state, EBX, RAX, RSI, diff); + mov_rax_memoffs64(state, (unsigned long long *) &state->dst_block->code); + add_reg64_reg64(state, RAX, RBX); + jmp_reg64(state, RAX); +#endif +} + +void gensyscall(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[63]); +#endif +#ifdef INTERPRET_SYSCALL + gencallinterp(state, (unsigned long long)state->current_instruction_table.SYSCALL, 0); +#else + free_registers_move_start(state); + + mov_m32rel_imm32(state, &state->g_cp0_regs[CP0_CAUSE_REG], 8 << 2); + gencallinterp(state, (unsigned long long)exception_general, 0); +#endif +} + +void gensync(usf_state_t * state) +{ + (void)state; +} + +void genmfhi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[64]); +#endif +#ifdef INTERPRET_MFHI + gencallinterp(state, (unsigned long long)state->current_instruction_table.MFHI, 0); +#else + int rd = allocate_register_64_w(state, (unsigned long long *) state->dst->f.r.rd); + int _hi = allocate_register_64(state, (unsigned long long *) &state->hi); + + mov_reg64_reg64(state, rd, _hi); +#endif +} + +void genmthi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[65]); +#endif +#ifdef INTERPRET_MTHI + gencallinterp(state, (unsigned long long)state->current_instruction_table.MTHI, 0); +#else + int _hi = allocate_register_64_w(state, (unsigned long long *) &state->hi); + int rs = allocate_register_64(state, (unsigned long long *) state->dst->f.r.rs); + + mov_reg64_reg64(state, _hi, rs); +#endif +} + +void genmflo(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[66]); +#endif +#ifdef INTERPRET_MFLO + gencallinterp(state, (unsigned long long)state->current_instruction_table.MFLO, 0); +#else + int rd = allocate_register_64_w(state, (unsigned long long *) state->dst->f.r.rd); + int _lo = allocate_register_64(state, (unsigned long long *) &state->lo); + + mov_reg64_reg64(state, rd, _lo); +#endif +} + +void genmtlo(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[67]); +#endif +#ifdef INTERPRET_MTLO + gencallinterp(state, (unsigned long long)state->current_instruction_table.MTLO, 0); +#else + int _lo = allocate_register_64_w(state, (unsigned long long *)&state->lo); + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + + mov_reg64_reg64(state, _lo, rs); +#endif +} + +void gendsllv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[68]); +#endif +#ifdef INTERPRET_DSLLV + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSLLV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(state, rd, rt); + shl_reg64_cl(state, rd); + } + else + { + int temp; + temp = lru_register(state); + free_register(state, temp); + + mov_reg64_reg64(state, temp, rt); + shl_reg64_cl(state, temp); + mov_reg64_reg64(state, rd, temp); + } +#endif +} + +void gendsrlv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[69]); +#endif +#ifdef INTERPRET_DSRLV + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRLV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(state, rd, rt); + shr_reg64_cl(state, rd); + } + else + { + int temp; + temp = lru_register(state); + free_register(state, temp); + + mov_reg64_reg64(state, temp, rt); + shr_reg64_cl(state, temp); + mov_reg64_reg64(state, rd, temp); + } +#endif +} + +void gendsrav(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[70]); +#endif +#ifdef INTERPRET_DSRAV + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRAV, 0); +#else + int rt, rd; + allocate_register_32_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); + + rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(state, rd, rt); + sar_reg64_cl(state, rd); + } + else + { + int temp; + temp = lru_register(state); + free_register(state, temp); + + mov_reg64_reg64(state, temp, rt); + sar_reg64_cl(state, temp); + mov_reg64_reg64(state, rd, temp); + } +#endif +} + +void genmult(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[71]); +#endif +#ifdef INTERPRET_MULT + gencallinterp(state, (unsigned long long)state->current_instruction_table.MULT, 0); +#else + int rs, rt; + allocate_register_32_manually_w(state, EAX, (unsigned int *)&state->lo); /* these must be done first so they are not assigned by allocate_register() */ + allocate_register_32_manually_w(state, EDX, (unsigned int *)&state->hi); + rs = allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register_32(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_reg32(state, EAX, rs); + imul_reg32(state, rt); +#endif +} + +void genmultu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[72]); +#endif +#ifdef INTERPRET_MULTU + gencallinterp(state, (unsigned long long)state->current_instruction_table.MULTU, 0); +#else + int rs, rt; + allocate_register_32_manually_w(state, EAX, (unsigned int *)&state->lo); + allocate_register_32_manually_w(state, EDX, (unsigned int *)&state->hi); + rs = allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register_32(state, (unsigned int*)state->dst->f.r.rt); + mov_reg32_reg32(state, EAX, rs); + mul_reg32(state, rt); +#endif +} + +void gendiv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[73]); +#endif +#ifdef INTERPRET_DIV + gencallinterp(state, (unsigned long long)state->current_instruction_table.DIV, 0); +#else + int rs, rt; + allocate_register_32_manually_w(state, EAX, (unsigned int *)&state->lo); + allocate_register_32_manually_w(state, EDX, (unsigned int *)&state->hi); + rs = allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register_32(state, (unsigned int*)state->dst->f.r.rt); + cmp_reg32_imm32(state, rt, 0); + je_rj(state, (rs == EAX ? 0 : 2) + 1 + 2); + mov_reg32_reg32(state, EAX, rs); // 0 or 2 + cdq(state); // 1 + idiv_reg32(state, rt); // 2 +#endif +} + +void gendivu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[74]); +#endif +#ifdef INTERPRET_DIVU + gencallinterp(state, (unsigned long long)state->current_instruction_table.DIVU, 0); +#else + int rs, rt; + allocate_register_32_manually_w(state, EAX, (unsigned int *)&state->lo); + allocate_register_32_manually_w(state, EDX, (unsigned int *)&state->hi); + rs = allocate_register_32(state, (unsigned int*)state->dst->f.r.rs); + rt = allocate_register_32(state, (unsigned int*)state->dst->f.r.rt); + cmp_reg32_imm32(state, rt, 0); + je_rj(state, (rs == EAX ? 0 : 2) + 2 + 2); + mov_reg32_reg32(state, EAX, rs); // 0 or 2 + xor_reg32_reg32(state, EDX, EDX); // 2 + div_reg32(state, rt); // 2 +#endif +} + +void gendmult(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[75]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.DMULT, 0); +} + +void gendmultu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[76]); +#endif +#ifdef INTERPRET_DMULTU + gencallinterp(state, (unsigned long long)state->current_instruction_table.DMULTU, 0); +#else + free_registers_move_start(state); + + mov_xreg64_m64rel(state, RAX, (unsigned long long *) state->dst->f.r.rs); + mov_xreg64_m64rel(state, RDX, (unsigned long long *) state->dst->f.r.rt); + mul_reg64(state, RDX); + mov_m64rel_xreg64(state, (unsigned long long *) &state->lo, RAX); + mov_m64rel_xreg64(state, (unsigned long long *) &state->hi, RDX); +#endif +} + +void genddiv(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[77]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.DDIV, 0); +} + +void genddivu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[78]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.DDIVU, 0); +} + +void genadd(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[79]); +#endif +#ifdef INTERPRET_ADD + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADD, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rs == rd) + add_reg32_reg32(state, rd, rt); + else if (rt == rd) + add_reg32_reg32(state, rd, rs); + else + { + mov_reg32_reg32(state, rd, rs); + add_reg32_reg32(state, rd, rt); + } +#endif +} + +void genaddu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[80]); +#endif +#ifdef INTERPRET_ADDU + gencallinterp(state, (unsigned long long)state->current_instruction_table.ADDU, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rs == rd) + add_reg32_reg32(state, rd, rt); + else if (rt == rd) + add_reg32_reg32(state, rd, rs); + else + { + mov_reg32_reg32(state, rd, rs); + add_reg32_reg32(state, rd, rt); + } +#endif +} + +void gensub(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[81]); +#endif +#ifdef INTERPRET_SUB + gencallinterp(state, (unsigned long long)state->current_instruction_table.SUB, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rs == rd) + sub_reg32_reg32(state, rd, rt); + else if (rt == rd) + { + neg_reg32(state, rd); + add_reg32_reg32(state, rd, rs); + } + else + { + mov_reg32_reg32(state, rd, rs); + sub_reg32_reg32(state, rd, rt); + } +#endif +} + +void gensubu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[82]); +#endif +#ifdef INTERPRET_SUBU + gencallinterp(state, (unsigned long long)state->current_instruction_table.SUBU, 0); +#else + int rs = allocate_register_32(state, (unsigned int *)state->dst->f.r.rs); + int rt = allocate_register_32(state, (unsigned int *)state->dst->f.r.rt); + int rd = allocate_register_32_w(state, (unsigned int *)state->dst->f.r.rd); + + if (rs == rd) + sub_reg32_reg32(state, rd, rt); + else if (rt == rd) + { + neg_reg32(state, rd); + add_reg32_reg32(state, rd, rs); + } + else + { + mov_reg32_reg32(state, rd, rs); + sub_reg32_reg32(state, rd, rt); + } +#endif +} + +void genand(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[83]); +#endif +#ifdef INTERPRET_AND + gencallinterp(state, (unsigned long long)state->current_instruction_table.AND, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + and_reg64_reg64(state, rd, rt); + else if (rt == rd) + and_reg64_reg64(state, rd, rs); + else + { + mov_reg64_reg64(state, rd, rs); + and_reg64_reg64(state, rd, rt); + } +#endif +} + +void genor(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[84]); +#endif +#ifdef INTERPRET_OR + gencallinterp(state, (unsigned long long)state->current_instruction_table.OR, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + or_reg64_reg64(state, rd, rt); + else if (rt == rd) + or_reg64_reg64(state, rd, rs); + else + { + mov_reg64_reg64(state, rd, rs); + or_reg64_reg64(state, rd, rt); + } +#endif +} + +void genxor(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[85]); +#endif +#ifdef INTERPRET_XOR + gencallinterp(state, (unsigned long long)state->current_instruction_table.XOR, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + xor_reg64_reg64(state, rd, rt); + else if (rt == rd) + xor_reg64_reg64(state, rd, rs); + else + { + mov_reg64_reg64(state, rd, rs); + xor_reg64_reg64(state, rd, rt); + } +#endif +} + +void gennor(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[86]); +#endif +#ifdef INTERPRET_NOR + gencallinterp(state, (unsigned long long)state->current_instruction_table.NOR, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + { + or_reg64_reg64(state, rd, rt); + not_reg64(state, rd); + } + else if (rt == rd) + { + or_reg64_reg64(state, rd, rs); + not_reg64(state, rd); + } + else + { + mov_reg64_reg64(state, rd, rs); + or_reg64_reg64(state, rd, rt); + not_reg64(state, rd); + } +#endif +} + +void genslt(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[87]); +#endif +#ifdef INTERPRET_SLT + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLT, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + cmp_reg64_reg64(state, rs, rt); + setl_reg8(state, rd); + and_reg64_imm8(state, rd, 1); +#endif +} + +void gensltu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[88]); +#endif +#ifdef INTERPRET_SLTU + gencallinterp(state, (unsigned long long)state->current_instruction_table.SLTU, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + cmp_reg64_reg64(state, rs, rt); + setb_reg8(state, rd); + and_reg64_imm8(state, rd, 1); +#endif +} + +void gendadd(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[89]); +#endif +#ifdef INTERPRET_DADD + gencallinterp(state, (unsigned long long)state->current_instruction_table.DADD, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + add_reg64_reg64(state, rd, rt); + else if (rt == rd) + add_reg64_reg64(state, rd, rs); + else + { + mov_reg64_reg64(state, rd, rs); + add_reg64_reg64(state, rd, rt); + } +#endif +} + +void gendaddu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[90]); +#endif +#ifdef INTERPRET_DADDU + gencallinterp(state, (unsigned long long)state->current_instruction_table.DADDU, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + add_reg64_reg64(state, rd, rt); + else if (rt == rd) + add_reg64_reg64(state, rd, rs); + else + { + mov_reg64_reg64(state, rd, rs); + add_reg64_reg64(state, rd, rt); + } +#endif +} + +void gendsub(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[91]); +#endif +#ifdef INTERPRET_DSUB + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSUB, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + sub_reg64_reg64(state, rd, rt); + else if (rt == rd) + { + neg_reg64(state, rd); + add_reg64_reg64(state, rd, rs); + } + else + { + mov_reg64_reg64(state, rd, rs); + sub_reg64_reg64(state, rd, rt); + } +#endif +} + +void gendsubu(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[92]); +#endif +#ifdef INTERPRET_DSUBU + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSUBU, 0); +#else + int rs = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rs); + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + if (rs == rd) + sub_reg64_reg64(state, rd, rt); + else if (rt == rd) + { + neg_reg64(state, rd); + add_reg64_reg64(state, rd, rs); + } + else + { + mov_reg64_reg64(state, rd, rs); + sub_reg64_reg64(state, rd, rt); + } +#endif +} + +void genteq(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[96]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.TEQ, 0); +} + +void gendsll(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[93]); +#endif +#ifdef INTERPRET_DSLL + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSLL, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + shl_reg64_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gendsrl(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[94]); +#endif +#ifdef INTERPRET_DSRL + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRL, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + shr_reg64_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gendsra(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[95]); +#endif +#ifdef INTERPRET_DSRA + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRA, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + sar_reg64_imm8(state, rd, state->dst->f.r.sa); +#endif +} + +void gendsll32(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[97]); +#endif +#ifdef INTERPRET_DSLL32 + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSLL32, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + shl_reg64_imm8(state, rd, state->dst->f.r.sa + 32); +#endif +} + +void gendsrl32(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[98]); +#endif +#ifdef INTERPRET_DSRL32 + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRL32, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + shr_reg64_imm8(state, rd, state->dst->f.r.sa + 32); +#endif +} + +void gendsra32(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[99]); +#endif +#ifdef INTERPRET_DSRA32 + gencallinterp(state, (unsigned long long)state->current_instruction_table.DSRA32, 0); +#else + int rt = allocate_register_64(state, (unsigned long long *)state->dst->f.r.rt); + int rd = allocate_register_64_w(state, (unsigned long long *)state->dst->f.r.rd); + + mov_reg64_reg64(state, rd, rt); + sar_reg64_imm8(state, rd, state->dst->f.r.sa + 32); +#endif +} + +/* Idle loop hack from 64th Note */ +void genbreak(usf_state_t * state) +{ + gencallinterp(state, (unsigned long long)state->current_instruction_table.BREAK, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/gtlb.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gtlb.c new file mode 100644 index 000000000..3dab44bd0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/gtlb.c @@ -0,0 +1,101 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gtlb.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "assemble.h" + +#include "r4300/cached_interp.h" +#include "r4300/recomph.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" + +#if defined(COUNT_INSTR) +#include "r4300/instr_counters.h" +#endif + +void gentlbwi(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[104]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.TLBWI, 0); + /*dst->local_addr = code_length; + mov_m32_imm32(state, (void *)(&state->PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBWI)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void gentlbp(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[105]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.TLBP, 0); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBP)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void gentlbr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[106]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.TLBR, 0); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + mov_reg32_imm32(EAX, (unsigned int)(TLBR)); + call_reg32(EAX); + genupdate_system(0);*/ +} + +void generet(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[108]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.ERET, 1); + /*dst->local_addr = code_length; + mov_m32_imm32((void *)(&PC), (unsigned int)(dst)); + genupdate_system(0); + mov_reg32_imm32(EAX, (unsigned int)(ERET)); + call_reg32(EAX); + mov_reg32_imm32(EAX, (unsigned int)(jump_code)); + jmp_reg32(EAX);*/ +} + +void gentlbwr(usf_state_t * state) +{ +#if defined(COUNT_INSTR) + inc_m32rel(state, &state->instr_count[107]); +#endif + gencallinterp(state, (unsigned long long)state->current_instruction_table.TLBWR, 0); +} + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/interpret.h b/Frameworks/lazyusf/lazyusf/r4300/x86_64/interpret.h new file mode 100644 index 000000000..763f2148c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/interpret.h @@ -0,0 +1,240 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - interpret.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_R4300_INTERPRET_H +#define M64P_R4300_INTERPRET_H + +//#define INTERPRET_J +//#define INTERPRET_J_OUT +//#define INTERPRET_J_IDLE +//#define INTERPRET_JAL +//#define INTERPRET_JAL_OUT +//#define INTERPRET_JAL_IDLE +//#define INTERPRET_BEQ +//#define INTERPRET_BEQ_OUT +//#define INTERPRET_BEQ_IDLE +//#define INTERPRET_BNE +//#define INTERPRET_BNE_OUT +//#define INTERPRET_BNE_IDLE +//#define INTERPRET_BLEZ +//#define INTERPRET_BLEZ_OUT +//#define INTERPRET_BLEZ_IDLE +//#define INTERPRET_BGTZ +//#define INTERPRET_BGTZ_OUT +//#define INTERPRET_BGTZ_IDLE +//#define INTERPRET_ADDI +//#define INTERPRET_ADDIU +//#define INTERPRET_SLTI +//#define INTERPRET_SLTIU +//#define INTERPRET_ANDI +//#define INTERPRET_ORI +//#define INTERPRET_XORI +//#define INTERPRET_LUI +//#define INTERPRET_BEQL +//#define INTERPRET_BEQL_OUT +//#define INTERPRET_BEQL_IDLE +//#define INTERPRET_BNEL +//#define INTERPRET_BNEL_OUT +//#define INTERPRET_BNEL_IDLE +//#define INTERPRET_BLEZL +//#define INTERPRET_BLEZL_OUT +//#define INTERPRET_BLEZL_IDLE +//#define INTERPRET_BGTZL +//#define INTERPRET_BGTZL_OUT +//#define INTERPRET_BGTZL_IDLE +//#define INTERPRET_DADDI +//#define INTERPRET_DADDIU +//#define INTERPRET_LB +//#define INTERPRET_LH +//#define INTERPRET_LW +//#define INTERPRET_LBU +//#define INTERPRET_LHU +//#define INTERPRET_LWU +//#define INTERPRET_SB +//#define INTERPRET_SH +//#define INTERPRET_SW +//#define INTERPRET_LWC1 +//#define INTERPRET_LDC1 +//#define INTERPRET_LD +//#define INTERPRET_SWC1 +//#define INTERPRET_SDC1 +//#define INTERPRET_SD +//#define INTERPRET_SLL +//#define INTERPRET_SRL +//#define INTERPRET_SRA +//#define INTERPRET_SLLV +//#define INTERPRET_SRLV +//#define INTERPRET_SRAV +//#define INTERPRET_JR +//#define INTERPRET_JALR +//#define INTERPRET_SYSCALL +//#define INTERPRET_MFHI +//#define INTERPRET_MTHI +//#define INTERPRET_MFLO +//#define INTERPRET_MTLO +//#define INTERPRET_DSLLV +//#define INTERPRET_DSRLV +//#define INTERPRET_DSRAV +//#define INTERPRET_MULT +//#define INTERPRET_MULTU +//#define INTERPRET_DIV +//#define INTERPRET_DIVU +//#define INTERPRET_DMULTU +//#define INTERPRET_ADD +//#define INTERPRET_ADDU +//#define INTERPRET_SUB +//#define INTERPRET_SUBU +//#define INTERPRET_AND +//#define INTERPRET_OR +//#define INTERPRET_XOR +//#define INTERPRET_NOR +//#define INTERPRET_SLT +//#define INTERPRET_SLTU +//#define INTERPRET_DADD +//#define INTERPRET_DADDU +//#define INTERPRET_DSUB +//#define INTERPRET_DSUBU +//#define INTERPRET_DSLL +//#define INTERPRET_DSRL +//#define INTERPRET_DSRA +//#define INTERPRET_DSLL32 +//#define INTERPRET_DSRL32 +//#define INTERPRET_DSRA32 +//#define INTERPRET_BLTZ +//#define INTERPRET_BLTZ_OUT +//#define INTERPRET_BLTZ_IDLE +//#define INTERPRET_BGEZ +//#define INTERPRET_BGEZ_OUT +//#define INTERPRET_BGEZ_IDLE +//#define INTERPRET_BLTZL +//#define INTERPRET_BLTZL_OUT +//#define INTERPRET_BLTZL_IDLE +//#define INTERPRET_BGEZL +//#define INTERPRET_BGEZL_OUT +//#define INTERPRET_BGEZL_IDLE +//#define INTERPRET_BLTZAL +//#define INTERPRET_BLTZAL_OUT +//#define INTERPRET_BLTZAL_IDLE +//#define INTERPRET_BGEZAL +//#define INTERPRET_BGEZAL_OUT +//#define INTERPRET_BGEZAL_IDLE +//#define INTERPRET_BLTZALL +//#define INTERPRET_BLTZALL_OUT +//#define INTERPRET_BLTZALL_IDLE +//#define INTERPRET_BGEZALL +//#define INTERPRET_BGEZALL_OUT +//#define INTERPRET_BGEZALL_IDLE +//#define INTERPRET_BC1F +//#define INTERPRET_BC1F_OUT +//#define INTERPRET_BC1F_IDLE +//#define INTERPRET_BC1T +//#define INTERPRET_BC1T_OUT +//#define INTERPRET_BC1T_IDLE +//#define INTERPRET_BC1FL +//#define INTERPRET_BC1FL_OUT +//#define INTERPRET_BC1FL_IDLE +//#define INTERPRET_BC1TL +//#define INTERPRET_BC1TL_OUT +//#define INTERPRET_BC1TL_IDLE +//#define INTERPRET_MFC1 +//#define INTERPRET_DMFC1 +//#define INTERPRET_CFC1 +//#define INTERPRET_MTC1 +//#define INTERPRET_DMTC1 +//#define INTERPRET_CTC1 +//#define INTERPRET_ADD_D +//#define INTERPRET_SUB_D +//#define INTERPRET_MUL_D +//#define INTERPRET_DIV_D +//#define INTERPRET_SQRT_D +//#define INTERPRET_ABS_D +//#define INTERPRET_MOV_D +//#define INTERPRET_NEG_D +//#define INTERPRET_ROUND_L_D +//#define INTERPRET_TRUNC_L_D +//#define INTERPRET_CEIL_L_D +//#define INTERPRET_FLOOR_L_D +//#define INTERPRET_ROUND_W_D +//#define INTERPRET_TRUNC_W_D +//#define INTERPRET_CEIL_W_D +//#define INTERPRET_FLOOR_W_D +//#define INTERPRET_CVT_S_D +//#define INTERPRET_CVT_W_D +//#define INTERPRET_CVT_L_D +//#define INTERPRET_C_F_D +//#define INTERPRET_C_UN_D +//#define INTERPRET_C_EQ_D +//#define INTERPRET_C_UEQ_D +//#define INTERPRET_C_OLT_D +//#define INTERPRET_C_ULT_D +//#define INTERPRET_C_OLE_D +//#define INTERPRET_C_ULE_D +//#define INTERPRET_C_SF_D +//#define INTERPRET_C_NGLE_D +//#define INTERPRET_C_SEQ_D +//#define INTERPRET_C_NGL_D +//#define INTERPRET_C_LT_D +//#define INTERPRET_C_NGE_D +//#define INTERPRET_C_LE_D +//#define INTERPRET_C_NGT_D +//#define INTERPRET_CVT_S_L +//#define INTERPRET_CVT_D_L +//#define INTERPRET_CVT_S_W +//#define INTERPRET_CVT_D_W +//#define INTERPRET_ADD_S +//#define INTERPRET_SUB_S +//#define INTERPRET_MUL_S +//#define INTERPRET_DIV_S +//#define INTERPRET_SQRT_S +//#define INTERPRET_ABS_S +//#define INTERPRET_MOV_S +//#define INTERPRET_NEG_S +//#define INTERPRET_ROUND_L_S +//#define INTERPRET_TRUNC_L_S +//#define INTERPRET_CEIL_L_S +//#define INTERPRET_FLOOR_L_S +//#define INTERPRET_ROUND_W_S +//#define INTERPRET_TRUNC_W_S +//#define INTERPRET_CEIL_W_S +//#define INTERPRET_FLOOR_W_S +//#define INTERPRET_CVT_D_S +//#define INTERPRET_CVT_W_S +//#define INTERPRET_CVT_L_S +//#define INTERPRET_C_F_S +//#define INTERPRET_C_UN_S +//#define INTERPRET_C_EQ_S +//#define INTERPRET_C_UEQ_S +//#define INTERPRET_C_OLT_S +//#define INTERPRET_C_ULT_S +//#define INTERPRET_C_OLE_S +//#define INTERPRET_C_ULE_S +//#define INTERPRET_C_SF_S +//#define INTERPRET_C_NGLE_S +//#define INTERPRET_C_SEQ_S +//#define INTERPRET_C_NGL_S +//#define INTERPRET_C_LT_S +//#define INTERPRET_C_NGE_S +//#define INTERPRET_C_LE_S +//#define INTERPRET_C_NGT_S + +#endif /* M64P_R4300_INTERPRET_H */ + diff --git a/Frameworks/lazyusf/lazyusf/r4300/x86_64/regcache.c b/Frameworks/lazyusf/lazyusf/r4300/x86_64/regcache.c new file mode 100644 index 000000000..aaa78fd27 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/r4300/x86_64/regcache.c @@ -0,0 +1,625 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - regcache.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "regcache.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/recomph.h" + +void init_cache(usf_state_t * state, precomp_instr* start) +{ + int i; + for (i=0; i<8; i++) + { + state->reg_content[i] = NULL; + state->last_access[i] = NULL; + state->free_since[i] = start; + state->dirty[i] = 0; + state->is64bits[i] = 0; + } + state->r0 = (unsigned long long *) state->reg; +} + +void free_all_registers(usf_state_t * state) +{ + int i; + for (i=0; i<8; i++) + { + if (state->last_access[i]) + { + free_register(state, i); + } + else + { + while (state->free_since[i] <= state->dst) + { + state->free_since[i]->reg_cache_infos.needed_registers[i] = NULL; + state->free_since[i]++; + } + } + } +} + +static void simplify_access(usf_state_t * state) +{ + int i; + state->dst->local_addr = state->code_length; + for(i=0; i<8; i++) state->dst->reg_cache_infos.needed_registers[i] = NULL; +} + +void free_registers_move_start(usf_state_t * state) +{ + /* flush all dirty registers and clear needed_registers table */ + free_all_registers(state); + + /* now move the start of the new instruction down past the flushing instructions */ + simplify_access(state); +} + +// this function frees a specific X86 GPR +void free_register(usf_state_t * state, int reg) +{ + precomp_instr *last; + + if (state->last_access[reg] == (precomp_instr *) 0xFFFFFFFFFFFFFFFFULL) + unlock_register(state, reg); + + if (state->last_access[reg] != NULL) + last = state->last_access[reg]+1; + else + last = state->free_since[reg]; + + while (last <= state->dst) + { + if (state->last_access[reg] != NULL && state->dirty[reg]) + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + else + last->reg_cache_infos.needed_registers[reg] = NULL; + last++; + } + if (state->last_access[reg] == NULL) + { + state->free_since[reg] = state->dst+1; + return; + } + + if (state->dirty[reg]) + { + if (state->is64bits[reg]) + { + mov_m64rel_xreg64(state, (unsigned long long *) state->reg_content[reg], reg); + } + else + { + movsxd_reg64_reg32(state, reg, reg); + mov_m64rel_xreg64(state, (unsigned long long *) state->reg_content[reg], reg); + } + } + + state->last_access[reg] = NULL; + state->free_since[reg] = state->dst+1; +} + +int lru_register(usf_state_t * state) +{ + unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL; + int i, reg = 0; + for (i=0; i<8; i++) + { + if (i != ESP && (unsigned long long) state->last_access[i] < oldest_access) + { + oldest_access = (unsigned long long) state->last_access[i]; + reg = i; + } + } + return reg; +} + +int lru_base_register(usf_state_t * state) /* EBP cannot be used as a base register for SIB addressing byte */ +{ + unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL; + int i, reg = 0; + for (i=0; i<8; i++) + { + if (i != ESP && i != EBP && (unsigned long long) state->last_access[i] < oldest_access) + { + oldest_access = (unsigned long long) state->last_access[i]; + reg = i; + } + } + return reg; +} + +void set_register_state(usf_state_t * state, int reg, unsigned int *addr, int _dirty, int _is64bits) +{ + if (addr == NULL) + state->last_access[reg] = NULL; + else + state->last_access[reg] = state->dst; + state->reg_content[reg] = (unsigned long long *) addr; + state->is64bits[reg] = _is64bits; + state->dirty[reg] = _dirty; +} + +int lock_register(usf_state_t * state, int reg) +{ + free_register(state, reg); + state->last_access[reg] = (precomp_instr *) 0xFFFFFFFFFFFFFFFFULL; + state->reg_content[reg] = NULL; + return reg; +} + +void unlock_register(usf_state_t * state, int reg) +{ + state->last_access[reg] = NULL; +} + +// this function finds a register to put the data contained in addr, +// if there was another value before it's cleanly removed of the +// register cache. After that, the register number is returned. +// If data are already cached, the function only returns the register number +int allocate_register_32(usf_state_t * state, unsigned int *addr) +{ + int reg = 0, i; + + // is it already cached ? + if (addr != NULL) + { + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && (unsigned int *) state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + state->is64bits[i] = 0; + return i; + } + } + } + + // it's not cached, so take the least recently used register + reg = lru_register(state); + + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = (unsigned long long *) addr; + state->dirty[reg] = 0; + state->is64bits[reg] = 0; + + if (addr != NULL) + { + if (addr == (unsigned int *) state->r0) + xor_reg32_reg32(state, reg, reg); + else + mov_xreg32_m32rel(state, reg, addr); + } + + return reg; +} + +// this function is similar to allocate_register except it loads +// a 64 bits value, and return the register number of the LSB part +int allocate_register_64(usf_state_t * state, unsigned long long *addr) +{ + int reg, i; + + // is it already cached? + if (addr != NULL) + { + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i]+1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + if (state->is64bits[i] == 0) + { + movsxd_reg64_reg32(state, i, i); + state->is64bits[i] = 1; + } + return i; + } + } + } + + // it's not cached, so take the least recently used register + reg = lru_register(state); + + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 0; + state->is64bits[reg] = 1; + + if (addr != NULL) + { + if (addr == state->r0) + xor_reg64_reg64(state, reg, reg); + else + mov_xreg64_m64rel(state, reg, addr); + } + + return reg; +} + +// this function checks if the data located at addr are cached in a register +// and then, it returns 1 if it's a 64 bit value +// 0 if it's a 32 bit value +// -1 if it's not cached +int is64(usf_state_t * state, unsigned int *addr) +{ + int i; + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == (unsigned long long *) addr) + { + return state->is64bits[i]; + } + } + return -1; +} + +int allocate_register_32_w(usf_state_t * state, unsigned int *addr) +{ + int reg = 0, i; + + // is it already cached ? + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == (unsigned long long *) addr) + { + precomp_instr *last = state->last_access[i] + 1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = NULL; + last++; + } + state->last_access[i] = state->dst; + state->dirty[i] = 1; + state->is64bits[i] = 0; + return i; + } + } + + // it's not cached, so take the least recently used register + reg = lru_register(state); + + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = (unsigned long long *) addr; + state->dirty[reg] = 1; + state->is64bits[reg] = 0; + + return reg; +} + +int allocate_register_64_w(usf_state_t *state, unsigned long long *addr) +{ + int reg, i; + + // is it already cached? + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == addr) + { + precomp_instr *last = state->last_access[i] + 1; + + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = NULL; + last++; + } + state->last_access[i] = state->dst; + state->is64bits[i] = 1; + state->dirty[i] = 1; + return i; + } + } + + // it's not cached, so take the least recently used register + reg = lru_register(state); + + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + state->last_access[reg] = state->dst; + state->reg_content[reg] = addr; + state->dirty[reg] = 1; + state->is64bits[reg] = 1; + + return reg; +} + +void allocate_register_32_manually(usf_state_t * state, int reg, unsigned int *addr) +{ + int i; + + /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ + if (state->last_access[reg] != NULL && state->reg_content[reg] == (unsigned long long *) addr) + { + precomp_instr *last = state->last_access[reg] + 1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; + last++; + } + state->last_access[reg] = state->dst; + /* we won't touch is64bits or dirty; the register returned is "read-only" */ + return; + } + + /* otherwise free up the requested x86 register */ + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + /* if the r4300 register is already cached in a different x86 register, then copy it to the requested x86 register */ + for (i=0; i<8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == (unsigned long long *) addr) + { + precomp_instr *last = state->last_access[i]+1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; + last++; + } + state->last_access[i] = state->dst; + if (state->is64bits[i]) + mov_reg64_reg64(state, reg, i); + else + mov_reg32_reg32(state, reg, i); + state->last_access[reg] = state->dst; + state->is64bits[reg] = state->is64bits[i]; + state->dirty[reg] = state->dirty[i]; + state->reg_content[reg] = state->reg_content[i]; + /* free the previous x86 register used to cache this r4300 register */ + state->free_since[i] = state->dst + 1; + state->last_access[i] = NULL; + return; + } + } + + /* otherwise just load the 32-bit value into the requested register */ + state->last_access[reg] = state->dst; + state->reg_content[reg] = (unsigned long long *) addr; + state->dirty[reg] = 0; + state->is64bits[reg] = 0; + + if ((unsigned long long *) addr == state->r0) + xor_reg32_reg32(state, reg, reg); + else + mov_xreg32_m32rel(state, reg, addr); +} + +void allocate_register_32_manually_w(usf_state_t * state, int reg, unsigned int *addr) +{ + int i; + + /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ + if (state->last_access[reg] != NULL && state->reg_content[reg] == (unsigned long long *) addr) + { + precomp_instr *last = state->last_access[reg]+1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[reg] = NULL; + last++; + } + state->last_access[reg] = state->dst; + state->is64bits[reg] = 0; + state->dirty[reg] = 1; + return; + } + + /* otherwise free up the requested x86 register */ + if (state->last_access[reg]) + free_register(state, reg); + else + { + while (state->free_since[reg] <= state->dst) + { + state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; + state->free_since[reg]++; + } + } + + /* if the r4300 register is already cached in a different x86 register, then free it and bind to the requested x86 register */ + for (i = 0; i < 8; i++) + { + if (state->last_access[i] != NULL && state->reg_content[i] == (unsigned long long *) addr) + { + precomp_instr *last = state->last_access[i] + 1; + while (last <= state->dst) + { + last->reg_cache_infos.needed_registers[i] = NULL; + last++; + } + state->last_access[reg] = state->dst; + state->reg_content[reg] = state->reg_content[i]; + state->dirty[reg] = 1; + state->is64bits[reg] = 0; + /* free the previous x86 register used to cache this r4300 register */ + state->free_since[i] = state->dst+1; + state->last_access[i] = NULL; + return; + } + } + + /* otherwise just set up the requested register as 32-bit */ + state->last_access[reg] = state->dst; + state->reg_content[reg] = (unsigned long long *) addr; + state->dirty[reg] = 1; + state->is64bits[reg] = 0; +} + + +// 0x48 0x83 0xEC 0x8 sub rsp, byte 8 +// 0x48 0xA1 0xXXXXXXXXXXXXXXXX mov rax, qword (&code start) +// 0x48 0x05 0xXXXXXXXX add rax, dword (local_addr) +// 0x48 0x89 0x04 0x24 mov [rsp], rax +// 0x48 0xB8 0xXXXXXXXXXXXXXXXX mov rax, ®[0] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdi, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rsi, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbp, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdx, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rcx, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbx, [rax + XXXXXXXX] +// 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rax, [rax + XXXXXXXX] +// 0xC3 ret +// total : 84 bytes + +static void build_wrapper(usf_state_t * state, precomp_instr *instr, unsigned char* pCode, precomp_block* block) +{ + int i; + + *pCode++ = 0x48; + *pCode++ = 0x83; + *pCode++ = 0xEC; + *pCode++ = 0x08; + + *pCode++ = 0x48; + *pCode++ = 0xA1; + *((unsigned long long *) pCode) = (unsigned long long) (&block->code); + pCode += 8; + + *pCode++ = 0x48; + *pCode++ = 0x05; + *((unsigned int *) pCode) = (unsigned int) instr->local_addr; + pCode += 4; + + *pCode++ = 0x48; + *pCode++ = 0x89; + *pCode++ = 0x04; + *pCode++ = 0x24; + + *pCode++ = 0x48; + *pCode++ = 0xB8; + *((unsigned long long *) pCode) = (unsigned long long) &state->reg[0]; + pCode += 8; + + for (i=7; i>=0; i--) + { + long long riprel; + if (instr->reg_cache_infos.needed_registers[i] != NULL) + { + *pCode++ = 0x48; + *pCode++ = 0x8B; + *pCode++ = 0x80 | (i << 3); + riprel = (long long) ((unsigned char *) instr->reg_cache_infos.needed_registers[i] - (unsigned char *) &state->reg[0]); + *((int *) pCode) = (int) riprel; + pCode += 4; + if (riprel >= 0x7fffffffLL || riprel < -0x80000000LL) + { + DebugMessage(state, M64MSG_ERROR, "build_wrapper error: reg[%i] offset too big for relative address from %p to %p", + i, (&state->reg[0]), instr->reg_cache_infos.needed_registers[i]); + OSAL_BREAKPOINT_INTERRUPT + } + } + } + *pCode++ = 0xC3; +} + +void build_wrappers(usf_state_t * state, precomp_instr *instr, int start, int end, precomp_block* block) +{ + int i, reg; + for (i=start; i + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "r4300/cached_interp.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/macros.h" +#include "r4300/ops.h" +#include "r4300/recomph.h" + +void dyna_jump(usf_state_t * state) +{ + if (state->stop == 1) + { + dyna_stop(state); + return; + } + + if (state->PC->reg_cache_infos.need_map) + *state->return_address = (unsigned long long) (state->PC->reg_cache_infos.jump_wrapper); + else + *state->return_address = (unsigned long long) (state->actual->code + state->PC->local_addr); +} + +void dyna_start(usf_state_t * state, void *code) +{ + /* save the base and stack pointers */ + /* make a call and a pop to retrieve the instruction pointer and save it too */ + /* then call the code(), which should theoretically never return. */ + /* When dyna_stop() sets the *return_address to the saved RIP, the emulator thread will come back here. */ + /* It will jump to label 2, restore the base and stack pointers, and exit this function */ + DebugMessage(state, M64MSG_INFO, "R4300: starting 64-bit dynamic recompiler at: %p", code); +#if defined(__GNUC__) && defined(__x86_64__) + asm volatile + (" push %%rbx \n" /* we must push an even # of registers to keep stack 16-byte aligned */ + " push %%r12 \n" + " push %%r13 \n" + " push %%r14 \n" + " push %%r15 \n" + " push %%rbp \n" + " movq %[state], %%r15 \n" /* store the base location of the emulator state in r15 for addressing */ + " movq %%rsp, %c[save_rsp](%%r15) \n" + " call 1f \n" + " jmp 2f \n" + "1: \n" + " pop %%rax \n" + " movq %%rax, %c[save_rip](%%r15) \n" + + " sub $0x10, %%rsp \n" + " and $-16, %%rsp \n" /* ensure that stack is 16-byte aligned */ + " mov %%rsp, %%rax \n" + " sub $8, %%rax \n" + " movq %%rax, %c[return_address](%%r15)\n" + + " call *%%rbx \n" + "2: \n" + " movq %c[save_rsp](%%r15), %%rsp \n" + " pop %%rbp \n" + " pop %%r15 \n" + " pop %%r14 \n" + " pop %%r13 \n" + " pop %%r12 \n" + " pop %%rbx \n" + : + : [save_rsp]"i"(offsetof(usf_state_t,save_rsp)), [save_rip]"i"(offsetof(usf_state_t,save_rip)), [return_address]"i"(offsetof(usf_state_t,return_address)), "b" (code), [state]"r"(state) + : "%rax", "memory" + ); +#endif + + /* clear the registers so we don't return here a second time; that would be a bug */ + state->save_rsp=0; + state->save_rip=0; +} + +void dyna_stop(usf_state_t * state) +{ + if (state->save_rip == 0) + DebugMessage(state, M64MSG_WARNING, "Instruction pointer is 0 at dyna_stop()"); + else + { + *state->return_address = (unsigned long long) state->save_rip; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rdp/rdp_core.c b/Frameworks/lazyusf/lazyusf/rdp/rdp_core.c new file mode 100644 index 000000000..830bcaf80 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rdp/rdp_core.c @@ -0,0 +1,148 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdp_core.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "rdp_core.h" + +#include "memory/memory.h" +#include "r4300/interupt.h" +#include "r4300/r4300_core.h" +#include "rsp/rsp_core.h" + +#include + +static int update_dpc_status(struct rdp_core* dp, uint32_t w) +{ + /* see do_SP_Task for more info */ + int do_sp_task_on_unfreeze = 0; + + /* clear / set xbus_dmem_dma */ + if (w & 0x1) dp->dpc_regs[DPC_STATUS_REG] &= ~0x1; + if (w & 0x2) dp->dpc_regs[DPC_STATUS_REG] |= 0x1; + + /* clear / set freeze */ + if (w & 0x4) + { + dp->dpc_regs[DPC_STATUS_REG] &= ~0x2; + + if (!(dp->sp->regs[SP_STATUS_REG] & 0x3)) // !halt && !broke + do_sp_task_on_unfreeze = 1; + } + if (w & 0x8) dp->dpc_regs[DPC_STATUS_REG] |= 0x2; + + /* clear / set flush */ + if (w & 0x10) dp->dpc_regs[DPC_STATUS_REG] &= ~0x4; + if (w & 0x20) dp->dpc_regs[DPC_STATUS_REG] |= 0x4; + + return do_sp_task_on_unfreeze; +} + + +void connect_rdp(struct rdp_core* dp, + struct r4300_core* r4300, + struct rsp_core* sp, + struct ri_controller* ri) +{ + dp->r4300 = r4300; + dp->sp = sp; + dp->ri = ri; +} + +void init_rdp(struct rdp_core* dp) +{ + memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t)); + memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t)); +} + + +int read_dpc_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct rdp_core* dp = (struct rdp_core*)opaque; + uint32_t reg = dpc_reg(address); + + *value = dp->dpc_regs[reg]; + + return 0; +} + +int write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct rdp_core* dp = (struct rdp_core*)opaque; + uint32_t reg = dpc_reg(address); + + switch(reg) + { + case DPC_STATUS_REG: + if (update_dpc_status(dp, value & mask) != 0) + do_SP_Task(dp->sp); + case DPC_CURRENT_REG: + case DPC_CLOCK_REG: + case DPC_BUFBUSY_REG: + case DPC_PIPEBUSY_REG: + case DPC_TMEM_REG: + return 0; + } + + masked_write(&dp->dpc_regs[reg], value, mask); + + switch(reg) + { + case DPC_START_REG: + dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG]; + break; + case DPC_END_REG: + signal_rcp_interrupt(dp->r4300, MI_INTR_DP); + break; + } + + return 0; +} + + +int read_dps_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct rdp_core* dp = (struct rdp_core*)opaque; + uint32_t reg = dps_reg(address); + + *value = dp->dps_regs[reg]; + + return 0; +} + +int write_dps_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct rdp_core* dp = (struct rdp_core*)opaque; + uint32_t reg = dps_reg(address); + + masked_write(&dp->dps_regs[reg], value, mask); + + return 0; +} + +void rdp_interrupt_event(struct rdp_core* dp) +{ + dp->dpc_regs[DPC_STATUS_REG] &= ~2; + dp->dpc_regs[DPC_STATUS_REG] |= 0x81; + + raise_rcp_interrupt(dp->r4300, MI_INTR_DP); +} + diff --git a/Frameworks/lazyusf/lazyusf/rdp/rdp_core.h b/Frameworks/lazyusf/lazyusf/rdp/rdp_core.h new file mode 100644 index 000000000..b54234810 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rdp/rdp_core.h @@ -0,0 +1,91 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdp_core.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_RDP_RDP_CORE_H +#define M64P_RDP_RDP_CORE_H + +#include + +struct r4300_core; +struct rsp_core; +struct ri_controller; + +enum dpc_registers +{ + DPC_START_REG, + DPC_END_REG, + DPC_CURRENT_REG, + DPC_STATUS_REG, + DPC_CLOCK_REG, + DPC_BUFBUSY_REG, + DPC_PIPEBUSY_REG, + DPC_TMEM_REG, + DPC_REGS_COUNT +}; + +enum dps_registers +{ + DPS_TBIST_REG, + DPS_TEST_MODE_REG, + DPS_BUFTEST_ADDR_REG, + DPS_BUFTEST_DATA_REG, + DPS_REGS_COUNT +}; + + +struct rdp_core +{ + uint32_t dpc_regs[DPC_REGS_COUNT]; + uint32_t dps_regs[DPS_REGS_COUNT]; + + struct r4300_core* r4300; + struct rsp_core* sp; + struct ri_controller* ri; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t dpc_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +static osal_inline uint32_t dps_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +void connect_rdp(struct rdp_core* dp, + struct r4300_core* r4300, + struct rsp_core* sp, + struct ri_controller* ri); + +void init_rdp(struct rdp_core* dp); + +int read_dpc_regs(void* opaque, uint32_t address, uint32_t* value); +int write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_dps_regs(void* opaque, uint32_t address, uint32_t* value); +int write_dps_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void rdp_interrupt_event(struct rdp_core* dp); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/registers.c b/Frameworks/lazyusf/lazyusf/registers.c deleted file mode 100644 index 8f7db882c..000000000 --- a/Frameworks/lazyusf/lazyusf/registers.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -// #ifdef EXT_REGS - -#include "usf.h" - -#include "main.h" -#include "cpu.h" -#include "types.h" - -#include "usf_internal.h" - -void SetupRegisters(usf_state_t * state, N64_REGISTERS * n64_Registers) { - state->PROGRAM_COUNTER = n64_Registers->PROGRAM_COUNTER; - state->HI.DW = n64_Registers->HI.DW; - state->LO.DW = n64_Registers->LO.DW; - state->CP0 = n64_Registers->CP0; - state->GPR = n64_Registers->GPR; - state->FPR = n64_Registers->FPR; - state->FPCR = n64_Registers->FPCR; - state->RegRDRAM = n64_Registers->RDRAM; - state->RegSP = n64_Registers->SP; - state->RegDPC = n64_Registers->DPC; - state->RegMI = n64_Registers->MI; - state->RegVI = n64_Registers->VI; - state->RegAI = n64_Registers->AI; - state->RegPI = n64_Registers->PI; - state->RegRI = n64_Registers->RI; - state->RegSI = n64_Registers->SI; - state->PIF_Ram = (uint8_t *) n64_Registers->PIF_Ram; -} - -void ChangeMiIntrMask (usf_state_t * state) { - if ( ( state->RegModValue & MI_INTR_MASK_CLR_SP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SP; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_SP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SP; } - if ( ( state->RegModValue & MI_INTR_MASK_CLR_SI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SI; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_SI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SI; } - if ( ( state->RegModValue & MI_INTR_MASK_CLR_AI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_AI; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_AI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_AI; } - if ( ( state->RegModValue & MI_INTR_MASK_CLR_VI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_VI; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_VI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_VI; } - if ( ( state->RegModValue & MI_INTR_MASK_CLR_PI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_PI; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_PI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_PI; } - if ( ( state->RegModValue & MI_INTR_MASK_CLR_DP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_DP; } - if ( ( state->RegModValue & MI_INTR_MASK_SET_DP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_DP; } -} - -void ChangeMiModeReg (usf_state_t * state) { - MI_MODE_REG &= ~0x7F; - MI_MODE_REG |= (state->RegModValue & 0x7F); - if ( ( state->RegModValue & MI_CLR_INIT ) != 0 ) { MI_MODE_REG &= ~MI_MODE_INIT; } - if ( ( state->RegModValue & MI_SET_INIT ) != 0 ) { MI_MODE_REG |= MI_MODE_INIT; } - if ( ( state->RegModValue & MI_CLR_EBUS ) != 0 ) { MI_MODE_REG &= ~MI_MODE_EBUS; } - if ( ( state->RegModValue & MI_SET_EBUS ) != 0 ) { MI_MODE_REG |= MI_MODE_EBUS; } - if ( ( state->RegModValue & MI_CLR_DP_INTR ) != 0 ) { MI_INTR_REG &= ~MI_INTR_DP; } - if ( ( state->RegModValue & MI_CLR_RDRAM ) != 0 ) { MI_MODE_REG &= ~MI_MODE_RDRAM; } - if ( ( state->RegModValue & MI_SET_RDRAM ) != 0 ) { MI_MODE_REG |= MI_MODE_RDRAM; } -} - -void ChangeSpStatus (usf_state_t * state) { - if ( ( state->RegModValue & SP_CLR_HALT ) != 0) { SP_STATUS_REG &= ~SP_STATUS_HALT; } - if ( ( state->RegModValue & SP_SET_HALT ) != 0) { SP_STATUS_REG |= SP_STATUS_HALT; } - if ( ( state->RegModValue & SP_CLR_BROKE ) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; } - if ( ( state->RegModValue & SP_CLR_INTR ) != 0) { - MI_INTR_REG &= ~MI_INTR_SP; - CheckInterrupts(state); - } - - if ( ( state->RegModValue & SP_CLR_SSTEP ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SSTEP; } - if ( ( state->RegModValue & SP_SET_SSTEP ) != 0) { SP_STATUS_REG |= SP_STATUS_SSTEP; } - if ( ( state->RegModValue & SP_CLR_INTR_BREAK ) != 0) { SP_STATUS_REG &= ~SP_STATUS_INTR_BREAK; } - if ( ( state->RegModValue & SP_SET_INTR_BREAK ) != 0) { SP_STATUS_REG |= SP_STATUS_INTR_BREAK; } - if ( ( state->RegModValue & SP_CLR_SIG0 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG0; } - if ( ( state->RegModValue & SP_SET_SIG0 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG0; } - if ( ( state->RegModValue & SP_CLR_SIG1 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG1; } - if ( ( state->RegModValue & SP_SET_SIG1 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG1; } - if ( ( state->RegModValue & SP_CLR_SIG2 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG2; } - if ( ( state->RegModValue & SP_SET_SIG2 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG2; } - if ( ( state->RegModValue & SP_CLR_SIG3 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG3; } - if ( ( state->RegModValue & SP_SET_SIG3 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG3; } - if ( ( state->RegModValue & SP_CLR_SIG4 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG4; } - if ( ( state->RegModValue & SP_SET_SIG4 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG4; } - if ( ( state->RegModValue & SP_CLR_SIG5 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG5; } - if ( ( state->RegModValue & SP_SET_SIG5 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG5; } - if ( ( state->RegModValue & SP_CLR_SIG6 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG6; } - if ( ( state->RegModValue & SP_SET_SIG6 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG6; } - if ( ( state->RegModValue & SP_CLR_SIG7 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG7; } - if ( ( state->RegModValue & SP_SET_SIG7 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; } - - RunRsp(state); - -} - -void UpdateCurrentHalfLine (usf_state_t * state) { - if (state->Timers->Timer < 0) { - state->HalfLine = 0; - return; - } - state->HalfLine = (state->Timers->Timer / 1500); - state->HalfLine &= ~1; - state->HalfLine += state->ViFieldNumber; -} - -void SetFpuLocations (usf_state_t * state) { - int count; - - if ((STATUS_REGISTER & STATUS_FR) == 0) { - for (count = 0; count < 32; count ++) { - state->FPRFloatLocation[count] = (void *)(&state->FPR[count >> 1].W[count & 1]); - //state->FPRDoubleLocation[count] = state->FPRFloatLocation[count]; - state->FPRDoubleLocation[count] = (void *)(&state->FPR[count >> 1].DW); - } - } else { - for (count = 0; count < 32; count ++) { - state->FPRFloatLocation[count] = (void *)(&state->FPR[count].W[1]); - //state->FPRFloatLocation[count] = (void *)(&state->FPR[count].W[1]); - //state->FPRDoubleLocation[count] = state->FPRFloatLocation[count]; - state->FPRDoubleLocation[count] = (void *)(&state->FPR[count].DW); - } - } -} diff --git a/Frameworks/lazyusf/lazyusf/registers.h b/Frameworks/lazyusf/lazyusf/registers.h deleted file mode 100644 index 6f4f205b4..000000000 --- a/Frameworks/lazyusf/lazyusf/registers.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#ifndef REGISTERS_H -#define REGISTERS_H - -#include "types.h" - -#define INDEX_REGISTER state->CP0[0] -#define RANDOM_REGISTER state->CP0[1] -#define ENTRYLO0_REGISTER state->CP0[2] -#define ENTRYLO1_REGISTER state->CP0[3] -#define CONTEXT_REGISTER state->CP0[4] -#define PAGE_MASK_REGISTER state->CP0[5] -#define WIRED_REGISTER state->CP0[6] -#define BAD_VADDR_REGISTER state->CP0[8] -#define COUNT_REGISTER state->CP0[9] -#define ENTRYHI_REGISTER state->CP0[10] -#define COMPARE_REGISTER state->CP0[11] -#define STATUS_REGISTER state->CP0[12] -#define CAUSE_REGISTER state->CP0[13] -#define EPC_REGISTER state->CP0[14] -#define CONFIG_REGISTER state->CP0[16] -#define TAGLO_REGISTER state->CP0[28] -#define TAGHI_REGISTER state->CP0[29] -#define ERROREPC_REGISTER state->CP0[30] -#define FAKE_CAUSE_REGISTER state->CP0[32] - -#define COMPARE_REGISTER_NO 11 -#define STATUS_REGISTER_NO 12 -#define CAUSE_REGISTER_NO 13 - -#define REVISION_REGISTER state->FPCR[0] -#define FSTATUS_REGISTER state->FPCR[31] - -#define GPR_S0 state->GPR[16] -#define GPR_S1 state->GPR[17] -#define GPR_S2 state->GPR[18] -#define GPR_S3 state->GPR[19] -#define GPR_S4 state->GPR[20] -#define GPR_S5 state->GPR[21] -#define GPR_S6 state->GPR[22] -#define GPR_S7 state->GPR[23] -#define GPR_SP state->GPR[29] -#define GPR_RA state->GPR[31] - -#define RDRAM_CONFIG_REG state->RegRDRAM[0] -#define RDRAM_DEVICE_TYPE_REG state->RegRDRAM[0] -#define RDRAM_DEVICE_ID_REG state->RegRDRAM[1] -#define RDRAM_DELAY_REG state->RegRDRAM[2] -#define RDRAM_MODE_REG state->RegRDRAM[3] -#define RDRAM_REF_INTERVAL_REG state->RegRDRAM[4] -#define RDRAM_REF_ROW_REG state->RegRDRAM[5] -#define RDRAM_RAS_INTERVAL_REG state->RegRDRAM[6] -#define RDRAM_MIN_INTERVAL_REG state->RegRDRAM[7] -#define RDRAM_ADDR_SELECT_REG state->RegRDRAM[8] -#define RDRAM_DEVICE_MANUF_REG state->RegRDRAM[9] - -#define SP_MEM_ADDR_REG state->RegSP[0] -#define SP_DRAM_ADDR_REG state->RegSP[1] -#define SP_RD_LEN_REG state->RegSP[2] -#define SP_WR_LEN_REG state->RegSP[3] -#define SP_STATUS_REG state->RegSP[4] -#define SP_DMA_FULL_REG state->RegSP[5] -#define SP_DMA_BUSY_REG state->RegSP[6] -#define SP_SEMAPHORE_REG state->RegSP[7] -#define SP_PC_REG state->RegSP[8] -#define SP_IBIST_REG state->RegSP[9] - -#define DPC_START_REG state->RegDPC[0] -#define DPC_END_REG state->RegDPC[1] -#define DPC_CURRENT_REG state->RegDPC[2] -#define DPC_STATUS_REG state->RegDPC[3] -#define DPC_CLOCK_REG state->RegDPC[4] -#define DPC_BUFBUSY_REG state->RegDPC[5] -#define DPC_PIPEBUSY_REG state->RegDPC[6] -#define DPC_TMEM_REG state->RegDPC[7] - -#define MI_INIT_MODE_REG state->RegMI[0] -#define MI_MODE_REG state->RegMI[0] -#define MI_VERSION_REG state->RegMI[1] -#define MI_NOOP_REG state->RegMI[1] -#define MI_INTR_REG state->RegMI[2] -#define MI_INTR_MASK_REG state->RegMI[3] - -#define VI_STATUS_REG state->RegVI[0] -#define VI_CONTROL_REG state->RegVI[0] -#define VI_ORIGIN_REG state->RegVI[1] -#define VI_DRAM_ADDR_REG state->RegVI[1] -#define VI_WIDTH_REG state->RegVI[2] -#define VI_H_WIDTH_REG state->RegVI[2] -#define VI_INTR_REG state->RegVI[3] -#define VI_V_INTR_REG state->RegVI[3] -#define VI_CURRENT_REG state->RegVI[4] -#define VI_V_CURRENT_LINE_REG state->RegVI[4] -#define VI_BURST_REG state->RegVI[5] -#define VI_TIMING_REG state->RegVI[5] -#define VI_V_SYNC_REG state->RegVI[6] -#define VI_H_SYNC_REG state->RegVI[7] -#define VI_LEAP_REG state->RegVI[8] -#define VI_H_SYNC_LEAP_REG state->RegVI[8] -#define VI_H_START_REG state->RegVI[9] -#define VI_H_VIDEO_REG state->RegVI[9] -#define VI_V_START_REG state->RegVI[10] -#define VI_V_VIDEO_REG state->RegVI[10] -#define VI_V_BURST_REG state->RegVI[11] -#define VI_X_SCALE_REG state->RegVI[12] -#define VI_Y_SCALE_REG state->RegVI[13] - -#define AI_DRAM_ADDR_REG state->RegAI[0] -#define AI_LEN_REG state->RegAI[1] -#define AI_CONTROL_REG state->RegAI[2] -#define AI_STATUS_REG state->RegAI[3] -#define AI_DACRATE_REG state->RegAI[4] -#define AI_BITRATE_REG state->RegAI[5] - -#define PI_DRAM_ADDR_REG state->RegPI[0] -#define PI_CART_ADDR_REG state->RegPI[1] -#define PI_RD_LEN_REG state->RegPI[2] -#define PI_WR_LEN_REG state->RegPI[3] -#define PI_STATUS_REG state->RegPI[4] -#define PI_BSD_DOM1_LAT_REG state->RegPI[5] -#define PI_DOMAIN1_REG state->RegPI[5] -#define PI_BSD_DOM1_PWD_REG state->RegPI[6] -#define PI_BSD_DOM1_PGS_REG state->RegPI[7] -#define PI_BSD_DOM1_RLS_REG state->RegPI[8] -#define PI_BSD_DOM2_LAT_REG state->RegPI[9] -#define PI_DOMAIN2_REG state->RegPI[9] -#define PI_BSD_DOM2_PWD_REG state->RegPI[10] -#define PI_BSD_DOM2_PGS_REG state->RegPI[11] -#define PI_BSD_DOM2_RLS_REG state->RegPI[12] - -#define RI_MODE_REG state->RegRI[0] -#define RI_CONFIG_REG state->RegRI[1] -#define RI_CURRENT_LOAD_REG state->RegRI[2] -#define RI_SELECT_REG state->RegRI[3] -#define RI_COUNT_REG state->RegRI[4] -#define RI_REFRESH_REG state->RegRI[4] -#define RI_LATENCY_REG state->RegRI[5] -#define RI_RERROR_REG state->RegRI[6] -#define RI_WERROR_REG state->RegRI[7] - -#define SI_DRAM_ADDR_REG state->RegSI[0] -#define SI_PIF_ADDR_RD64B_REG state->RegSI[1] -#define SI_PIF_ADDR_WR64B_REG state->RegSI[2] -#define SI_STATUS_REG state->RegSI[3] - -#define STATUS_IE 0x00000001 -#define STATUS_EXL 0x00000002 -#define STATUS_ERL 0x00000004 -#define STATUS_IP0 0x00000100 -#define STATUS_IP1 0x00000200 -#define STATUS_IP2 0x00000400 -#define STATUS_IP3 0x00000800 -#define STATUS_IP4 0x00001000 -#define STATUS_IP5 0x00002000 -#define STATUS_IP6 0x00004000 -#define STATUS_IP7 0x00008000 -#define STATUS_BEV 0x00400000 -#define STATUS_FR 0x04000000 -#define STATUS_CU0 0x10000000 -#define STATUS_CU1 0x20000000 - -#define CAUSE_EXC_CODE 0xFF -#define CAUSE_IP0 0x100 -#define CAUSE_IP1 0x200 -#define CAUSE_IP2 0x400 -#define CAUSE_IP3 0x800 -#define CAUSE_IP4 0x1000 -#define CAUSE_IP5 0x2000 -#define CAUSE_IP6 0x4000 -#define CAUSE_IP7 0x8000 -#define CAUSE_BD 0x80000000 - -#define SP_CLR_HALT 0x00001 /* Bit 0: clear halt */ -#define SP_SET_HALT 0x00002 /* Bit 1: set halt */ -#define SP_CLR_BROKE 0x00004 /* Bit 2: clear broke */ -#define SP_CLR_INTR 0x00008 /* Bit 3: clear intr */ -#define SP_SET_INTR 0x00010 /* Bit 4: set intr */ -#define SP_CLR_SSTEP 0x00020 /* Bit 5: clear sstep */ -#define SP_SET_SSTEP 0x00040 /* Bit 6: set sstep */ -#define SP_CLR_INTR_BREAK 0x00080 /* Bit 7: clear intr on break */ -#define SP_SET_INTR_BREAK 0x00100 /* Bit 8: set intr on break */ -#define SP_CLR_SIG0 0x00200 /* Bit 9: clear signal 0 */ -#define SP_SET_SIG0 0x00400 /* Bit 10: set signal 0 */ -#define SP_CLR_SIG1 0x00800 /* Bit 11: clear signal 1 */ -#define SP_SET_SIG1 0x01000 /* Bit 12: set signal 1 */ -#define SP_CLR_SIG2 0x02000 /* Bit 13: clear signal 2 */ -#define SP_SET_SIG2 0x04000 /* Bit 14: set signal 2 */ -#define SP_CLR_SIG3 0x08000 /* Bit 15: clear signal 3 */ -#define SP_SET_SIG3 0x10000 /* Bit 16: set signal 3 */ -#define SP_CLR_SIG4 0x20000 /* Bit 17: clear signal 4 */ -#define SP_SET_SIG4 0x40000 /* Bit 18: set signal 4 */ -#define SP_CLR_SIG5 0x80000 /* Bit 19: clear signal 5 */ -#define SP_SET_SIG5 0x100000 /* Bit 20: set signal 5 */ -#define SP_CLR_SIG6 0x200000 /* Bit 21: clear signal 6 */ -#define SP_SET_SIG6 0x400000 /* Bit 22: set signal 6 */ -#define SP_CLR_SIG7 0x800000 /* Bit 23: clear signal 7 */ -#define SP_SET_SIG7 0x1000000 /* Bit 24: set signal 7 */ - -#define SP_STATUS_HALT 0x001 /* Bit 0: halt */ -#define SP_STATUS_BROKE 0x002 /* Bit 1: broke */ -#define SP_STATUS_DMA_BUSY 0x004 /* Bit 2: dma busy */ -#define SP_STATUS_DMA_FULL 0x008 /* Bit 3: dma full */ -#define SP_STATUS_IO_FULL 0x010 /* Bit 4: io full */ -#define SP_STATUS_SSTEP 0x020 /* Bit 5: single step */ -#define SP_STATUS_INTR_BREAK 0x040 /* Bit 6: interrupt on break */ -#define SP_STATUS_SIG0 0x080 /* Bit 7: signal 0 set */ -#define SP_STATUS_SIG1 0x100 /* Bit 8: signal 1 set */ -#define SP_STATUS_SIG2 0x200 /* Bit 9: signal 2 set */ -#define SP_STATUS_SIG3 0x400 /* Bit 10: signal 3 set */ -#define SP_STATUS_SIG4 0x800 /* Bit 11: signal 4 set */ -#define SP_STATUS_SIG5 0x1000 /* Bit 12: signal 5 set */ -#define SP_STATUS_SIG6 0x2000 /* Bit 13: signal 6 set */ -#define SP_STATUS_SIG7 0x4000 /* Bit 14: signal 7 set */ - -#define DPC_CLR_XBUS_DMEM_DMA 0x0001 /* Bit 0: clear xbus_dmem_dma */ -#define DPC_SET_XBUS_DMEM_DMA 0x0002 /* Bit 1: set xbus_dmem_dma */ -#define DPC_CLR_FREEZE 0x0004 /* Bit 2: clear freeze */ -#define DPC_SET_FREEZE 0x0008 /* Bit 3: set freeze */ -#define DPC_CLR_FLUSH 0x0010 /* Bit 4: clear flush */ -#define DPC_SET_FLUSH 0x0020 /* Bit 5: set flush */ -#define DPC_CLR_TMEM_CTR 0x0040 /* Bit 6: clear tmem ctr */ -#define DPC_CLR_PIPE_CTR 0x0080 /* Bit 7: clear pipe ctr */ -#define DPC_CLR_CMD_CTR 0x0100 /* Bit 8: clear cmd ctr */ -#define DPC_CLR_CLOCK_CTR 0x0200 /* Bit 9: clear clock ctr */ - -#define DPC_STATUS_XBUS_DMEM_DMA 0x001 /* Bit 0: xbus_dmem_dma */ -#define DPC_STATUS_FREEZE 0x002 /* Bit 1: freeze */ -#define DPC_STATUS_FLUSH 0x004 /* Bit 2: flush */ -#define DPC_STATUS_START_GCLK 0x008 /* Bit 3: start gclk */ -#define DPC_STATUS_TMEM_BUSY 0x010 /* Bit 4: tmem busy */ -#define DPC_STATUS_PIPE_BUSY 0x020 /* Bit 5: pipe busy */ -#define DPC_STATUS_CMD_BUSY 0x040 /* Bit 6: cmd busy */ -#define DPC_STATUS_CBUF_READY 0x080 /* Bit 7: cbuf ready */ -#define DPC_STATUS_DMA_BUSY 0x100 /* Bit 8: dma busy */ -#define DPC_STATUS_END_VALID 0x200 /* Bit 9: end valid */ -#define DPC_STATUS_START_VALID 0x400 /* Bit 10: start valid */ - -#define MI_CLR_INIT 0x0080 /* Bit 7: clear init mode */ -#define MI_SET_INIT 0x0100 /* Bit 8: set init mode */ -#define MI_CLR_EBUS 0x0200 /* Bit 9: clear ebus test */ -#define MI_SET_EBUS 0x0400 /* Bit 10: set ebus test mode */ -#define MI_CLR_DP_INTR 0x0800 /* Bit 11: clear dp interrupt */ -#define MI_CLR_RDRAM 0x1000 /* Bit 12: clear RDRAM reg */ -#define MI_SET_RDRAM 0x2000 /* Bit 13: set RDRAM reg mode */ - -#define MI_MODE_INIT 0x0080 /* Bit 7: init mode */ -#define MI_MODE_EBUS 0x0100 /* Bit 8: ebus test mode */ -#define MI_MODE_RDRAM 0x0200 /* Bit 9: RDRAM reg mode */ - -#define MI_INTR_MASK_CLR_SP 0x0001 /* Bit 0: clear SP mask */ -#define MI_INTR_MASK_SET_SP 0x0002 /* Bit 1: set SP mask */ -#define MI_INTR_MASK_CLR_SI 0x0004 /* Bit 2: clear SI mask */ -#define MI_INTR_MASK_SET_SI 0x0008 /* Bit 3: set SI mask */ -#define MI_INTR_MASK_CLR_AI 0x0010 /* Bit 4: clear AI mask */ -#define MI_INTR_MASK_SET_AI 0x0020 /* Bit 5: set AI mask */ -#define MI_INTR_MASK_CLR_VI 0x0040 /* Bit 6: clear VI mask */ -#define MI_INTR_MASK_SET_VI 0x0080 /* Bit 7: set VI mask */ -#define MI_INTR_MASK_CLR_PI 0x0100 /* Bit 8: clear PI mask */ -#define MI_INTR_MASK_SET_PI 0x0200 /* Bit 9: set PI mask */ -#define MI_INTR_MASK_CLR_DP 0x0400 /* Bit 10: clear DP mask */ -#define MI_INTR_MASK_SET_DP 0x0800 /* Bit 11: set DP mask */ - -#define MI_INTR_MASK_SP 0x01 /* Bit 0: SP intr mask */ -#define MI_INTR_MASK_SI 0x02 /* Bit 1: SI intr mask */ -#define MI_INTR_MASK_AI 0x04 /* Bit 2: AI intr mask */ -#define MI_INTR_MASK_VI 0x08 /* Bit 3: VI intr mask */ -#define MI_INTR_MASK_PI 0x10 /* Bit 4: PI intr mask */ -#define MI_INTR_MASK_DP 0x20 /* Bit 5: DP intr mask */ - -#define MI_INTR_SP 0x01 /* Bit 0: SP intr */ -#define MI_INTR_SI 0x02 /* Bit 1: SI intr */ -#define MI_INTR_AI 0x04 /* Bit 2: AI intr */ -#define MI_INTR_VI 0x08 /* Bit 3: VI intr */ -#define MI_INTR_PI 0x10 /* Bit 4: PI intr */ -#define MI_INTR_DP 0x20 /* Bit 5: DP intr */ - -#define PI_STATUS_DMA_BUSY 0x01 -#define PI_STATUS_IO_BUSY 0x02 -#define PI_STATUS_ERROR 0x04 - -#define PI_SET_RESET 0x01 -#define PI_CLR_INTR 0x02 - -#define SI_STATUS_DMA_BUSY 0x0001 -#define SI_STATUS_RD_BUSY 0x0002 -#define SI_STATUS_DMA_ERROR 0x0008 -#define SI_STATUS_INTERRUPT 0x1000 - -#define FPCSR_FS 0x01000000 /* flush denorm to zero */ -#define FPCSR_C 0x00800000 /* condition bit */ -#define FPCSR_CE 0x00020000 /* cause: unimplemented operation */ -#define FPCSR_CV 0x00010000 /* cause: invalid operation */ -#define FPCSR_CZ 0x00008000 /* cause: division by zero */ -#define FPCSR_CO 0x00004000 /* cause: overflow */ -#define FPCSR_CU 0x00002000 /* cause: underflow */ -#define FPCSR_CI 0x00001000 /* cause: inexact operation */ -#define FPCSR_EV 0x00000800 /* enable: invalid operation */ -#define FPCSR_EZ 0x00000400 /* enable: division by zero */ -#define FPCSR_EO 0x00000200 /* enable: overflow */ -#define FPCSR_EU 0x00000100 /* enable: underflow */ -#define FPCSR_EI 0x00000080 /* enable: inexact operation */ -#define FPCSR_FV 0x00000040 /* flag: invalid operation */ -#define FPCSR_FZ 0x00000020 /* flag: division by zero */ -#define FPCSR_FO 0x00000010 /* flag: overflow */ -#define FPCSR_FU 0x00000008 /* flag: underflow */ -#define FPCSR_FI 0x00000004 /* flag: inexact operation */ -#define FPCSR_RM_MASK 0x00000003 /* rounding mode mask */ -#define FPCSR_RM_RN 0x00000000 /* round to nearest */ -#define FPCSR_RM_RZ 0x00000001 /* round to zero */ -#define FPCSR_RM_RP 0x00000002 /* round to positive infinity */ -#define FPCSR_RM_RM 0x00000003 /* round to negative infinity */ - -#define FPR_Type(Reg) (Reg) == R4300i_COP1_S ? "S" : (Reg) == R4300i_COP1_D ? "D" :\ - (Reg) == R4300i_COP1_W ? "W" : "L" - -typedef struct { - uint32_t PROGRAM_COUNTER; - MIPS_DWORD GPR[32]; - MIPS_DWORD FPR[32]; - uint32_t CP0[33]; - uint32_t FPCR[32]; - MIPS_DWORD HI; - MIPS_DWORD LO; - uint32_t RDRAM[10]; - uint32_t SP[10]; - uint32_t DPC[10]; - uint32_t MI[4]; - uint32_t VI[14]; - uint32_t AI[6]; - uint32_t PI[13]; - uint32_t RI[8]; - uint32_t SI[4]; - int8_t PIF_Ram[0x40]; -} N64_REGISTERS; - -enum FPU_Format { - FPU_Unkown,FPU_Dword, FPU_Qword, FPU_Float, FPU_Double -}; - -enum FPU_RoundingModel { - RoundUnknown, RoundDefault, RoundTruncate, RoundNearest, RoundDown, RoundUp -}; - -void ChangeMiIntrMask ( usf_state_t * ); -void ChangeMiModeReg ( usf_state_t * ); -void ChangeSpStatus ( usf_state_t * ); -void InitalizeR4300iRegisters ( usf_state_t * ); -void UpdateCurrentHalfLine ( usf_state_t * ); -void SetFpuLocations ( usf_state_t * ); - -void SetupRegisters(usf_state_t *, N64_REGISTERS * n64_Registers); - -#endif diff --git a/Frameworks/lazyusf/lazyusf/ri/rdram.c b/Frameworks/lazyusf/lazyusf/ri/rdram.c new file mode 100644 index 000000000..782f08fd1 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/rdram.c @@ -0,0 +1,118 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdram.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "usf/barray.h" + +#include "rdram.h" +#include "ri_controller.h" + +#include "memory/memory.h" + +#include + +void connect_rdram(struct rdram* rdram, + uint32_t* dram, + size_t dram_size) +{ + rdram->dram = dram; + rdram->dram_size = dram_size; +} + +void init_rdram(struct rdram* rdram) +{ + memset(rdram->regs, 0, RDRAM_REGS_COUNT*sizeof(uint32_t)); + memset(rdram->dram, 0, rdram->dram_size); +} + + +int read_rdram_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t reg = rdram_reg(address); + + *value = ri->rdram.regs[reg]; + + return 0; +} + +int write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t reg = rdram_reg(address); + + masked_write(&ri->rdram.regs[reg], value, mask); + + return 0; +} + + +int read_rdram_dram(void* opaque, uint32_t address, uint32_t* value) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t addr = rdram_dram_address(address); + + *value = ri->rdram.dram[addr]; + + return 0; +} + +int write_rdram_dram(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t addr = rdram_dram_address(address); + + masked_write(&ri->rdram.dram[addr], value, mask); + + return 0; +} + +int read_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t* value) +{ + usf_state_t* state = (usf_state_t*) opaque; + struct ri_controller* ri = &state->g_ri; + uint32_t addr = rdram_dram_address(address); + + if (!bit_array_test(state->barray_ram_written_first, addr / 4)) + bit_array_set(state->barray_ram_read, addr / 4); + + *value = ri->rdram.dram[addr]; + + return 0; +} + +int write_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + usf_state_t* state = (usf_state_t*) opaque; + struct ri_controller* ri = &state->g_ri; + uint32_t addr = rdram_dram_address(address); + + if (mask && !bit_array_test(state->barray_ram_read, addr / 4)) + bit_array_set(state->barray_ram_written_first, addr / 4); + + masked_write(&ri->rdram.dram[addr], value, mask); + + return 0; +} + diff --git a/Frameworks/lazyusf/lazyusf/ri/rdram.h b/Frameworks/lazyusf/lazyusf/ri/rdram.h new file mode 100644 index 000000000..bdc1c0a64 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/rdram.h @@ -0,0 +1,77 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdram.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_RI_RDRAM_H +#define M64P_RI_RDRAM_H + +#include +#include + +enum rdram_registers +{ + RDRAM_CONFIG_REG, + RDRAM_DEVICE_ID_REG, + RDRAM_DELAY_REG, + RDRAM_MODE_REG, + RDRAM_REF_INTERVAL_REG, + RDRAM_REF_ROW_REG, + RDRAM_RAS_INTERVAL_REG, + RDRAM_MIN_INTERVAL_REG, + RDRAM_ADDR_SELECT_REG, + RDRAM_DEVICE_MANUF_REG, + RDRAM_REGS_COUNT +}; + +struct rdram +{ + uint32_t regs[RDRAM_REGS_COUNT]; + uint32_t* dram; + size_t dram_size; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t rdram_reg(uint32_t address) +{ + return (address & 0x3ff) >> 2; +} + +static osal_inline uint32_t rdram_dram_address(uint32_t address) +{ + return (address & 0xffffff) >> 2; +} + +void connect_rdram(struct rdram* rdram, + uint32_t* dram, + size_t dram_size); + +void init_rdram(struct rdram* rdram); + +int read_rdram_regs(void* opaque, uint32_t address, uint32_t* value); +int write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_rdram_dram(void* opaque, uint32_t address, uint32_t* value); +int write_rdram_dram(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t* value); +int write_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.c b/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.c new file mode 100644 index 000000000..82c16bb4c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdram_detection_hack.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "rdram_detection_hack.h" +#include "ri_controller.h" + +#include "main/main.h" +#include "si/si_controller.h" + +#include + +/* HACK: force detected RDRAM size + * This hack is triggered just before initial ROM loading (see pi_controller.c) + * + * Proper emulation of RI/RDRAM subsystem is required to avoid this hack. + */ +void force_detected_rdram_size_hack(usf_state_t * state) +{ + uint32_t address = (state->g_si.pif.cic.version != CIC_X105) + ? 0x318 + : 0x3f0; + + state->g_ri.rdram.dram[address/4] = state->g_ri.rdram.dram_size; +} + diff --git a/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.h b/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.h new file mode 100644 index 000000000..9e7e3a743 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/rdram_detection_hack.h @@ -0,0 +1,27 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rdram_detection_hack.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_RI_RDRAM_DETECTION_HACK_H +#define M64P_RI_RDRAM_DETECTION_HACK_H + +void force_detected_rdram_size_hack(usf_state_t *); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/ri/ri_controller.c b/Frameworks/lazyusf/lazyusf/ri/ri_controller.c new file mode 100644 index 000000000..b5a3fc25d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/ri_controller.c @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - ri_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "ri_controller.h" + +#include "memory/memory.h" + +#include + +void connect_ri(struct ri_controller* ri, + uint32_t* dram, + size_t dram_size) +{ + connect_rdram(&ri->rdram, dram, dram_size); +} + +void init_ri(struct ri_controller* ri) +{ + memset(ri->regs, 0, RI_REGS_COUNT*sizeof(uint32_t)); + + init_rdram(&ri->rdram); +} + + +int read_ri_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t reg = ri_reg(address); + + *value = ri->regs[reg]; + + return 0; +} + +int write_ri_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct ri_controller* ri = (struct ri_controller*)opaque; + uint32_t reg = ri_reg(address); + + masked_write(&ri->regs[reg], value, mask); + + return 0; +} + diff --git a/Frameworks/lazyusf/lazyusf/ri/ri_controller.h b/Frameworks/lazyusf/lazyusf/ri/ri_controller.h new file mode 100644 index 000000000..24ddf16f2 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/ri/ri_controller.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - ri_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_RI_RI_CONTROLLER_H +#define M64P_RI_RI_CONTROLLER_H + +#include + +#include "rdram.h" + +enum ri_registers +{ + RI_MODE_REG, + RI_CONFIG_REG, + RI_CURRENT_LOAD_REG, + RI_SELECT_REG, + RI_REFRESH_REG, + RI_LATENCY_REG, + RI_ERROR_REG, + RI_WERROR_REG, + RI_REGS_COUNT +}; + +struct ri_controller +{ + uint32_t regs[RI_REGS_COUNT]; + + struct rdram rdram; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t ri_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +void connect_ri(struct ri_controller* ri, + uint32_t* dram, + size_t dram_size); + +void init_ri(struct ri_controller* ri); + +int read_ri_regs(void* opaque, uint32_t address, uint32_t* value); +int write_ri_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/rsp.h b/Frameworks/lazyusf/lazyusf/rsp.h deleted file mode 100644 index 7dce5e512..000000000 --- a/Frameworks/lazyusf/lazyusf/rsp.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef RSP_H -#define RSP_H - -#include "usf.h" -#include "usf_internal.h" - -void real_run_rsp(usf_state_t *, uint32_t cycles); - -int32_t init_rsp(usf_state_t *); - -#endif diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp.c b/Frameworks/lazyusf/lazyusf/rsp/rsp.c deleted file mode 100644 index 780122b8a..000000000 --- a/Frameworks/lazyusf/lazyusf/rsp/rsp.c +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************************************\ -* Authors: Iconoclast * -* Release: 2013.12.12 * -* License: CC0 Public Domain Dedication * -* * -* To the extent possible under law, the author(s) have dedicated all copyright * -* and related and neighboring rights to this software to the public domain * -* worldwide. This software is distributed without any warranty. * -* * -* You should have received a copy of the CC0 Public Domain Dedication along * -* with this software. * -* If not, see . * -\******************************************************************************/ - -#include -#include -#include -#include - -#include "../usf.h" - -#include "../dma.h" -#include "../exception.h" -#include "../main.h" -#include "../memory.h" -#include "../registers.h" - -#include "../usf_internal.h" - -#undef JUMP - -#include "config.h" - -#include "rsp.h" - -#include "../rsp_hle/hle.h" - -void real_run_rsp(usf_state_t * state, uint32_t cycles) -{ - (void)cycles; - - if (SP_STATUS_REG & 0x00000003) - { - message(state, "SP_STATUS_HALT", 3); - return; - } - switch (*(unsigned int *)(state->DMEM + 0xFC0)) - { /* Simulation barrier to redirect processing externally. */ - case 0x00000002: /* OSTask.type == M_AUDTASK */ - if (state->enable_hle_audio == 0) - break; - hle_execute(&state->hle); - SP_STATUS_REG |= 0x00000203; - if (SP_STATUS_REG & 0x00000040) /* SP_STATUS_INTR_BREAK */ - { - MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */ - CheckInterrupts(state); - } - return; - } - run_task(state); - return; -} - -int32_t init_rsp(usf_state_t * state) -{ - state->CR[0x0] = &SP_MEM_ADDR_REG; - state->CR[0x1] = &SP_DRAM_ADDR_REG; - state->CR[0x2] = &SP_RD_LEN_REG; - state->CR[0x3] = &SP_WR_LEN_REG; - state->CR[0x4] = &SP_STATUS_REG; - state->CR[0x5] = &SP_DMA_FULL_REG; - state->CR[0x6] = &SP_DMA_BUSY_REG; - state->CR[0x7] = &SP_SEMAPHORE_REG; - state->CR[0x8] = &DPC_START_REG; - state->CR[0x9] = &DPC_END_REG; - state->CR[0xA] = &DPC_CURRENT_REG; - state->CR[0xB] = &DPC_STATUS_REG; - state->CR[0xC] = &DPC_CLOCK_REG; - state->CR[0xD] = &DPC_BUFBUSY_REG; - state->CR[0xE] = &DPC_PIPEBUSY_REG; - state->CR[0xF] = &DPC_TMEM_REG; - - hle_init(&state->hle, - state->N64MEM, - state->DMEM, - state->IMEM, - &MI_INTR_REG, - &SP_MEM_ADDR_REG, - &SP_DRAM_ADDR_REG, - &SP_RD_LEN_REG, - &SP_WR_LEN_REG, - &SP_STATUS_REG, - &SP_DMA_FULL_REG, - &SP_DMA_BUSY_REG, - &SP_PC_REG, - &SP_SEMAPHORE_REG, - &DPC_START_REG, - &DPC_END_REG, - &DPC_CURRENT_REG, - &DPC_STATUS_REG, - &DPC_CLOCK_REG, - &DPC_BUFBUSY_REG, - &DPC_PIPEBUSY_REG, - &DPC_TMEM_REG, - state); - - return 0; -} diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp_core.c b/Frameworks/lazyusf/lazyusf/rsp/rsp_core.c new file mode 100644 index 000000000..fcafc3af8 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp/rsp_core.c @@ -0,0 +1,364 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rsp_core.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "rsp_lle/rsp_lle.h" + +#include "rsp_core.h" + +#include "main/main.h" +#include "memory/memory.h" +#include "r4300/cp0.h" +#include "r4300/r4300_core.h" +#include "r4300/interupt.h" +#include "rdp/rdp_core.h" +#include "ri/ri_controller.h" + +#include + +void dma_sp_write(struct rsp_core* sp) +{ + unsigned int i,j; + + unsigned int l = sp->regs[SP_RD_LEN_REG]; + + unsigned int length = ((l & 0xfff) | 7) + 1; + unsigned int count = ((l >> 12) & 0xff) + 1; + unsigned int skip = ((l >> 20) & 0xfff); + + unsigned int memaddr = sp->regs[SP_MEM_ADDR_REG] & 0xfff; + unsigned int dramaddr = sp->regs[SP_DRAM_ADDR_REG] & 0xffffff; + + unsigned char *spmem = (unsigned char*)sp->mem + (sp->regs[SP_MEM_ADDR_REG] & 0x1000); + unsigned char *dram = (unsigned char*)sp->ri->rdram.dram; + + for(j=0; jregs[SP_WR_LEN_REG]; + + unsigned int length = ((l & 0xfff) | 7) + 1; + unsigned int count = ((l >> 12) & 0xff) + 1; + unsigned int skip = ((l >> 20) & 0xfff); + + unsigned int memaddr = sp->regs[SP_MEM_ADDR_REG] & 0xfff; + unsigned int dramaddr = sp->regs[SP_DRAM_ADDR_REG] & 0xffffff; + + unsigned char *spmem = (unsigned char*)sp->mem + (sp->regs[SP_MEM_ADDR_REG] & 0x1000); + unsigned char *dram = (unsigned char*)sp->ri->rdram.dram; + + for(j=0; jregs[SP_STATUS_REG] &= ~0x1; + if (w & 0x2) sp->regs[SP_STATUS_REG] |= 0x1; + + /* clear broke */ + if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~0x2; + + /* clear SP interrupt */ + if (w & 0x8) + { + clear_rcp_interrupt(sp->r4300, MI_INTR_SP); + } + /* set SP interrupt */ + if (w & 0x10) + { + signal_rcp_interrupt(sp->r4300, MI_INTR_SP); + } + + /* clear / set single step */ + if (w & 0x20) sp->regs[SP_STATUS_REG] &= ~0x20; + if (w & 0x40) sp->regs[SP_STATUS_REG] |= 0x20; + + /* clear / set interrupt on break */ + if (w & 0x80) sp->regs[SP_STATUS_REG] &= ~0x40; + if (w & 0x100) sp->regs[SP_STATUS_REG] |= 0x40; + + /* clear / set signal 0 */ + if (w & 0x200) sp->regs[SP_STATUS_REG] &= ~0x80; + if (w & 0x400) sp->regs[SP_STATUS_REG] |= 0x80; + + /* clear / set signal 1 */ + if (w & 0x800) sp->regs[SP_STATUS_REG] &= ~0x100; + if (w & 0x1000) sp->regs[SP_STATUS_REG] |= 0x100; + + /* clear / set signal 2 */ + if (w & 0x2000) sp->regs[SP_STATUS_REG] &= ~0x200; + if (w & 0x4000) sp->regs[SP_STATUS_REG] |= 0x200; + + /* clear / set signal 3 */ + if (w & 0x8000) sp->regs[SP_STATUS_REG] &= ~0x400; + if (w & 0x10000) sp->regs[SP_STATUS_REG] |= 0x400; + + /* clear / set signal 4 */ + if (w & 0x20000) sp->regs[SP_STATUS_REG] &= ~0x800; + if (w & 0x40000) sp->regs[SP_STATUS_REG] |= 0x800; + + /* clear / set signal 5 */ + if (w & 0x80000) sp->regs[SP_STATUS_REG] &= ~0x1000; + if (w & 0x100000) sp->regs[SP_STATUS_REG] |= 0x1000; + + /* clear / set signal 6 */ + if (w & 0x200000) sp->regs[SP_STATUS_REG] &= ~0x2000; + if (w & 0x400000) sp->regs[SP_STATUS_REG] |= 0x2000; + + /* clear / set signal 7 */ + if (w & 0x800000) sp->regs[SP_STATUS_REG] &= ~0x4000; + if (w & 0x1000000) sp->regs[SP_STATUS_REG] |= 0x4000; + + //if (get_event(SP_INT)) return; + if (!(w & 0x1) && !(w & 0x4)) + return; + + if (!(sp->regs[SP_STATUS_REG] & 0x3)) // !halt && !broke + do_SP_Task(sp); +} + +void connect_rsp(struct rsp_core* sp, + struct r4300_core* r4300, + struct rdp_core* dp, + struct ri_controller* ri) +{ + sp->r4300 = r4300; + sp->dp = dp; + sp->ri = ri; + + init_rsp_lle(r4300->state); +} + +void init_rsp(struct rsp_core* sp) +{ + memset(sp->mem, 0, SP_MEM_SIZE); + memset(sp->regs, 0, SP_REGS_COUNT*sizeof(uint32_t)); + memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t)); + + sp->regs[SP_STATUS_REG] = 1; +} + + +int read_rsp_mem(void* opaque, uint32_t address, uint32_t* value) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t addr = rsp_mem_address(address); + + *value = sp->mem[addr]; + + return 0; +} + +int write_rsp_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t addr = rsp_mem_address(address); + + masked_write(&sp->mem[addr], value, mask); + + return 0; +} + + +int read_rsp_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t reg = rsp_reg(address); + + *value = sp->regs[reg]; + + if (reg == SP_SEMAPHORE_REG) + { + sp->regs[SP_SEMAPHORE_REG] = 1; + } + + return 0; +} + +int write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t reg = rsp_reg(address); + + switch(reg) + { + case SP_STATUS_REG: + update_sp_status(sp, value & mask); + case SP_DMA_FULL_REG: + case SP_DMA_BUSY_REG: + return 0; + } + + masked_write(&sp->regs[reg], value, mask); + + switch(reg) + { + case SP_RD_LEN_REG: + dma_sp_write(sp); + break; + case SP_WR_LEN_REG: + dma_sp_read(sp); + break; + case SP_SEMAPHORE_REG: + sp->regs[SP_SEMAPHORE_REG] = 0; + break; + } + + return 0; +} + + +int read_rsp_regs2(void* opaque, uint32_t address, uint32_t* value) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t reg = rsp_reg2(address); + + *value = sp->regs2[reg]; + + return 0; +} + +int write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + uint32_t reg = rsp_reg2(address); + + masked_write(&sp->regs2[reg], value, mask); + + return 0; +} + +void do_SP_Task(struct rsp_core* sp) +{ +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, "RSP Task"); +#endif + uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff; + if (sp->mem[0xfc0/4] == 1) + { +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, " - DList"); +#endif + if (sp->dp->dpc_regs[DPC_STATUS_REG] & 0x2) // DP frozen (DK64, BC) + { +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, " - frozen!\n"); +#endif + // don't do the task now + // the task will be done when DP is unfreezed (see update_dpc_status) + return; + } + + //gfx.processDList(); + sp->regs2[SP_PC_REG] &= 0xfff; + real_run_rsp(sp->r4300->state, 0xffffffff); + sp->regs2[SP_PC_REG] |= save_pc; + + update_count(sp->r4300->state); + if (sp->r4300->mi.regs[MI_INTR_REG] & MI_INTR_SP) + add_interupt_event(sp->r4300->state, SP_INT, sp->r4300->state->g_delay_sp ? 1000 : 0); + if (sp->r4300->mi.regs[MI_INTR_REG] & MI_INTR_DP) + add_interupt_event(sp->r4300->state, DP_INT, sp->r4300->state->g_delay_dp ? 1000 : 0); +#ifdef DEBUG_INFO + if (sp->r4300->mi.regs[MI_INTR_REG]) + fprintf(sp->r4300->state->debug_log, " - interrupts fired %d", sp->r4300->mi.regs[MI_INTR_REG]); +#endif + sp->r4300->mi.regs[MI_INTR_REG] &= ~(MI_INTR_SP | MI_INTR_DP); + sp->regs[SP_STATUS_REG] &= ~0x303; + } + else if (sp->mem[0xfc0/4] == 2) + { +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, " - AList"); +#endif + //audio.processAList(); + sp->regs2[SP_PC_REG] &= 0xfff; + real_run_rsp(sp->r4300->state, 0xffffffff); + sp->regs2[SP_PC_REG] |= save_pc; + + update_count(sp->r4300->state); + if (sp->r4300->mi.regs[MI_INTR_REG] & MI_INTR_SP) + add_interupt_event(sp->r4300->state, SP_INT, sp->r4300->state->g_delay_sp ? 4000/*500*/: 0); +#ifdef DEBUG_INFO + if (sp->r4300->mi.regs[MI_INTR_REG]) + fprintf(sp->r4300->state->debug_log, " - interrupt fired %d", sp->r4300->mi.regs[MI_INTR_REG]); +#endif + sp->r4300->mi.regs[MI_INTR_REG] &= ~MI_INTR_SP; + sp->regs[SP_STATUS_REG] &= ~0x303; + + } + else + { +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, " - Unknown task"); +#endif + sp->regs2[SP_PC_REG] &= 0xfff; + real_run_rsp(sp->r4300->state, 0xffffffff); + sp->regs2[SP_PC_REG] |= save_pc; + + update_count(sp->r4300->state); + if (sp->r4300->mi.regs[MI_INTR_REG] & MI_INTR_SP) + { + add_interupt_event(sp->r4300->state, SP_INT, 0/*100*/); + } +#ifdef DEBUG_INFO + if (sp->r4300->mi.regs[MI_INTR_REG]) + fprintf(sp->r4300->state->debug_log, " - interrupt fired %d", sp->r4300->mi.regs[MI_INTR_REG]); +#endif + sp->r4300->mi.regs[MI_INTR_REG] &= ~MI_INTR_SP; + sp->regs[SP_STATUS_REG] &= ~0x203; + } +#ifdef DEBUG_INFO + fprintf(sp->r4300->state->debug_log, "\n"); +#endif +} + +void rsp_interrupt_event(struct rsp_core* sp) +{ + sp->regs[SP_STATUS_REG] |= 0x203; + + if ((sp->regs[SP_STATUS_REG] & 0x40) != 0) + { + raise_rcp_interrupt(sp->r4300, MI_INTR_SP); + } +} diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp_core.h b/Frameworks/lazyusf/lazyusf/rsp/rsp_core.h new file mode 100644 index 000000000..37a9fb42b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp/rsp_core.h @@ -0,0 +1,110 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - rsp_core.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_RSP_RSP_CORE_H +#define M64P_RSP_RSP_CORE_H + +#include + +struct r4300_core; +struct rdp_core; +struct ri_controller; + +enum { SP_MEM_SIZE = 0x2000 }; + +enum sp_registers +{ + SP_MEM_ADDR_REG, + SP_DRAM_ADDR_REG, + SP_RD_LEN_REG, + SP_WR_LEN_REG, + SP_STATUS_REG, + SP_DMA_FULL_REG, + SP_DMA_BUSY_REG, + SP_SEMAPHORE_REG, + SP_REGS_COUNT +}; + +enum sp_registers2 +{ + SP_PC_REG, + SP_IBIST_REG, + SP_REGS2_COUNT +}; + +enum +{ + SP_STATUS_INTR_BREAK = 0x040 +}; + +struct rsp_core +{ + uint32_t mem[SP_MEM_SIZE/4]; + uint32_t regs[SP_REGS_COUNT]; + uint32_t regs2[SP_REGS2_COUNT]; + + struct r4300_core* r4300; + struct rdp_core* dp; + struct ri_controller* ri; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t rsp_mem_address(uint32_t address) +{ + return (address & 0x1fff) >> 2; +} + +static osal_inline uint32_t rsp_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +static osal_inline uint32_t rsp_reg2(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +void connect_rsp(struct rsp_core* sp, + struct r4300_core* r4300, + struct rdp_core* dp, + struct ri_controller* ri); + +void init_rsp(struct rsp_core* sp); + +int read_rsp_mem(void* opaque, uint32_t address, uint32_t* value); +int write_rsp_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_rsp_regs(void* opaque, uint32_t address, uint32_t* value); +int write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +int read_rsp_regs2(void* opaque, uint32_t address, uint32_t* value); +int write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void do_SP_Task(struct rsp_core* sp); + +void rsp_interrupt_event(struct rsp_core* sp); + +// For use by the LLE RSP +void dma_sp_write(struct rsp_core* sp); +void dma_sp_read(struct rsp_core* sp); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c index 2f32bdc93..4d5a965dd 100644 --- a/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c @@ -25,9 +25,10 @@ #include #include -#include "../usf.h" -#include "../main.h" -#include "../usf_internal.h" +#include "usf/usf.h" +#include "usf/usf_internal.h" + +#include "r4300/interupt.h" #include "hle.h" @@ -54,7 +55,7 @@ void HleErrorMessage(void* user_defined, const char *message, ...) va_end( ap ); state->last_error = state->error_message; - StopEmulation( state ); + state->stop = 1; } void HleWarnMessage(void* user_defined, const char *message, ...) @@ -74,17 +75,18 @@ void HleWarnMessage(void* user_defined, const char *message, ...) va_end( ap ); state->last_error = state->error_message; - StopEmulation( state ); + state->stop = 1; } void HleCheckInterrupts(void* user_defined) { - CheckInterrupts((usf_state_t*)user_defined); + //check_interupt((usf_state_t*)user_defined); } void HleProcessDlistList(void* user_defined) { - /* disabled */ + usf_state_t * state = (usf_state_t *) user_defined; + state->g_r4300.mi.regs[MI_INTR_REG] |= MI_INTR_DP; } void HleProcessAlistList(void* user_defined) diff --git a/Frameworks/lazyusf/lazyusf/rsp_lle/bench.c b/Frameworks/lazyusf/lazyusf/rsp_lle/bench.c new file mode 100644 index 000000000..61f353805 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/bench.c @@ -0,0 +1,227 @@ +/******************************************************************************\ +* Project: Simple Vector Unit Benchmark * +* Authors: Iconoclast * +* Release: 2013.12.12 * +* License: CC0 Public Domain Dedication * +* * +* To the extent possible under law, the author(s) have dedicated all copyright * +* and related and neighboring rights to this software to the public domain * +* worldwide. This software is distributed without any warranty. * +* * +* You should have received a copy of the CC0 Public Domain Dedication along * +* with this software. * +* If not, see . * +\******************************************************************************/ + +/* + * Since operations on scalar registers are much more predictable, + * standardized, and documented, we don't really need to bench those. + * + * I was thinking I should also add MTC0 (SP DMA and writes to SP_STATUS_REG) + * and, due to the SSE-style flags register file, CFC2 and CTC2, but I mostly + * just wanted to hurry up and make this header quick with all the basics. :P + * + * Fortunately, because all the methods are static (no conditional jumps), + * we can lazily leave the instruction word set to 0x00000000 for all the + * op-codes we are benching, and it will make no difference in speed. + */ + +#include +#include +#include +#include + +#include "../usf.h" + +#include "../usf_internal.h" + +#undef JUMP + +#define DisplayError(...) + +#include "config.h" +#include "matrix.h" +#include "rsp.h" + +#define NUMBER_OF_VU_OPCODES 38 + +ALIGNED usf_state_t state; + +void CheckInterrupts(usf_state_t * state) +{ + (void)state; + return; +} + +void SP_DMA_READ(usf_state_t * state) +{ + (void)state; + return; +} + +void SP_DMA_WRITE(usf_state_t * state) +{ + (void)state; + return; +} + +static void (*bench_tests[NUMBER_OF_VU_OPCODES])(usf_state_t *, int, int, int, int) = { + VMULF, VMACF, /* signed single-precision fractions */ + VMULU, VMACU, /* unsigned single-precision fractions */ + + VMUDL, VMADL, /* double-precision multiplies using partial products */ + VMUDM, VMADM, + VMUDN, VMADN, + VMUDH, VMADH, + + VADD, VSUB, VABS, + VADDC, VSUBC, + VSAW, + + VEQ, VNE, VLT, VGE, /* normal select compares */ + VCH, VCL, /* double-precision clip select */ + VCR, /* single-precision, one's complement */ + VMRG, + + VAND, VNAND, + VOR , VNOR , + VXOR, VNXOR, + + VRCPL, VRSQL, /* double-precision reciprocal look-ups */ + VRCPH, VRSQH, + + VMOV, VNOP +}; + +enum { + SP_VMULF = 000, + SP_VMULU = 001, + SP_VRNDP = 002, + SP_VMULQ = 003, + SP_VMUDL = 004, + SP_VMUDM = 005, + SP_VMUDN = 006, + SP_VMUDH = 007, + SP_VMACF = 010, + SP_VMACU = 011, + SP_VRNDN = 012, + SP_VMACQ = 013, + SP_VMADL = 014, + SP_VMADM = 015, + SP_VMADN = 016, + SP_VMADH = 017, + SP_VADD = 020, + SP_VSUB = 021, + SP_VSUT = 022, + SP_VABS = 023, + SP_VADDC = 024, + SP_VSUBC = 025, + SP_VADDB = 026, + SP_VSUBB = 027, + SP_VACCB = 030, + SP_VSUCB = 031, + SP_VSAD = 032, + SP_VSAC = 033, + SP_VSUM = 034, + SP_VSAW = 035, + + + SP_VLT = 040, + SP_VEQ = 041, + SP_VNE = 042, + SP_VGE = 043, + SP_VCL = 044, + SP_VCH = 045, + SP_VCR = 046, + SP_VMRG = 047, + SP_VAND = 050, + SP_VNAND = 051, + SP_VOR = 052, + SP_VNOR = 053, + SP_VXOR = 054, + SP_VNXOR = 055, + + + SP_VRCP = 060, + SP_VRCPL = 061, + SP_VRCPH = 062, + SP_VMOV = 063, + SP_VRSQ = 064, + SP_VRSQL = 065, + SP_VRSQH = 066, + SP_VNOP = 067, + SP_VEXTT = 070, + SP_VEXTQ = 071, + SP_VEXTN = 072, + + SP_VINST = 074, + SP_VINSQ = 075, + SP_VINSN = 076, + SP_VNULLOP= 077 +}; +const char* test_names[NUMBER_OF_VU_OPCODES] = { + mnemonics_C2[SP_VMULF], mnemonics_C2[SP_VMACF], + mnemonics_C2[SP_VMULU], mnemonics_C2[SP_VMACU], + + mnemonics_C2[SP_VMUDL], mnemonics_C2[SP_VMADL], + mnemonics_C2[SP_VMUDM], mnemonics_C2[SP_VMADM], + mnemonics_C2[SP_VMUDN], mnemonics_C2[SP_VMADN], + mnemonics_C2[SP_VMUDH], mnemonics_C2[SP_VMADH], + + mnemonics_C2[SP_VADD], mnemonics_C2[SP_VSUB], mnemonics_C2[SP_VABS], + mnemonics_C2[SP_VADDC], mnemonics_C2[SP_VSUBC], + mnemonics_C2[SP_VSAW], + + mnemonics_C2[SP_VEQ], mnemonics_C2[SP_VNE], + mnemonics_C2[SP_VLT], mnemonics_C2[SP_VGE], + mnemonics_C2[SP_VCH], mnemonics_C2[SP_VCL], + mnemonics_C2[SP_VCR], + mnemonics_C2[SP_VMRG], + + mnemonics_C2[SP_VAND], mnemonics_C2[SP_VNAND], + mnemonics_C2[SP_VOR] , mnemonics_C2[SP_VNOR] , + mnemonics_C2[SP_VXOR], mnemonics_C2[SP_VNXOR], + + mnemonics_C2[SP_VRCPL], mnemonics_C2[SP_VRSQL], + mnemonics_C2[SP_VRCPH], mnemonics_C2[SP_VRSQH], + + mnemonics_C2[SP_VMOV], mnemonics_C2[SP_VNOP], +}; + +const char* notice_starting = + "Ready to start benchmarks.\n"\ + "Close this message to commence tests. Testing could take minutes."; +const char* notice_finished = + "Finished writing benchmark results.\n"\ + "Check working emulator directory for \"sp_bench.txt\"."; + +int main(void) +{ + FILE* log; + clock_t t1, t2; + register int i, j; + register float delta, total; + + fputs(notice_starting, stderr); + log = fopen("sp_bench.txt", "w"); + fprintf(log, "RSP Vector Benchmarks Log\n\n"); + + total = 0.0; + for (i = 0; i < NUMBER_OF_VU_OPCODES; i++) + { + t1 = clock(); + for (j = -0x1000000; j < 0; j++) + bench_tests[i](&state, 0, 0, 0, 8); + t2 = clock(); + delta = (float)(t2 - t1) / CLOCKS_PER_SEC; + fprintf(log, "%s: %.3f s\n", test_names[i], delta); + fprintf(stderr, "%s: %.3f s\n", test_names[i], delta); + total += delta; + } + fprintf(log, "Total time spent: %.3f s\n", total); + fprintf(stderr, "Total time spent: %.3f s\n", total); + fclose(log); + fputs(notice_finished, stderr); + return 0; +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp/config.h b/Frameworks/lazyusf/lazyusf/rsp_lle/config.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/config.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/config.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/execute.h b/Frameworks/lazyusf/lazyusf/rsp_lle/execute.h similarity index 95% rename from Frameworks/lazyusf/lazyusf/rsp/execute.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/execute.h index 01801242b..fc5f022c6 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/execute.h +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/execute.h @@ -16,6 +16,8 @@ #include "su.h" #include "vu/vu.h" +#include "r4300/interupt.h" + #define FIT_IMEM(PC) (PC & 0xFFF & 0xFFC) NOINLINE void run_task(usf_state_t * state) @@ -33,8 +35,8 @@ NOINLINE void run_task(usf_state_t * state) for (i = 0; i < 32; i++) state->MFC0_count[i] = 0; } - PC = FIT_IMEM(SP_PC_REG); - while ((SP_STATUS_REG & 0x00000001) == 0x00000000) + PC = FIT_IMEM(state->g_sp.regs2[SP_PC_REG]); + while ((state->g_sp.regs[SP_STATUS_REG] & 0x00000001) == 0x00000000) { register uint32_t inst; @@ -115,11 +117,11 @@ EX: set_PC(state, state->SR[rs]); JUMP case 015: /* BREAK */ - SP_STATUS_REG |= 0x00000003; /* BROKE | HALT */ - if (SP_STATUS_REG & 0x00000040) + state->g_sp.regs[SP_STATUS_REG] |= 0x00000003; /* BROKE | HALT */ + if (state->g_sp.regs[SP_STATUS_REG] & 0x00000040) { /* SP_STATUS_INTR_BREAK */ - MI_INTR_REG |= 0x00000001; - CheckInterrupts(state); + state->g_r4300.mi.regs[MI_INTR_REG] |= 0x00000001; + //check_interupt(state); } CONTINUE case 040: /* ADD */ @@ -451,7 +453,7 @@ EX: { state->stage = 0*stage; PC = state->temp_PC & 0x00000FFC; - SP_PC_REG = state->temp_PC; + state->g_sp.regs2[SP_PC_REG] = state->temp_PC; } else { @@ -462,7 +464,7 @@ EX: message( state, "RSP execution presumably caught in an infinite loop", 3 ); break; } - SP_PC_REG = 0x04001000 + PC; + state->g_sp.regs2[SP_PC_REG] = PC; } continue; #else @@ -476,20 +478,20 @@ BRANCH: goto EX; #endif } - SP_PC_REG = 0x04001000 | FIT_IMEM(PC); - if (SP_STATUS_REG & 0x00000002) /* normal exit, from executing BREAK */ + state->g_sp.regs2[SP_PC_REG] = FIT_IMEM(PC); + if (state->g_sp.regs[SP_STATUS_REG] & 0x00000002) /* normal exit, from executing BREAK */ return; - else if (MI_INTR_REG & 0x00000001) /* interrupt set by MTC0 to break */ - CheckInterrupts(state); + else if (state->g_r4300.mi.regs[MI_INTR_REG] & 0x00000001) /* interrupt set by MTC0 to break */ + /*check_interupt(state)*/; else if (CFG_WAIT_FOR_CPU_HOST != 0) /* plugin system hack to re-sync */ {} - else if (SP_SEMAPHORE_REG != 0x00000000) /* semaphore lock fixes */ + else if (state->g_sp.regs[SP_SEMAPHORE_REG] != 0x00000000) /* semaphore lock fixes */ {} else /* ??? unknown, possibly external intervention from CPU memory map */ { message(state, "SP_SET_HALT", 3); return; } - SP_STATUS_REG &= ~0x00000001; /* CPU restarts with the correct SIGs. */ + state->g_sp.regs[SP_STATUS_REG] &= ~0x00000001; /* CPU restarts with the correct SIGs. */ return; } diff --git a/Frameworks/lazyusf/lazyusf/rsp/matrix.h b/Frameworks/lazyusf/lazyusf/rsp_lle/matrix.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/matrix.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/matrix.h diff --git a/Frameworks/lazyusf/lazyusf/rsp_lle/rsp.c b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp.c new file mode 100644 index 000000000..c03ff7947 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp.c @@ -0,0 +1,109 @@ +/******************************************************************************\ +* Authors: Iconoclast * +* Release: 2013.12.12 * +* License: CC0 Public Domain Dedication * +* * +* To the extent possible under law, the author(s) have dedicated all copyright * +* and related and neighboring rights to this software to the public domain * +* worldwide. This software is distributed without any warranty. * +* * +* You should have received a copy of the CC0 Public Domain Dedication along * +* with this software. * +* If not, see . * +\******************************************************************************/ + +#include +#include +#include +#include + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "api/callbacks.h" + +#undef JUMP + +#include "config.h" + +#include "rsp.h" + +#include "../rsp_hle/hle.h" + +void real_run_rsp(usf_state_t * state, uint32_t cycles) +{ + (void)cycles; + + if (state->g_sp.regs[SP_STATUS_REG] & 0x00000003) + { + message(state, "SP_STATUS_HALT", 3); + return; + } + switch (*(unsigned int *)(state->DMEM + 0xFC0)) + { /* Simulation barrier to redirect processing externally. */ + case 0x00000002: /* OSTask.type == M_AUDTASK */ + if (state->enable_hle_audio == 0) + break; + hle_execute(&state->hle); + return; + + /* XXX USF sets should not be processing DLists, but several of them + require them at least once to boot properly. And for some reason, + with this emulator core, Iconoclast's RSP core is not up to the + task of running the DLists, so this HLE will do instead. */ + case 0x00000001: + hle_execute(&state->hle); + return; + } + run_task(state); +} + +int32_t init_rsp_lle(usf_state_t * state) +{ + state->CR[0x0] = &state->g_sp.regs[SP_MEM_ADDR_REG]; + state->CR[0x1] = &state->g_sp.regs[SP_DRAM_ADDR_REG]; + state->CR[0x2] = &state->g_sp.regs[SP_RD_LEN_REG]; + state->CR[0x3] = &state->g_sp.regs[SP_WR_LEN_REG]; + state->CR[0x4] = &state->g_sp.regs[SP_STATUS_REG]; + state->CR[0x5] = &state->g_sp.regs[SP_DMA_FULL_REG]; + state->CR[0x6] = &state->g_sp.regs[SP_DMA_BUSY_REG]; + state->CR[0x7] = &state->g_sp.regs[SP_SEMAPHORE_REG]; + state->CR[0x8] = &state->g_dp.dpc_regs[DPC_START_REG]; + state->CR[0x9] = &state->g_dp.dpc_regs[DPC_END_REG]; + state->CR[0xA] = &state->g_dp.dpc_regs[DPC_CURRENT_REG]; + state->CR[0xB] = &state->g_dp.dpc_regs[DPC_STATUS_REG]; + state->CR[0xC] = &state->g_dp.dpc_regs[DPC_CLOCK_REG]; + state->CR[0xD] = &state->g_dp.dpc_regs[DPC_BUFBUSY_REG]; + state->CR[0xE] = &state->g_dp.dpc_regs[DPC_PIPEBUSY_REG]; + state->CR[0xF] = &state->g_dp.dpc_regs[DPC_TMEM_REG]; + + state->DMEM = (unsigned char *)state->g_sp.mem; + state->IMEM = (unsigned char *)state->g_sp.mem + 0x1000; + + hle_init(&state->hle, + (unsigned char *)state->g_rdram, + state->DMEM, + state->IMEM, + &state->g_r4300.mi.regs[MI_INTR_REG], + &state->g_sp.regs[SP_MEM_ADDR_REG], + &state->g_sp.regs[SP_DRAM_ADDR_REG], + &state->g_sp.regs[SP_RD_LEN_REG], + &state->g_sp.regs[SP_WR_LEN_REG], + &state->g_sp.regs[SP_STATUS_REG], + &state->g_sp.regs[SP_DMA_FULL_REG], + &state->g_sp.regs[SP_DMA_BUSY_REG], + &state->g_sp.regs[SP_PC_REG], + &state->g_sp.regs[SP_SEMAPHORE_REG], + &state->g_dp.dpc_regs[DPC_START_REG], + &state->g_dp.dpc_regs[DPC_END_REG], + &state->g_dp.dpc_regs[DPC_CURRENT_REG], + &state->g_dp.dpc_regs[DPC_STATUS_REG], + &state->g_dp.dpc_regs[DPC_CLOCK_REG], + &state->g_dp.dpc_regs[DPC_BUFBUSY_REG], + &state->g_dp.dpc_regs[DPC_PIPEBUSY_REG], + &state->g_dp.dpc_regs[DPC_TMEM_REG], + state); + + return 0; +} diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp.h b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp.h similarity index 97% rename from Frameworks/lazyusf/lazyusf/rsp/rsp.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/rsp.h index 0b40ccc91..5c7aeb19e 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/rsp.h +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp.h @@ -50,7 +50,7 @@ NOINLINE static void message(usf_state_t * state, const char* body, int priority (void)body; (void)priority; if ( priority > 1 ) - DisplayError( state, "%s", body ); + DebugMessage( state, 5, "%s", body ); } /* @@ -70,6 +70,8 @@ extern void step_SP_commands(usf_state_t * state, int PC, uint32_t inst); #include "su.h" #include "vu/vu.h" +int32_t init_rsp_lle(usf_state_t * state); + /* Allocate the RSP CPU loop to its own functional space. */ NOINLINE static void run_task(usf_state_t * state); #include "execute.h" diff --git a/Frameworks/lazyusf/lazyusf/rsp_lle/rsp_lle.h b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp_lle.h new file mode 100644 index 000000000..6ff4a4c26 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/rsp_lle.h @@ -0,0 +1,6 @@ +#ifndef _RSP_LLE_H +#define _RSP_LLE_H +int32_t init_rsp_lle(usf_state_t * state); +void real_run_rsp(usf_state_t * state, uint32_t cycles); +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp/su.h b/Frameworks/lazyusf/lazyusf/rsp_lle/su.h similarity index 92% rename from Frameworks/lazyusf/lazyusf/rsp/su.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/su.h index 248422e1a..20ee96800 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/su.h +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/su.h @@ -46,7 +46,7 @@ NOINLINE static void res_S(usf_state_t * state) #define LINK_OFF (BASE_OFF + 0x004) static void set_PC(usf_state_t * state, int address) { - state->temp_PC = 0x04001000 + (address & 0xFFC); + state->temp_PC = (address & 0xFFC); #ifndef EMULATE_STATIC_PC state->stage = 1; #endif @@ -93,8 +93,8 @@ static void MFC0(usf_state_t * state, int rt, int rd) { if (CFG_MEND_SEMAPHORE_LOCK == 0) return; - SP_SEMAPHORE_REG = 0x00000001; - SP_STATUS_REG |= 0x00000001; /* temporary bit to break CPU */ + state->g_sp.regs[SP_SEMAPHORE_REG] = 0x00000001; + state->g_sp.regs[SP_STATUS_REG] |= 0x00000001; /* temporary bit to break CPU */ return; } if (rd == 0x4) /* SP_STATUS_REG */ @@ -104,7 +104,7 @@ static void MFC0(usf_state_t * state, int rt, int rd) #ifdef WAIT_FOR_CPU_HOST ++state->MFC0_count[rt]; if (state->MFC0_count[rt] > 07) - SP_STATUS_REG |= 0x00000001; /* Let OS restart the task. */ + state->g_sp.regs[SP_STATUS_REG] |= 0x00000001; /* Let OS restart the task. */ #endif } return; @@ -112,23 +112,25 @@ static void MFC0(usf_state_t * state, int rt, int rd) static void MT_DMA_CACHE(usf_state_t * state, int rt) { - SP_MEM_ADDR_REG = state->SR[rt] & 0xFFFFFFF8; /* & 0x00001FF8 */ + state->g_sp.regs[SP_MEM_ADDR_REG] = state->SR[rt] & 0xFFFFFFF8; /* & 0x00001FF8 */ return; /* Reserved upper bits are ignored during DMA R/W. */ } static void MT_DMA_DRAM(usf_state_t * state, int rt) { - SP_DRAM_ADDR_REG = state->SR[rt] & 0xFFFFFFF8; /* & 0x00FFFFF8 */ + state->g_sp.regs[SP_DRAM_ADDR_REG] = state->SR[rt] & 0xFFFFFFF8; /* & 0x00FFFFF8 */ return; /* Let the reserved bits get sent, but the pointer is 24-bit. */ } +void SP_DMA_READ(usf_state_t * state); static void MT_DMA_READ_LENGTH(usf_state_t * state, int rt) { - SP_RD_LEN_REG = state->SR[rt] | 07; + state->g_sp.regs[SP_RD_LEN_REG] = state->SR[rt] | 07; SP_DMA_READ(state); return; } +void SP_DMA_WRITE(usf_state_t * state); static void MT_DMA_WRITE_LENGTH(usf_state_t * state, int rt) { - SP_WR_LEN_REG = state->SR[rt] | 07; + state->g_sp.regs[SP_WR_LEN_REG] = state->SR[rt] | 07; SP_DMA_WRITE(state); return; } @@ -136,78 +138,78 @@ static void MT_SP_STATUS(usf_state_t * state, int rt) { if (state->SR[rt] & 0xFE000040) message(state, "MTC0\nSP_STATUS", 2); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1); - MI_INTR_REG &= ~((state->SR[rt] & 0x00000008) >> 3); /* SP_CLR_INTR */ - MI_INTR_REG |= ((state->SR[rt] & 0x00000010) >> 4); /* SP_SET_INTR */ - SP_STATUS_REG |= (state->SR[rt] & 0x00000010) >> 4; /* int set halt */ - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000020) << 5); - /* SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000040) << 5); */ - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000080) << 6); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000100) << 6); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000200) << 7); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000400) << 7); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000800) << 8); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00001000) << 8); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00002000) << 9); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00004000) << 9); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00008000) << 10); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00010000) << 10); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00020000) << 11); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00040000) << 11); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00080000) << 12); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00100000) << 12); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00200000) << 13); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x00400000) << 13); - SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00800000) << 14); - SP_STATUS_REG |= (!!(state->SR[rt] & 0x01000000) << 14); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000001) << 0); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00000002) << 0); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000004) << 1); + state->g_r4300.mi.regs[MI_INTR_REG] &= ~((state->SR[rt] & 0x00000008) >> 3); /* SP_CLR_INTR */ + state->g_r4300.mi.regs[MI_INTR_REG] |= ((state->SR[rt] & 0x00000010) >> 4); /* SP_SET_INTR */ + state->g_sp.regs[SP_STATUS_REG] |= (state->SR[rt] & 0x00000010) >> 4; /* int set halt */ + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000020) << 5); + /* state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00000040) << 5); */ + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000080) << 6); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00000100) << 6); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000200) << 7); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00000400) << 7); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000800) << 8); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00001000) << 8); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00002000) << 9); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00004000) << 9); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00008000) << 10); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00010000) << 10); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00020000) << 11); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00040000) << 11); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00080000) << 12); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00100000) << 12); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00200000) << 13); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x00400000) << 13); + state->g_sp.regs[SP_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00800000) << 14); + state->g_sp.regs[SP_STATUS_REG] |= (!!(state->SR[rt] & 0x01000000) << 14); return; } static void MT_SP_RESERVED(usf_state_t * state, int rt) { const uint32_t source = state->SR[rt] & 0x00000000; /* forced (zilmar, dox) */ - SP_SEMAPHORE_REG = source; + state->g_sp.regs[SP_SEMAPHORE_REG] = source; return; } static void MT_CMD_START(usf_state_t * state, int rt) { const uint32_t source = state->SR[rt] & 0xFFFFFFF8; /* Funnelcube demo */ - if (DPC_BUFBUSY_REG) /* lock hazards not implemented */ + if (state->g_dp.dpc_regs[DPC_BUFBUSY_REG]) /* lock hazards not implemented */ message(state, "MTC0\nCMD_START", 0); - DPC_END_REG = DPC_CURRENT_REG = DPC_START_REG = source; + state->g_dp.dpc_regs[DPC_END_REG] = state->g_dp.dpc_regs[DPC_CURRENT_REG] = state->g_dp.dpc_regs[DPC_START_REG] = source; return; } static void MT_CMD_END(usf_state_t * state, int rt) { - if (DPC_BUFBUSY_REG) + if (state->g_dp.dpc_regs[DPC_BUFBUSY_REG]) message(state, "MTC0\nCMD_END", 0); /* This is just CA-related. */ - DPC_END_REG = state->SR[rt] & 0xFFFFFFF8; + state->g_dp.dpc_regs[DPC_END_REG] = state->SR[rt] & 0xFFFFFFF8; return; } static void MT_CMD_STATUS(usf_state_t * state, int rt) { if (state->SR[rt] & 0xFFFFFD80) /* unsupported or reserved bits */ message(state, "MTC0\nCMD_STATUS", 2); - DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0); - DPC_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0); - DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1); - DPC_STATUS_REG |= (!!(state->SR[rt] & 0x00000008) << 1); - DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000010) << 2); - DPC_STATUS_REG |= (!!(state->SR[rt] & 0x00000020) << 2); + state->g_dp.dpc_regs[DPC_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000001) << 0); + state->g_dp.dpc_regs[DPC_STATUS_REG] |= (!!(state->SR[rt] & 0x00000002) << 0); + state->g_dp.dpc_regs[DPC_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000004) << 1); + state->g_dp.dpc_regs[DPC_STATUS_REG] |= (!!(state->SR[rt] & 0x00000008) << 1); + state->g_dp.dpc_regs[DPC_STATUS_REG] &= ~(!!(state->SR[rt] & 0x00000010) << 2); + state->g_dp.dpc_regs[DPC_STATUS_REG] |= (!!(state->SR[rt] & 0x00000020) << 2); /* Some NUS-CIC-6105 SP tasks try to clear some zeroed DPC registers. */ - DPC_TMEM_REG &= !(state->SR[rt] & 0x00000040) * -1; - /* DPC_PIPEBUSY_REG &= !(state->SR[rt] & 0x00000080) * -1; */ - /* DPC_BUFBUSY_REG &= !(state->SR[rt] & 0x00000100) * -1; */ - DPC_CLOCK_REG &= !(state->SR[rt] & 0x00000200) * -1; + state->g_dp.dpc_regs[DPC_TMEM_REG] &= !(state->SR[rt] & 0x00000040) * -1; + /* state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] &= !(state->SR[rt] & 0x00000080) * -1; */ + /* state->g_dp.dpc_regs[DPC_BUFBUSY_REG] &= !(state->SR[rt] & 0x00000100) * -1; */ + state->g_dp.dpc_regs[DPC_CLOCK_REG] &= !(state->SR[rt] & 0x00000200) * -1; return; } static void MT_CMD_CLOCK(usf_state_t * state, int rt) { message(state, "MTC0\nCMD_CLOCK", 1); /* read-only?? */ - DPC_CLOCK_REG = state->SR[rt]; + state->g_dp.dpc_regs[DPC_CLOCK_REG] = state->SR[rt]; return; /* Appendix says this is RW; elsewhere it says R. */ } static void MT_READ_ONLY(usf_state_t * state, int rt) @@ -227,68 +229,20 @@ MT_SP_STATUS ,MT_READ_ONLY ,MT_READ_ONLY ,MT_SP_RESERVED, MT_CMD_START ,MT_CMD_END ,MT_READ_ONLY ,MT_CMD_STATUS, MT_CMD_CLOCK ,MT_READ_ONLY ,MT_READ_ONLY ,MT_READ_ONLY }; -#if 0 void SP_DMA_READ(usf_state_t * state) { - register unsigned int length; - register unsigned int count; - register unsigned int skip; - - length = (SP_RD_LEN_REG & 0x00000FFF) >> 0; - count = (SP_RD_LEN_REG & 0x000FF000) >> 12; - skip = (SP_RD_LEN_REG & 0xFFF00000) >> 20; - /* length |= 07; // already corrected by mtc0 */ - ++length; - ++count; - skip += length; - do - { /* `count` always starts > 0, so we begin with `do` instead of `while`. */ - unsigned int offC, offD; /* SP cache and dynamic DMA pointers */ - register unsigned int i = 0; - - --count; - do - { - offC = (count*length + SP_MEM_ADDR_REG + i) & 0x00001FF8; - offD = (count*skip + SP_DRAM_ADDR_REG + i) & 0x00FFFFF8; - memcpy(state->DMEM + offC, state->RDRAM + offD, 8); - i += 0x008; - } while (i < length); - } while (count); - SP_DMA_BUSY_REG = 0x00000000; - SP_STATUS_REG &= ~0x00000004; /* SP_STATUS_DMABUSY */ + // Write to RSP, read from RDRAM + dma_sp_write(&state->g_sp); + state->g_sp.regs[SP_DMA_BUSY_REG] = 0x00000000; + state->g_sp.regs[SP_STATUS_REG] &= ~0x00000004; /* SP_STATUS_DMABUSY */ } void SP_DMA_WRITE(usf_state_t * state) { - register unsigned int length; - register unsigned int count; - register unsigned int skip; - - length = (SP_WR_LEN_REG & 0x00000FFF) >> 0; - count = (SP_WR_LEN_REG & 0x000FF000) >> 12; - skip = (SP_WR_LEN_REG & 0xFFF00000) >> 20; - /* length |= 07; // already corrected by mtc0 */ - ++length; - ++count; - skip += length; - do - { /* `count` always starts > 0, so we begin with `do` instead of `while`. */ - unsigned int offC, offD; /* SP cache and dynamic DMA pointers */ - register unsigned int i = 0; - - --count; - do - { - offC = (count*length + SP_MEM_ADDR_REG + i) & 0x00001FF8; - offD = (count*skip + SP_DRAM_ADDR_REG + i) & 0x00FFFFF8; - memcpy(state->RDRAM + offD, state->DMEM + offC, 8); - i += 0x000008; - } while (i < length); - } while (count); - SP_DMA_BUSY_REG = 0x00000000; - SP_STATUS_REG &= ~0x00000004; /* SP_STATUS_DMABUSY */ + // Read from RSP, write to RDRAM + dma_sp_read(&state->g_sp); + state->g_sp.regs[SP_DMA_BUSY_REG] = 0x00000000; + state->g_sp.regs[SP_STATUS_REG] &= ~0x00000004; /* SP_STATUS_DMABUSY */ } -#endif /*** Scalar, Coprocessor Operations (vector unit) ***/ diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/cf.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/cf.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/cf.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/cf.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/clamp.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/clamp.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/clamp.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/clamp.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/divrom.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/divrom.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/divrom.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/divrom.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/shuffle.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/shuffle.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/shuffle.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/shuffle.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vabs.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vabs.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vabs.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vabs.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vadd.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vadd.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vadd.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vadd.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vaddc.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vaddc.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vaddc.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vaddc.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vand.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vand.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vand.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vand.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vch.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vch.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vch.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vch.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vcl.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vcl.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vcl.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vcl.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vcr.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vcr.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vcr.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vcr.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/veq.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/veq.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/veq.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/veq.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vge.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vge.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vge.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vge.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vlt.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vlt.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vlt.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vlt.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmacf.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacf.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmacf.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacf.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmacq.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacq.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmacq.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacq.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmacu.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacu.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmacu.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmacu.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmadh.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadh.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmadh.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadh.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmadl.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadl.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmadl.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadl.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmadm.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadm.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmadm.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadm.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmadn.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadn.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmadn.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmadn.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmov.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmov.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmov.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmov.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmrg.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmrg.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmrg.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmrg.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmudh.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudh.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmudh.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudh.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmudl.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudl.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmudl.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudl.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmudm.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudm.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmudm.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudm.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmudn.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudn.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmudn.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmudn.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmulf.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmulf.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmulf.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmulf.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vmulu.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmulu.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vmulu.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vmulu.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vnand.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnand.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vnand.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnand.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vne.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vne.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vne.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vne.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vnop.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnop.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vnop.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnop.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vnor.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnor.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vnor.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnor.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vnxor.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnxor.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vnxor.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vnxor.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vor.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vor.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vor.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vor.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrcp.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcp.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrcp.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcp.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrcph.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcph.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrcph.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcph.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrcpl.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcpl.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrcpl.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrcpl.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrsq.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsq.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrsq.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsq.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrsqh.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsqh.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrsqh.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsqh.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vrsql.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsql.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vrsql.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vrsql.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vsaw.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsaw.h similarity index 90% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vsaw.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsaw.h index a6f4b28f1..1782d62d3 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/vu/vsaw.h +++ b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsaw.h @@ -14,13 +14,13 @@ #include "vu.h" #ifdef VU_EMULATE_SCALAR_ACCUMULATOR_READ -static void VSAR(usf_state_t * state, int vd, int vs, int vt, int e) +static void VSAR(int vd, int vs, int vt, int e) { ALIGNED short oldval[N]; register int i; for (i = 0; i < N; i++) - oldval[i] = state->VR[vs][i]; + oldval[i] = VR[vs][i]; vt = 0; /* Even though VT is ignored in VSAR, according to official sources as well * as reversing, lots of games seem to specify it as non-zero, possibly to @@ -39,7 +39,7 @@ static void VSAR(usf_state_t * state, int vd, int vs, int vt, int e) vst1q_s16(VR[vd], zero); #else for (i = 0; i < N; i++) - state->VR[vd][i] = 0x0000; /* override behavior (zilmar) */ + VR[vd][i] = 0x0000; /* override behavior (zilmar) */ #endif } else @@ -48,12 +48,12 @@ static void VSAR(usf_state_t * state, int vd, int vs, int vt, int e) vector_copy(VR[vd], VACC[e]); #else for (i = 0; i < N; i++) - state->VR[vd][i] = state->VACC[e][i]; + VR[vd][i] = VACC[e][i]; #endif } for (i = 0; i < N; i++) - state->VACC[e][i] = oldval[i]; /* ... = VS */ + VACC[e][i] = oldval[i]; /* ... = VS */ return; } #endif diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vsub.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsub.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vsub.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsub.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vsubc.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsubc.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vsubc.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vsubc.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vu.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vu.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vu.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vu.h diff --git a/Frameworks/lazyusf/lazyusf/rsp/vu/vxor.h b/Frameworks/lazyusf/lazyusf/rsp_lle/vu/vxor.h similarity index 100% rename from Frameworks/lazyusf/lazyusf/rsp/vu/vxor.h rename to Frameworks/lazyusf/lazyusf/rsp_lle/vu/vxor.h diff --git a/Frameworks/lazyusf/lazyusf/si/cic.c b/Frameworks/lazyusf/lazyusf/si/cic.c new file mode 100644 index 000000000..bd4964e69 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/cic.c @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cic.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "cic.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#include +#include +#include + + +void init_cic_using_ipl3(usf_state_t * state, struct cic* cic, const void* ipl3) +{ + size_t i; + unsigned long long crc = 0; + + static const struct cic cics[] = + { + { CIC_X101, 0x3f }, + { CIC_X102, 0x3f }, + { CIC_X103, 0x78 }, + { CIC_X105, 0x91 }, + { CIC_X106, 0x85 } + }; + + for (i = 0; i < 0xfc0/4; i++) + crc += ((uint32_t*)ipl3)[i]; + + switch(crc) + { + default: + DebugMessage(state, M64MSG_WARNING, "Unknown CIC type (%08x)! using CIC 6102.", crc); + case 0x000000D057C85244LL: i = 1; break; /* CIC_X102 */ + case 0x000000D0027FDF31LL: /* CIC_X101 */ + case 0x000000CFFB631223LL: i = 0; break; /* CIC_X101 */ + case 0x000000D6497E414BLL: i = 2; break; /* CIC_X103 */ + case 0x0000011A49F60E96LL: i = 3; break; /* CIC_X105 */ + case 0x000000D6D5BE5580LL: i = 4; break; /* CIC_X106 */ + } + + memcpy(cic, &cics[i], sizeof(*cic)); +} + diff --git a/Frameworks/lazyusf/lazyusf/si/cic.h b/Frameworks/lazyusf/lazyusf/si/cic.h new file mode 100644 index 000000000..ba34a41b3 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/cic.h @@ -0,0 +1,42 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - cic.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_SI_CIC_H +#define M64P_SI_CIC_H + +enum cic_version +{ + CIC_X101, + CIC_X102, + CIC_X103, + CIC_X105, + CIC_X106 +}; + +struct cic +{ + enum cic_version version; + unsigned int seed; +}; + +void init_cic_using_ipl3(usf_state_t *, struct cic* cic, const void* ipl3); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/si/game_controller.c b/Frameworks/lazyusf/lazyusf/si/game_controller.c new file mode 100644 index 000000000..377ccc00f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/game_controller.c @@ -0,0 +1,143 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - game_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "game_controller.h" +#include "pif.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" + +#ifdef COMPARE_CORE +#include "api/debugger.h" +#endif + +#include + + +static uint8_t pak_data_crc(const uint8_t* data) +{ + size_t i; + uint8_t crc = 0; + + for(i = 0; i <= 0x20; ++i) + { + int mask; + for (mask = 0x80; mask >= 1; mask >>= 1) + { + uint8_t xor_tap = (crc & 0x80) ? 0x85 : 0x00; + crc <<= 1; + if (i != 0x20 && (data[i] & mask)) crc |= 1; + crc ^= xor_tap; + } + } + return crc; +} + + +static void read_controller_read_buttons(struct game_controller* cont, uint8_t* cmd) +{ +} + + +static void controller_status_command(struct game_controller* cont, uint8_t* cmd) +{ + int connected = 0; + + if (cmd[1] & 0x80) + return; + + if (!connected) + { + cmd[1] |= 0x80; + return; + } +} + +static void controller_read_buttons_command(struct game_controller* cont, uint8_t* cmd) +{ + enum pak_type pak; + int connected = 0; + + if (!connected) + cmd[1] |= 0x80; +} + +static void controller_read_pak_command(struct game_controller* cont, uint8_t* cmd) +{ + int connected = 0; + + if (!connected) + { + cmd[1] |= 0x80; + return; + } +} + +static void controller_write_pak_command(struct game_controller* cont, uint8_t* cmd) +{ + int connected = 0; + + if (!connected) + { + cmd[1] |= 0x80; + return; + } +} + + +int game_controller_is_connected(struct game_controller* cont, enum pak_type* pak) +{ + return 0; +} + +uint32_t game_controller_get_input(struct game_controller* cont) +{ + return 0; +} + + +void process_controller_command(struct game_controller* cont, uint8_t* cmd) +{ + switch (cmd[2]) + { + case PIF_CMD_STATUS: + case PIF_CMD_RESET: + controller_status_command(cont, cmd); break; + case PIF_CMD_CONTROLLER_READ: + controller_read_buttons_command(cont, cmd); break; + case PIF_CMD_PAK_READ: + controller_read_pak_command(cont, cmd); break; + case PIF_CMD_PAK_WRITE: + controller_write_pak_command(cont, cmd); break; + break; + } +} + +void read_controller(struct game_controller* cont, uint8_t* cmd) +{ + switch (cmd[2]) + { + case PIF_CMD_CONTROLLER_READ: read_controller_read_buttons(cont, cmd); break; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/si/game_controller.h b/Frameworks/lazyusf/lazyusf/si/game_controller.h new file mode 100644 index 000000000..8118b4798 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/game_controller.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - game_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_SI_GAME_CONTROLLER_H +#define M64P_SI_GAME_CONTROLLER_H + +#include + +enum pak_type +{ + PAK_NONE, + PAK_MEM, + PAK_RUMBLE, + PAK_TRANSFER +}; + +struct game_controller +{ + uint32_t padding; +}; + +int game_controller_is_connected(struct game_controller* cont, enum pak_type* pak); +uint32_t game_controller_get_input(struct game_controller* cont); + +void process_controller_command(struct game_controller* cont, uint8_t* cmd); +void read_controller(struct game_controller* cont, uint8_t* cmd); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.c b/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.c new file mode 100644 index 000000000..0055f27c7 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.c @@ -0,0 +1,120 @@ +/* + * Copyright 2011 X-Scale. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of X-Scale. + * + * This software provides an algorithm that emulates the protection scheme of + * N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge. + * It was synthesized after a careful, exhaustive and detailed analysis of the + * challenge/response pairs stored in the 'pif2.dat' file from Project 64. + * These challenge/response pairs were the only resource used during this + * project. There was no kind of physical access to N64 hardware. + * + * This project would have never been possible without the contribuitions of + * the following individuals and organizations: + * + * - Oman: For being at the right place at the right time and being brave + * enough to pay a personal price so we could understand in a much deeper + * way how this magical console really works. We owe you so much. + * + * - Jovis: For all the positive energy and impressive hacking spirit that you + * shared with the N64 community. You were absolutely instrumental in + * several key events that shaped the N64 community in the last 14 years. + * Even if you're not physically with us anymore, your heritage, your + * knowledge and your attitude will never be forgotten. + * + * 'The candle that burns twice as bright burns half as long.' + * + * - LaC: For the endless contributions that you've given to the N64 community + * since the early days, when N64 was the next big thing. I've always + * admired the deep knowledge that you've gathered about the most little + * hardware details. Recently, you challanged us to find a small and + * concise algorithm that would emulate the behaviour of CIC-NUS-6105 + * challenge/response protection scheme and here is the final result. + * LaC, Oman and Jovis were definitly the dream team of N64 reversing in + * the late 90's. Without your contributions, we would be much poorer. + * + * - marshall: For keeping the N64 scene alive during the last decade, when + * most people lost interest and moved along to different projects. You + * are the force that has been keeping us all together in the later + * years. When almost nobody cared about N64 anymore, you were always + * there, spreading the word, developing in the console, and lately, + * making impressive advances on the hardware side. I wish the best + * success to your new 64drive project. + * + * - hcs: For your contributions to the better understanding of the inner + * workings of the Reality Co-Processor (RCP). Your skills have impressed + * me for a long time now. And without your precious help by sharing your + * kownledge, I would have never understood the immense importance of + * Oman, Jovis and LaC achievements. Thank you ! + * + * - Azimer & Tooie: For sharing with the N64 community your findings about the + * challenge/response pair used in 'Jet Force Gemini' and the 267 + * challenge/response pairs used in 'Banjo Tooie', all stored in the + * 'pif2.dat' file of Project 64. They were instrumental to the final + * success of this endeavour. + * + * - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and + * Reality Co-Processor (RCP). You were the ultimate dream creator during + * the late 80's and early 90's. A very special word of gratitude goes to + * the two teams that during those years created RCP and MIPS R4300. They + * were technological breakthroughs back then. + * + * On a personal note, I would like to show my deepest gratitude to _Bijou_, + * for being always a source of endless hope and inspiration. + * + * -= X-Scale =- (#n64dev@EFnet) + */ + +#include "n64_cic_nus_6105.h" + +void n64_cic_nus_6105(char chl[], char rsp[], int len) +{ + static const char lut0[0x10] = { + 0x4, 0x7, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1, + 0xC, 0xF, 0x8, 0xF, 0x6, 0x3, 0x6, 0x9 + }; + static const char lut1[0x10] = { + 0x4, 0x1, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1, + 0xC, 0x9, 0x8, 0x5, 0x6, 0x3, 0xC, 0x9 + }; + char key; + const char *lut; + int i, sgn, mag, mod; + + for (key = 0xB, lut = lut0, i = 0; i < len; i++) { + rsp[i] = (key + 5 * chl[i]) & 0xF; + key = lut[(int) rsp[i]]; + sgn = (rsp[i] >> 3) & 0x1; + mag = ((sgn == 1) ? ~rsp[i] : rsp[i]) & 0x7; + mod = (mag % 3 == 1) ? sgn : 1 - sgn; + if (lut == lut1 && (rsp[i] == 0x1 || rsp[i] == 0x9)) + mod = 1; + if (lut == lut1 && (rsp[i] == 0xB || rsp[i] == 0xE)) + mod = 0; + lut = (mod == 1) ? lut1 : lut0; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.h b/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.h new file mode 100644 index 000000000..0185d5ecf --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/n64_cic_nus_6105.h @@ -0,0 +1,98 @@ +/* + * Copyright 2011 X-Scale. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of X-Scale. + * + * This software provides an algorithm that emulates the protection scheme of + * N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge. + * It was synthesized after a careful, exhaustive and detailed analysis of the + * challenge/response pairs stored in the 'pif2.dat' file from Project 64. + * These challenge/response pairs were the only resource used during this + * project. There was no kind of physical access to N64 hardware. + * + * This project would have never been possible without the contribuitions of + * the following individuals and organizations: + * + * - Oman: For being at the right place at the right time and being brave + * enough to pay a personal price so we could understand in a much deeper + * way how this magical console really works. We owe you so much. + * + * - Jovis: For all the positive energy and impressive hacking spirit that you + * shared with the N64 community. You were absolutely instrumental in + * several key events that shaped the N64 community in the last 14 years. + * Even if you're not physically with us anymore, your heritage, your + * knowledge and your attitude will never be forgotten. + * + * 'The candle that burns twice as bright burns half as long.' + * + * - LaC: For the endless contributions that you've given to the N64 community + * since the early days, when N64 was the next big thing. I've always + * admired the deep knowledge that you've gathered about the most little + * hardware details. Recently, you challanged us to find a small and + * concise algorithm that would emulate the behaviour of CIC-NUS-6105 + * challenge/response protection scheme and here is the final result. + * LaC, Oman and Jovis were definitly the dream team of N64 reversing in + * the late 90's. Without your contributions, we would be much poorer. + * + * - marshall: For keeping the N64 scene alive during the last decade, when + * most people lost interest and moved along to different projects. You + * are the force that has been keeping us all together in the later + * years. When almost nobody cared about N64 anymore, you were always + * there, spreading the word, developing in the console, and lately, + * making impressive advances on the hardware side. I wish the best + * success to your new 64drive project. + * + * - hcs: For your contributions to the better understanding of the inner + * workings of the Reality Co-Processor (RCP). Your skills have impressed + * me for a long time now. And without your precious help by sharing your + * kownledge, I would have never understood the immense importance of + * Oman, Jovis and LaC achievements. Thank you ! + * + * - Azimer & Tooie: For sharing with the N64 community your findings about the + * challenge/response pair used in 'Jet Force Gemini' and the 267 + * challenge/response pairs used in 'Banjo Tooie', all stored in the + * 'pif2.dat' file of Project 64. They were instrumental to the final + * success of this endeavour. + * + * - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and + * Reality Co-Processor (RCP). You were the ultimate dream creator during + * the late 80's and early 90's. A very special word of gratitude goes to + * the two teams that during those years created RCP and MIPS R4300. They + * were technological breakthroughs back then. + * + * On a personal note, I would like to show my deepest gratitude to _Bijou_, + * for being always a source of endless hope and inspiration. + * + * -= X-Scale =- (#n64dev@EFnet) + */ + +#ifndef N64_CIC_NUS_6105_H +#define N64_CIC_NUS_6105_H + +#define CHL_LEN 0x20 + +void n64_cic_nus_6105(char chl[], char rsp[], int len); + +#endif /* N64_CIC_NUS_6105_H */ diff --git a/Frameworks/lazyusf/lazyusf/si/pif.c b/Frameworks/lazyusf/lazyusf/si/pif.c new file mode 100644 index 000000000..fa000fccc --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/pif.c @@ -0,0 +1,238 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pif.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "pif.h" +#include "n64_cic_nus_6105.h" +#include "si_controller.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "memory/memory.h" +#include "r4300/r4300_core.h" +#include "r4300/cp0.h" +#include "r4300/interupt.h" + +#include + +//#define DEBUG_PIF +#ifdef DEBUG_PIF +void print_pif(usf_state_t * state, struct pif* pif) +{ + int i; + for (i=0; i<(64/8); i++) + DebugMessage(state, M64MSG_INFO, "%x %x %x %x | %x %x %x %x", + pif->ram[i*8+0], pif->ram[i*8+1],pif->ram[i*8+2], pif->ram[i*8+3], + pif->ram[i*8+4], pif->ram[i*8+5],pif->ram[i*8+6], pif->ram[i*8+7]); +} +#endif + +static void process_cart_command(usf_state_t * state, struct pif* pif, uint8_t* cmd) +{ + switch (cmd[2]) + { + case PIF_CMD_STATUS: break; + case PIF_CMD_EEPROM_READ: break; + case PIF_CMD_EEPROM_WRITE: break; + case PIF_CMD_AF_RTC_STATUS: break; + case PIF_CMD_AF_RTC_READ: break; + case PIF_CMD_AF_RTC_WRITE: break; + default: + DebugMessage(state, M64MSG_ERROR, "unknown PIF command: %02x", cmd[2]); + } +} + +void init_pif(struct pif* pif) +{ + memset(pif->ram, 0, PIF_RAM_SIZE); +} + +int read_pif_ram(void* opaque, uint32_t address, uint32_t* value) +{ + struct si_controller* si = (struct si_controller*)opaque; + uint32_t addr = pif_ram_address(address); + + if (addr >= PIF_RAM_SIZE) + { + DebugMessage(si->r4300->state, M64MSG_ERROR, "Invalid PIF address: %08x", address); + *value = 0; + return -1; + } + + memcpy(value, si->pif.ram + addr, sizeof(*value)); + *value = sl(*value); + + return 0; +} + +int write_pif_ram(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct si_controller* si = (struct si_controller*)opaque; + uint32_t addr = pif_ram_address(address); + + if (addr >= PIF_RAM_SIZE) + { + DebugMessage(si->r4300->state, M64MSG_ERROR, "Invalid PIF address: %08x", address); + return -1; + } + + masked_write((uint32_t*)(&si->pif.ram[addr]), sl(value), sl(mask)); + + if ((addr == 0x3c) && (mask & 0xff)) + { + if (si->pif.ram[0x3f] == 0x08) + { + si->pif.ram[0x3f] = 0; + update_count(si->r4300->state); + if (si->r4300->state->g_delay_si) + add_interupt_event(si->r4300->state, SI_INT, /*0x100*/0x900); + else + signal_rcp_interrupt(si->r4300, SI_INT); + } + else + { + update_pif_write(si); + } + } + + return 0; +} + + +void update_pif_write(struct si_controller* si) +{ + struct pif* pif = &si->pif; + + char challenge[30], response[30]; + int i=0, channel=0; + if (pif->ram[0x3F] > 1) + { + switch (pif->ram[0x3F]) + { + case 0x02: +#ifdef DEBUG_PIF + DebugMessage(si->r4300->state, M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 2 - CIC challenge"); +#endif + // format the 'challenge' message into 30 nibbles for X-Scale's CIC code + for (i = 0; i < 15; i++) + { + challenge[i*2] = (pif->ram[48+i] >> 4) & 0x0f; + challenge[i*2+1] = pif->ram[48+i] & 0x0f; + } + // calculate the proper response for the given challenge (X-Scale's algorithm) + n64_cic_nus_6105(challenge, response, CHL_LEN - 2); + pif->ram[46] = 0; + pif->ram[47] = 0; + // re-format the 'response' into a byte stream + for (i = 0; i < 15; i++) + { + pif->ram[48+i] = (response[i*2] << 4) + response[i*2+1]; + } + // the last byte (2 nibbles) is always 0 + pif->ram[63] = 0; + break; + case 0x08: +#ifdef DEBUG_PIF + DebugMessage(si->r4300->state, M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 8"); +#endif + pif->ram[0x3F] = 0; + break; + default: + DebugMessage(si->r4300->state, M64MSG_ERROR, "error in update_pif_write(): %x", pif->ram[0x3F]); + } + return; + } + while (i<0x40) + { + switch (pif->ram[i]) + { + case 0x00: + channel++; + if (channel > 6) i=0x40; + break; + case 0xFF: + break; + default: + if (!(pif->ram[i] & 0xC0)) + { + if (channel < 4) + { + process_controller_command(&pif->controllers[channel], &pif->ram[i]); + } + else if (channel == 4) + process_cart_command(si->r4300->state, pif, &pif->ram[i]); + else + DebugMessage(si->r4300->state, M64MSG_ERROR, "channel >= 4 in update_pif_write"); + i += pif->ram[i] + (pif->ram[(i+1)] & 0x3F) + 1; + channel++; + } + else + i=0x40; + } + i++; + } + + //pif->ram[0x3F] = 0; +} + +void update_pif_read(struct si_controller* si) +{ + struct pif* pif = &si->pif; + + int i=0, channel=0; + while (i<0x40) + { + switch (pif->ram[i]) + { + case 0x00: + channel++; + if (channel > 6) i=0x40; + break; + case 0xFE: + i = 0x40; + break; + case 0xFF: + break; + case 0xB4: + case 0x56: + case 0xB8: + break; + default: + if (!(pif->ram[i] & 0xC0)) + { + if (channel < 4) + { + read_controller(&pif->controllers[channel], &pif->ram[i]); + } + + i += pif->ram[i] + (pif->ram[(i+1)] & 0x3F) + 1; + channel++; + } + else + i=0x40; + } + i++; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/si/pif.h b/Frameworks/lazyusf/lazyusf/si/pif.h new file mode 100644 index 000000000..f73002f35 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/pif.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - pif.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_SI_PIF_H +#define M64P_SI_PIF_H + +#include + +#include "cic.h" +#include "game_controller.h" + +enum { GAME_CONTROLLERS_COUNT = 4 }; + +struct si_controller; + +enum { PIF_RAM_SIZE = 0x40 }; + +enum pif_commands +{ + PIF_CMD_STATUS = 0x00, + PIF_CMD_CONTROLLER_READ = 0x01, + PIF_CMD_PAK_READ = 0x02, + PIF_CMD_PAK_WRITE = 0x03, + PIF_CMD_EEPROM_READ = 0x04, + PIF_CMD_EEPROM_WRITE = 0x05, + PIF_CMD_AF_RTC_STATUS = 0x06, + PIF_CMD_AF_RTC_READ = 0x07, + PIF_CMD_AF_RTC_WRITE = 0x08, + PIF_CMD_RESET = 0xff, +}; + +struct pif +{ + uint8_t ram[PIF_RAM_SIZE]; + + struct game_controller controllers[GAME_CONTROLLERS_COUNT]; + + struct cic cic; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t pif_ram_address(uint32_t address) +{ + return ((address & 0xfffc) - 0x7c0); +} + + +void init_pif(struct pif* pif); + +int read_pif_ram(void* opaque, uint32_t address, uint32_t* value); +int write_pif_ram(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void update_pif_write(struct si_controller* si); +void update_pif_read(struct si_controller* si); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/si/si_controller.c b/Frameworks/lazyusf/lazyusf/si/si_controller.c new file mode 100644 index 000000000..2b653c7df --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/si_controller.c @@ -0,0 +1,159 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - si_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "si_controller.h" + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "main/main.h" +#include "memory/memory.h" +#include "r4300/cp0.h" +#include "r4300/interupt.h" +#include "r4300/r4300.h" +#include "r4300/r4300_core.h" +#include "ri/ri_controller.h" + +#include + + +static void dma_si_write(struct si_controller* si) +{ + int i; + + if (si->regs[SI_PIF_ADDR_WR64B_REG] != 0x1FC007C0) + { + DebugMessage(si->r4300->state, M64MSG_ERROR, "dma_si_write(): unknown SI use"); + si->r4300->state->stop=1; + } + + for (i = 0; i < PIF_RAM_SIZE; i += 4) + { + *((uint32_t*)(&si->pif.ram[i])) = sl(si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4]); + } + + update_pif_write(si); + update_count(si->r4300->state); + + if (si->r4300->state->g_delay_si) { + add_interupt_event(si->r4300->state, SI_INT, /*0x100*/0x900); + } else { + si->regs[SI_STATUS_REG] |= 0x1000; // INTERRUPT + signal_rcp_interrupt(si->r4300, MI_INTR_SI); + } +} + +static void dma_si_read(struct si_controller* si) +{ + int i; + + if (si->regs[SI_PIF_ADDR_RD64B_REG] != 0x1FC007C0) + { + DebugMessage(si->r4300->state, M64MSG_ERROR, "dma_si_read(): unknown SI use"); + si->r4300->state->stop=1; + } + + update_pif_read(si); + + for (i = 0; i < PIF_RAM_SIZE; i += 4) + { + si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4] = sl(*(uint32_t*)(&si->pif.ram[i])); + } + + update_count(si->r4300->state); + + if (si->r4300->state->g_delay_si) { + add_interupt_event(si->r4300->state, SI_INT, /*0x100*/0x900); + } else { + si->regs[SI_STATUS_REG] |= 0x1000; // INTERRUPT + signal_rcp_interrupt(si->r4300, MI_INTR_SI); + } +} + + +void connect_si(struct si_controller* si, + struct r4300_core* r4300, + struct ri_controller* ri) +{ + si->r4300 = r4300; + si->ri = ri; +} + +void init_si(struct si_controller* si) +{ + memset(si->regs, 0, SI_REGS_COUNT*sizeof(uint32_t)); + + init_pif(&si->pif); +} + + +int read_si_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct si_controller* si = (struct si_controller*)opaque; + uint32_t reg = si_reg(address); + + *value = si->regs[reg]; + + return 0; +} + +int write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct si_controller* si = (struct si_controller*)opaque; + uint32_t reg = si_reg(address); + + switch (reg) + { + case SI_DRAM_ADDR_REG: + masked_write(&si->regs[SI_DRAM_ADDR_REG], value, mask); + break; + + case SI_PIF_ADDR_RD64B_REG: + masked_write(&si->regs[SI_PIF_ADDR_RD64B_REG], value, mask); + dma_si_read(si); + break; + + case SI_PIF_ADDR_WR64B_REG: + masked_write(&si->regs[SI_PIF_ADDR_WR64B_REG], value, mask); + dma_si_write(si); + break; + + case SI_STATUS_REG: + si->regs[SI_STATUS_REG] &= ~0x1000; + clear_rcp_interrupt(si->r4300, MI_INTR_SI); + break; + } + + return 0; +} + +void si_end_of_dma_event(struct si_controller* si) +{ + si->pif.ram[0x3f] = 0x0; + + /* trigger SI interrupt */ + si->regs[SI_STATUS_REG] |= 0x1000; + raise_rcp_interrupt(si->r4300, MI_INTR_SI); +} + diff --git a/Frameworks/lazyusf/lazyusf/si/si_controller.h b/Frameworks/lazyusf/lazyusf/si/si_controller.h new file mode 100644 index 000000000..6879bdbce --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/si/si_controller.h @@ -0,0 +1,73 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - si_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SI_SI_CONTROLLER_H +#define SI_SI_CONTROLLER_H + +#include + +#include "pif.h" + +struct r4300_core; +struct ri_controller; + +enum si_registers +{ + SI_DRAM_ADDR_REG, + SI_PIF_ADDR_RD64B_REG, + SI_R2_REG, /* reserved */ + SI_R3_REG, /* reserved */ + SI_PIF_ADDR_WR64B_REG, + SI_R5_REG, /* reserved */ + SI_STATUS_REG, + SI_REGS_COUNT +}; + +struct si_controller +{ + uint32_t regs[SI_REGS_COUNT]; + + struct pif pif; + + struct r4300_core* r4300; + struct ri_controller* ri; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t si_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + + +void connect_si(struct si_controller* si, + struct r4300_core* r4300, + struct ri_controller* ri); + +void init_si(struct si_controller* si); + +int read_si_regs(void* opaque, uint32_t address, uint32_t* value); +int write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void si_end_of_dma_event(struct si_controller* si); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/tlb.c b/Frameworks/lazyusf/lazyusf/tlb.c deleted file mode 100644 index e1b3d166c..000000000 --- a/Frameworks/lazyusf/lazyusf/tlb.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ - -#include - -#include "main.h" -#include "cpu.h" - -#include "usf_internal.h" - -void SetupTLB_Entry (usf_state_t * state, int32_t Entry); - -uint32_t AddressDefined ( usf_state_t * state, uintptr_t VAddr) { - uint32_t i; - - if (VAddr >= 0x80000000 && VAddr <= 0xBFFFFFFF) { - return 1; - } - - for (i = 0; i < 64; i++) { - if (state->FastTlb[i].ValidEntry == 0) { continue; } - if (VAddr >= state->FastTlb[i].VSTART && VAddr <= state->FastTlb[i].VEND) { - return 1; - } - } - return 0; -} - -void InitilizeTLB (usf_state_t * state) { - uint32_t count; - - for (count = 0; count < 32; count++) { state->tlb[count].EntryDefined = 0; } - for (count = 0; count < 64; count++) { state->FastTlb[count].ValidEntry = 0; } - SetupTLB(state); -} - -void SetupTLB (usf_state_t * state) { - uint32_t count; - - memset(state->TLB_Map,0,(0xFFFFF * sizeof(uintptr_t))); - for (count = 0x80000000; count < 0xC0000000; count += 0x1000) { - state->TLB_Map[count >> 12] = ((uintptr_t)state->N64MEM + (count & 0x1FFFFFFF)) - count; - } - for (count = 0; count < 32; count ++) { SetupTLB_Entry(state, count); } -} -/* -test=(BYTE *) VirtualAlloc( 0x10, 0x70000, MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if(test == 0) { - //printf("FAIL!\n"); - exit(0); - } -*/ - -void SetupTLB_Entry (usf_state_t * state, int Entry) { - int32_t FastIndx; - - - if (!state->tlb[Entry].EntryDefined) { return; } - FastIndx = Entry << 1; - state->FastTlb[FastIndx].VSTART=state->tlb[Entry].EntryHi.b.VPN2 << 13; - state->FastTlb[FastIndx].VEND = state->FastTlb[FastIndx].VSTART + (state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF; - state->FastTlb[FastIndx].PHYSSTART = state->tlb[Entry].EntryLo0.b.PFN << 12; - state->FastTlb[FastIndx].VALID = state->tlb[Entry].EntryLo0.b.V; - state->FastTlb[FastIndx].DIRTY = state->tlb[Entry].EntryLo0.b.D; - state->FastTlb[FastIndx].GLOBAL = state->tlb[Entry].EntryLo0.b.GLOBAL & state->tlb[Entry].EntryLo1.b.GLOBAL; - state->FastTlb[FastIndx].ValidEntry = 0; - - FastIndx = (Entry << 1) + 1; - state->FastTlb[FastIndx].VSTART=(state->tlb[Entry].EntryHi.b.VPN2 << 13) + ((state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF + 1); - state->FastTlb[FastIndx].VEND = state->FastTlb[FastIndx].VSTART + (state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF; - state->FastTlb[FastIndx].PHYSSTART = state->tlb[Entry].EntryLo1.b.PFN << 12; - state->FastTlb[FastIndx].VALID = state->tlb[Entry].EntryLo1.b.V; - state->FastTlb[FastIndx].DIRTY = state->tlb[Entry].EntryLo1.b.D; - state->FastTlb[FastIndx].GLOBAL = state->tlb[Entry].EntryLo0.b.GLOBAL & state->tlb[Entry].EntryLo1.b.GLOBAL; - state->FastTlb[FastIndx].ValidEntry = 0; - - for ( FastIndx = Entry << 1; FastIndx <= (Entry << 1) + 1; FastIndx++) { - uint32_t count; - - if (!state->FastTlb[FastIndx].VALID) { - state->FastTlb[FastIndx].ValidEntry = 1; - continue; - } - if (state->FastTlb[FastIndx].VEND <= state->FastTlb[FastIndx].VSTART) { - continue; - } - if (state->FastTlb[FastIndx].VSTART >= 0x80000000 && state->FastTlb[FastIndx].VEND <= 0xBFFFFFFF) { - continue; - } - if (state->FastTlb[FastIndx].PHYSSTART > 0x1FFFFFFF) { - continue; - } - - //test if overlap - state->FastTlb[FastIndx].ValidEntry = 1; - for (count = state->FastTlb[FastIndx].VSTART; count < state->FastTlb[FastIndx].VEND; count += 0x1000) { - state->TLB_Map[count >> 12] = ((uintptr_t)state->N64MEM + (count - state->FastTlb[FastIndx].VSTART + state->FastTlb[FastIndx].PHYSSTART)) - count; - } - } -} - -void TLB_Probe (usf_state_t * state) { - uint32_t Counter; - - - INDEX_REGISTER |= 0x80000000; - for (Counter = 0; Counter < 32; Counter ++) { - uint32_t TlbValue = state->tlb[Counter].EntryHi.Value & (~state->tlb[Counter].PageMask.b.Mask << 13); - uint32_t EntryHi = ENTRYHI_REGISTER & (~state->tlb[Counter].PageMask.b.Mask << 13); - - if (TlbValue == EntryHi) { - uint32_t Global = (state->tlb[Counter].EntryHi.Value & 0x100) != 0; - uint32_t SameAsid = ((state->tlb[Counter].EntryHi.Value & 0xFF) == (ENTRYHI_REGISTER & 0xFF)); - - if (Global || SameAsid) { - INDEX_REGISTER = Counter; - return; - } - } - } -} - -void TLB_Read (usf_state_t * state) { - uint32_t index = INDEX_REGISTER & 0x1F; - - PAGE_MASK_REGISTER = state->tlb[index].PageMask.Value ; - ENTRYHI_REGISTER = (state->tlb[index].EntryHi.Value & ~state->tlb[index].PageMask.Value) ; - ENTRYLO0_REGISTER = state->tlb[index].EntryLo0.Value; - ENTRYLO1_REGISTER = state->tlb[index].EntryLo1.Value; -} - -uint32_t TranslateVaddr ( usf_state_t * state, uintptr_t * Addr) { - if (state->TLB_Map[((*Addr) & 0xffffffff) >> 12] == 0) { return 0; } - *Addr = (uintptr_t)((uint8_t *)(state->TLB_Map[((*Addr) & 0xffffffff) >> 12] + ((*Addr) & 0xffffffff)) - (uintptr_t)state->N64MEM); - return 1; -} - -void WriteTLBEntry (usf_state_t * state, int32_t index) { - int32_t FastIndx; - - FastIndx = index << 1; - if ((state->PROGRAM_COUNTER >= state->FastTlb[FastIndx].VSTART && - state->PROGRAM_COUNTER < state->FastTlb[FastIndx].VEND && - state->FastTlb[FastIndx].ValidEntry && state->FastTlb[FastIndx].VALID) - || - (state->PROGRAM_COUNTER >= state->FastTlb[FastIndx + 1].VSTART && - state->PROGRAM_COUNTER < state->FastTlb[FastIndx + 1].VEND && - state->FastTlb[FastIndx + 1].ValidEntry && state->FastTlb[FastIndx + 1].VALID)) - { - return; - } - - if (state->tlb[index].EntryDefined) { - uint32_t count; - - for ( FastIndx = index << 1; FastIndx <= (index << 1) + 1; FastIndx++) { - if (!state->FastTlb[FastIndx].ValidEntry) { continue; } - if (!state->FastTlb[FastIndx].VALID) { continue; } - for (count = state->FastTlb[FastIndx].VSTART; count < state->FastTlb[FastIndx].VEND; count += 0x1000) { - state->TLB_Map[count >> 12] = 0; - } - } - } - state->tlb[index].PageMask.Value = PAGE_MASK_REGISTER; - state->tlb[index].EntryHi.Value = ENTRYHI_REGISTER; - state->tlb[index].EntryLo0.Value = ENTRYLO0_REGISTER; - state->tlb[index].EntryLo1.Value = ENTRYLO1_REGISTER; - state->tlb[index].EntryDefined = 1; - - - SetupTLB_Entry(state, index); -} diff --git a/Frameworks/lazyusf/lazyusf/tlb.h b/Frameworks/lazyusf/lazyusf/tlb.h deleted file mode 100644 index 3807cf0c8..000000000 --- a/Frameworks/lazyusf/lazyusf/tlb.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#ifndef _TLB_H_ -#define _TLB_H_ - -typedef struct { - uint32_t EntryDefined; - union { - uint32_t Value; - uint8_t A[4]; - - struct { - unsigned zero : 13; - unsigned Mask : 12; - unsigned zero2 : 7; - } b; - - } PageMask; - - union { - uint32_t Value; - uint8_t A[4]; - - struct { - unsigned ASID : 8; - unsigned Zero : 4; - unsigned G : 1; - unsigned VPN2 : 19; - } b; - - } EntryHi; - - union { - uint32_t Value; - uint8_t A[4]; - - struct { - unsigned GLOBAL: 1; - unsigned V : 1; - unsigned D : 1; - unsigned C : 3; - unsigned PFN : 20; - unsigned ZERO: 6; - } b; - - } EntryLo0; - - union { - uint32_t Value; - uint8_t A[4]; - - struct { - unsigned GLOBAL: 1; - unsigned V : 1; - unsigned D : 1; - unsigned C : 3; - unsigned PFN : 20; - unsigned ZERO: 6; - } b; - - } EntryLo1; -} TLB; - -typedef struct { - uint32_t VSTART; - uint32_t VEND; - uint32_t PHYSSTART; - uint32_t VALID; - uint32_t DIRTY; - uint32_t GLOBAL; - uint32_t ValidEntry; -} FASTTLB; - -uint32_t AddressDefined ( usf_state_t *, uintptr_t VAddr); -void InitilizeTLB ( usf_state_t * ); -void SetupTLB ( usf_state_t * ); -void TLB_Probe ( usf_state_t * ); -void TLB_Read ( usf_state_t * ); -uint32_t TranslateVaddr ( usf_state_t *, uintptr_t * Addr); -void WriteTLBEntry ( usf_state_t *, int32_t index ); - -#endif diff --git a/Frameworks/lazyusf/lazyusf/types.h b/Frameworks/lazyusf/lazyusf/types.h deleted file mode 100644 index 30eb952cf..000000000 --- a/Frameworks/lazyusf/lazyusf/types.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Project 64 - A Nintendo 64 emulator. - * - * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and - * Jabo (jabo@emulation64.com). - * - * pj64 homepage: www.pj64.net - * - * Permission to use, copy, modify and distribute Project64 in both binary and - * source form, for non-commercial purposes, is hereby granted without fee, - * providing that this license information and copyright notice appear with - * all copies and any derived work. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event shall the authors be held liable for any damages - * arising from the use of this software. - * - * Project64 is freeware for PERSONAL USE only. Commercial users should - * seek permission of the copyright holders first. Commercial use includes - * charging money for Project64 or software derived from Project64. - * - * The copyright holders request that bug fixes and improvements to the code - * should be forwarded to them so if they want them. - * - */ -#ifndef __Types_h -#define __Types_h - -#include -typedef uint64_t QWORD; - -typedef union tagVect { - double FD[2]; - int64_t DW[2]; - uint64_t UDW[2]; - int32_t W[4]; - float FS[4]; - uint32_t UW[4]; - int16_t HW[8]; - uint16_t UHW[8]; - int8_t B[16]; - uint8_t UB[16]; -} VECTOR; - -typedef union tagUWORD { - int32_t W; - uint32_t UW; - int16_t HW[2]; - uint16_t UHW[2]; - int8_t B[4]; - uint8_t UB[4]; - float F; -} MIPS_WORD; - -typedef union tagUDWORD { - double D; - int64_t DW; - uint64_t UDW; - int32_t W[2]; - uint32_t UW[2]; - int16_t HW[4]; - uint16_t UHW[4]; - int8_t B[8]; - uint8_t UB[8]; - float F[2]; -} MIPS_DWORD; - -typedef MIPS_WORD MIPSUWORD; -typedef MIPS_DWORD MIPSUDWORD; - - -#endif diff --git a/Frameworks/lazyusf/lazyusf/usf.c b/Frameworks/lazyusf/lazyusf/usf.c deleted file mode 100644 index 547eabb1b..000000000 --- a/Frameworks/lazyusf/lazyusf/usf.c +++ /dev/null @@ -1,254 +0,0 @@ - -#include -#include - -#include "usf.h" -#include "cpu.h" -#include "memory.h" -#include "audio.h" - -#include -#include - -#include "types.h" - -#include "usf_internal.h" - -size_t usf_get_state_size() -{ - return sizeof(usf_state_t) + 8192; -} - -void usf_clear(void * state) -{ - size_t offset; - memset(state, 0, usf_get_state_size()); - offset = 4096 - (((uintptr_t)state) & 4095); - USF_STATE_HELPER->offset_to_structure = offset; - - //USF_STATE->savestatespace = NULL; - //USF_STATE->cpu_running = 0; - USF_STATE->cpu_stopped = 1; - - //USF_STATE->enablecompare = 0; - //USF_STATE->enableFIFOfull = 0; - - //USF_STATE->enable_hle_audio = 0; - - //USF_STATE->NextInstruction = 0; - //USF_STATE->JumpToLocation = 0; - //USF_STATE->AudioIntrReg = 0; - //USF_STATE->CPU_Action = 0; - //USF_STATE->Timers = 0; - //USF_STATE->CPURunning = 0; - //USF_STATE->SPHack = 0; - //USF_STATE->WaitMode = 0; - - //USF_STATE->TLB_Map = 0; - //USF_STATE->MemChunk = 0; - USF_STATE->RdramSize = 0x800000; - USF_STATE->SystemRdramSize = 0x800000; - USF_STATE->RomFileSize = 0x4000000; - - //USF_STATE->N64MEM = 0; - //USF_STATE->RDRAM = 0; - //USF_STATE->DMEM = 0; - //USF_STATE->IMEM = 0; - - //memset(USF_STATE->ROMPages, 0, sizeof(USF_STATE->ROMPages)); - //USF_STATE->savestatespace = 0; - //USF_STATE->NOMEM = 0; - - //USF_STATE->WrittenToRom = 0; - //USF_STATE->WroteToRom = 0; - //USF_STATE->TempValue = 0; - //USF_STATE->MemoryState = 0; - //USF_STATE->EmptySpace = 0; - - //USF_STATE->Registers = 0; - - //USF_STATE->PIF_Ram = 0; - - PreAllocate_Memory(USF_STATE); - -#ifdef DEBUG_INFO - USF_STATE->debug_log = fopen("/tmp/lazyusf.log", "w"); -#endif -} - -void usf_set_compare(void * state, int enable) -{ - USF_STATE->enablecompare = enable; -} - -void usf_set_fifo_full(void * state, int enable) -{ - USF_STATE->enableFIFOfull = enable; -} - -void usf_set_hle_audio(void * state, int enable) -{ - USF_STATE->enable_hle_audio = enable; -} - -static uint32_t get_le32( const void * _p ) -{ - const uint8_t * p = (const uint8_t *) _p; - return p[0] + p[1] * 0x100 + p[2] * 0x10000 + p[3] * 0x1000000; -} - -int usf_upload_section(void * state, const uint8_t * data, size_t size) -{ - uint32_t temp; - - if ( size < 4 ) return -1; - temp = get_le32( data ); data += 4; size -= 4; - - if(temp == 0x34365253) { //there is a rom section - uint32_t len, start; - - if ( size < 4 ) return -1; - len = get_le32( data ); data += 4; size -= 4; - - while(len) { - if ( size < 4 ) return -1; - start = get_le32( data ); data += 4; size -= 4; - - while(len) { - uint32_t page = start >> 16; - uint32_t readLen = ( ((start + len) >> 16) > page) ? (((page + 1) << 16) - start) : len; - - if( USF_STATE->ROMPages[page] == 0 ) { - USF_STATE->ROMPages[page] = malloc(0x10000); - if ( USF_STATE->ROMPages[page] == 0 ) - return -1; - - memset(USF_STATE->ROMPages[page], 0, 0x10000); - } - - if ( size < readLen ) - return -1; - - memcpy( USF_STATE->ROMPages[page] + (start & 0xffff), data, readLen ); - data += readLen; size -= readLen; - - start += readLen; - len -= readLen; - } - - if ( size < 4 ) return -1; - len = get_le32( data ); data += 4; size -= 4; - } - } - - if ( size < 4 ) return -1; - temp = get_le32( data ); data += 4; size -= 4; - - if(temp == 0x34365253) { - uint32_t len, start; - - if ( size < 4 ) return -1; - len = get_le32( data ); data += 4; size -= 4; - - while(len) { - if ( size < 4 ) return -1; - start = get_le32( data ); data += 4; size -= 4; - - if ( size < len ) return -1; - memcpy( USF_STATE->savestatespace + start, data, len ); - data += len; size -= len; - - if ( size < 4 ) return -1; - len = get_le32( data ); data += 4; size -= 4; - } - } - - return 0; -} - -static int usf_startup(usf_state_t * state) -{ - // Detect the Ramsize before the memory allocation - - if(get_le32(state->savestatespace + 4) == 0x400000) { - void * savestate; - state->RdramSize = 0x400000; - savestate = realloc(state->savestatespace, 0x40275c); - if ( savestate ) - state->savestatespace = savestate; - } else if(get_le32(USF_STATE->savestatespace + 4) == 0x800000) - state->RdramSize = 0x800000; - - if ( !Allocate_Memory(state) ) - return -1; - - StartEmulationFromSave(state, USF_STATE->savestatespace); - - return 0; -} - -const char * usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate) -{ - USF_STATE->last_error = 0; - USF_STATE->error_message[0] = '\0'; - - if ( !USF_STATE->MemoryState ) - { - if ( usf_startup( USF_STATE ) < 0 ) - return USF_STATE->last_error; - } - - if ( USF_STATE->samples_in_buffer ) - { - size_t do_max = USF_STATE->samples_in_buffer; - if ( do_max > count ) - do_max = count; - - if ( buffer ) - memcpy( buffer, USF_STATE->samplebuf, sizeof(int16_t) * 2 * do_max ); - - USF_STATE->samples_in_buffer -= do_max; - - if ( sample_rate ) - *sample_rate = USF_STATE->SampleRate; - - if ( USF_STATE->samples_in_buffer ) - { - memmove( USF_STATE->samplebuf, USF_STATE->samplebuf + do_max * 2, sizeof(int16_t) * 2 * USF_STATE->samples_in_buffer ); - return 0; - } - - if ( buffer ) - buffer += 2 * do_max; - count -= do_max; - } - - USF_STATE->sample_buffer = buffer; - USF_STATE->sample_buffer_count = count; - - USF_STATE->cpu_stopped = 0; - USF_STATE->cpu_running = 1; - - StartInterpreterCPU(USF_STATE); - - if ( sample_rate ) - *sample_rate = USF_STATE->SampleRate; - - return USF_STATE->last_error; -} - -void usf_restart(void * state) -{ - if ( USF_STATE->MemoryState ) - StartEmulationFromSave(USF_STATE, USF_STATE->savestatespace); - - USF_STATE->samples_in_buffer = 0; -} - -void usf_shutdown(void * state) -{ - Release_Memory(USF_STATE); -#ifdef DEBUG_INFO - fclose(USF_STATE->debug_log); -#endif -} diff --git a/Frameworks/lazyusf/lazyusf/usf/barray.c b/Frameworks/lazyusf/lazyusf/usf/barray.c new file mode 100644 index 000000000..b2aa082e3 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/barray.c @@ -0,0 +1,189 @@ +#include "barray.h" + +#include + + +void * bit_array_create(size_t size) +{ + size_t bsize = ((size + 7) >> 3) + sizeof(size_t); + void * ret = calloc(1, bsize); + if (ret) *(size_t *)ret = size; + return ret; +} + +void bit_array_destroy(void * array) +{ + if (array) free(array); +} + +void * bit_array_dup(void * array) +{ + if (array) + { + size_t * size = (size_t *) array; + size_t bsize = ((*size + 7) >> 3) + sizeof(*size); + void * ret = malloc(bsize); + if (ret) memcpy(ret, array, bsize); + return ret; + } + return NULL; +} + +void bit_array_reset(void * array) +{ + if (array) + { + size_t * size = (size_t *) array; + size_t bsize = (*size + 7) >> 3; + memset(size + 1, 0, bsize); + } +} + + +void bit_array_set(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + ptr[bit >> 3] |= (1U << (bit & 7)); + } + } +} + +void bit_array_set_range(void * array, size_t bit, size_t count) +{ + if (array && count) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + size_t i; + for (i = bit; i < *size && i < bit + count; ++i) + ptr[i >> 3] |= (1U << (i & 7)); + } + } +} + +int bit_array_test(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + if (ptr[bit >> 3] & (1U << (bit & 7))) + { + return 1; + } + } + } + return 0; +} + +int bit_array_test_range(void * array, size_t bit, size_t count) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + if ((bit & 7) && (count > 8)) + { + while ((bit < *size) && count && (bit & 7)) + { + if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; + bit++; + count--; + } + } + if (!(bit & 7)) + { + while (((*size - bit) >= 8) && (count >= 8)) + { + if (ptr[bit >> 3]) return 1; + bit += 8; + count -= 8; + } + } + while ((bit < *size) && count) + { + if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; + bit++; + count--; + } + } + } + return 0; +} + +void bit_array_clear(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + ptr[bit >> 3] &= ~(1U << (bit & 7)); + } + } +} + +void bit_array_clear_range(void * array, size_t bit, size_t count) +{ + if (array && count) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + size_t i; + for (i = bit; i < *size && i < bit + count; ++i) + ptr[i >> 3] &= ~(1U << (i & 7)); + } + } +} + +void bit_array_merge(void * dest, void * source, size_t offset) +{ + if (dest && source) + { + size_t * dsize = (size_t *) dest; + size_t * ssize = (size_t *) source; + size_t soffset = 0; + while (offset < *dsize && soffset < *ssize) + { + if (bit_array_test(source, soffset)) + { + bit_array_set(dest, offset); + } + soffset++; + offset++; + } + } +} + +void bit_array_mask(void * dest, void * source, size_t offset) +{ + if (dest && source) + { + size_t * dsize = (size_t *) dest; + size_t * ssize = (size_t *) source; + size_t soffset = 0; + while (offset < *dsize && soffset < *ssize) + { + if (bit_array_test(source, soffset)) + { + bit_array_clear(dest, offset); + } + soffset++; + offset++; + } + } +} diff --git a/Frameworks/lazyusf/lazyusf/usf/barray.h b/Frameworks/lazyusf/lazyusf/usf/barray.h new file mode 100644 index 000000000..1ab3ff4cd --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/barray.h @@ -0,0 +1,41 @@ +#ifndef _B_ARRAY_H_ +#define _B_ARRAY_H_ + +#include + +#ifdef BARRAY_DECORATE +#define PASTE(a,b) a ## b +#define EVALUATE(a,b) PASTE(a,b) +#define bit_array_create EVALUATE(BARRAY_DECORATE,_bit_array_create) +#define bit_array_destroy EVALUATE(BARRAY_DECORATE,_bit_array_destroy) +#define bit_array_dup EVALUATE(BARRAY_DECORATE,_bit_array_dup) +#define bit_array_reset EVALUATE(BARRAY_DECORATE,_bit_array_reset) +#define bit_array_set EVALUATE(BARRAY_DECORATE,_bit_array_set) +#define bit_array_set_range EVALUATE(BARRAY_DECORATE,_bit_array_set_range) +#define bit_array_test EVALUATE(BARRAY_DECORATE,_bit_array_test) +#define bit_array_test_range EVALUATE(BARRAY_DECORATE,_bit_array_test_range) +#define bit_array_clear EVALUATE(BARRAY_DECORATE,_bit_array_clear) +#define bit_array_clear_range EVALUATE(BARRAY_DECORATE,_bit_array_clear_range) +#define bit_array_merge EVALUATE(BARRAY_DECORATE,_bit_array_merge) +#define bit_array_mask EVALUATE(BARRAY_DECORATE,_bit_array_mask) +#endif + +void * bit_array_create(size_t size); +void bit_array_destroy(void * array); +void * bit_array_dup(void * array); + +void bit_array_reset(void * array); + +void bit_array_set(void * array, size_t bit); +void bit_array_set_range(void * array, size_t bit, size_t count); + +int bit_array_test(void * array, size_t bit); +int bit_array_test_range(void * array, size_t bit, size_t count); + +void bit_array_clear(void * array, size_t bit); +void bit_array_clear_range(void * array, size_t bit, size_t count); + +void bit_array_merge(void * array, void * source, size_t offset); +void bit_array_mask(void * array, void * source, size_t offset); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/usf/resampler.c b/Frameworks/lazyusf/lazyusf/usf/resampler.c new file mode 100644 index 000000000..b9d41a0d4 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/resampler.c @@ -0,0 +1,328 @@ +#include +#include +#define _USE_MATH_DEFINES +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "resampler.h" + +enum { RESAMPLER_SHIFT = 10 }; +enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; +enum { SINC_WIDTH = 16 }; +enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; + +static const float RESAMPLER_BLEP_CUTOFF = 0.90f; +static const float RESAMPLER_BLAM_CUTOFF = 0.93f; +static const float RESAMPLER_SINC_CUTOFF = 0.999f; + +static float sinc_lut[SINC_SAMPLES + 1]; +static float window_lut[SINC_SAMPLES + 1]; + +enum { resampler_buffer_size = SINC_WIDTH * 4 }; + +static int fEqual(const float b, const float a) +{ + return fabs(a - b) < 1.0e-6; +} + +static float sinc(float x) +{ + return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); +} + +void resampler_init(void) +{ + unsigned i; + double dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; + for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) + { + float y = x / SINC_WIDTH; +#if 0 + // Blackman + float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); +#elif 1 + // Nuttal 3 term + float window = 0.40897 + 0.5 * cos(M_PI * y) + 0.09103 * cos(2.0 * M_PI * y); +#elif 0 + // C.R.Helmrich's 2 term window + float window = 0.79445 * cos(0.5 * M_PI * y) + 0.20555 * cos(1.5 * M_PI * y); +#elif 0 + // Lanczos + float window = sinc(y); +#endif + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) : 0.0; + window_lut[i] = window; + } +} + +typedef struct resampler +{ + int write_pos, write_filled; + int read_pos, read_filled; + float phase; + float phase_inc; + signed char delay_added; + signed char delay_removed; + float buffer_in[2][resampler_buffer_size * 2]; + float buffer_out[resampler_buffer_size * 2]; +} resampler; + +void * resampler_create(void) +{ + resampler * r = ( resampler * ) malloc( sizeof(resampler) ); + if ( !r ) return 0; + + r->write_pos = SINC_WIDTH - 1; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; + r->phase_inc = 0; + r->delay_added = -1; + r->delay_removed = -1; + memset( r->buffer_in, 0, sizeof(r->buffer_in) ); + memset( r->buffer_out, 0, sizeof(r->buffer_out) ); + + return r; +} + +void resampler_delete(void * _r) +{ + free( _r ); +} + +void * resampler_dup(const void * _r) +{ + void * r_out = malloc( sizeof(resampler) ); + if ( !r_out ) return 0; + + resampler_dup_inplace(r_out, _r); + + return r_out; +} + +void resampler_dup_inplace(void *_d, const void *_s) +{ + const resampler * r_in = ( const resampler * ) _s; + resampler * r_out = ( resampler * ) _d; + + r_out->write_pos = r_in->write_pos; + r_out->write_filled = r_in->write_filled; + r_out->read_pos = r_in->read_pos; + r_out->read_filled = r_in->read_filled; + r_out->phase = r_in->phase; + r_out->phase_inc = r_in->phase_inc; + r_out->delay_added = r_in->delay_added; + r_out->delay_removed = r_in->delay_removed; + memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); + memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); +} + +int resampler_get_free_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + return resampler_buffer_size - r->write_filled; +} + +static int resampler_min_filled(resampler *r) +{ + return SINC_WIDTH * 2; +} + +static int resampler_input_delay(resampler *r) +{ + return SINC_WIDTH - 1; +} + +static int resampler_output_delay(resampler *r) +{ + return 0; +} + +int resampler_ready(void *_r) +{ + resampler * r = ( resampler * ) _r; + return r->write_filled > resampler_min_filled(r); +} + +void resampler_clear(void *_r) +{ + resampler * r = ( resampler * ) _r; + r->write_pos = SINC_WIDTH - 1; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; + r->delay_added = -1; + r->delay_removed = -1; +} + +void resampler_set_rate(void *_r, double new_factor) +{ + resampler * r = ( resampler * ) _r; + r->phase_inc = new_factor; +} + +void resampler_write_sample(void *_r, short ls, short rs) +{ + resampler * r = ( resampler * ) _r; + + if ( r->delay_added < 0 ) + { + r->delay_added = 0; + r->write_filled = resampler_input_delay( r ); + } + + if ( r->write_filled < resampler_buffer_size ) + { + float s32 = ls; + + r->buffer_in[ 0 ][ r->write_pos ] = s32; + r->buffer_in[ 0 ][ r->write_pos + resampler_buffer_size ] = s32; + + s32 = rs; + + r->buffer_in[ 1 ][ r->write_pos ] = s32; + r->buffer_in[ 1 ][ r->write_pos + resampler_buffer_size ] = s32; + + ++r->write_filled; + + r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; + } +} + +static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + int in_offset = resampler_buffer_size + r->write_pos - r->write_filled; + float const* inl_ = r->buffer_in[0] + in_offset; + float const* inr_ = r->buffer_in[1] + in_offset; + int used = 0; + in_size -= SINC_WIDTH * 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* inl = inl_; + float const* inr = inr_; + float const* const in_end = inl + in_size; + float phase = r->phase; + float phase_inc = r->phase_inc; + + int step = phase_inc > 1.0f ? (int)(RESAMPLER_RESOLUTION / phase_inc * RESAMPLER_SINC_CUTOFF) : (int)(RESAMPLER_RESOLUTION * RESAMPLER_SINC_CUTOFF); + int window_step = RESAMPLER_RESOLUTION; + + do + { + float kernel[SINC_WIDTH * 2], kernel_sum = 0.0; + int i = SINC_WIDTH; + int phase_reduced = (int)(phase * RESAMPLER_RESOLUTION); + int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; + float samplel, sampler; + + if ( out >= out_end ) + break; + + for (; i >= -SINC_WIDTH + 1; --i) + { + int pos = i * step; + int window_pos = i * window_step; + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; + } + for (samplel = 0, sampler = 0, i = 0; i < SINC_WIDTH * 2; ++i) + { + samplel += inl[i] * kernel[i]; + sampler += inr[i] * kernel[i]; + } + kernel_sum = 1.0f / kernel_sum; + *out++ = (float)(samplel * kernel_sum); + *out++ = (float)(sampler * kernel_sum); + + phase += phase_inc; + + inl += (int)phase; + inr += (int)phase; + + phase = fmod(phase, 1.0f); + } + while ( inl < in_end ); + + r->phase = phase; + *out_ = out; + + used = (int)(inl - inl_); + + r->write_filled -= used; + } + + return used; +} + +static void resampler_fill(resampler * r) +{ + int min_filled = resampler_min_filled(r); + while ( r->write_filled > min_filled && + r->read_filled < resampler_buffer_size ) + { + int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size; + int write_size = resampler_buffer_size - write_pos; + float * out = r->buffer_out + write_pos * 2; + if ( write_size > ( resampler_buffer_size - r->read_filled ) ) + write_size = resampler_buffer_size - r->read_filled; + resampler_run_sinc( r, &out, out + write_size * 2 ); + r->read_filled += ( out - r->buffer_out - write_pos * 2 ) / 2; + } +} + +static void resampler_fill_and_remove_delay(resampler * r) +{ + resampler_fill( r ); + if ( r->delay_removed < 0 ) + { + int delay = resampler_output_delay( r ); + r->delay_removed = 0; + while ( delay-- ) + resampler_remove_sample( r ); + } +} + +int resampler_get_sample_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 ) + resampler_fill_and_remove_delay( r ); + return r->read_filled; +} + +void resampler_get_sample(void *_r, short * ls, short * rs) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 && r->phase_inc) + resampler_fill_and_remove_delay( r ); + if ( r->read_filled < 1 ) + { + *ls = 0; + *rs = 0; + } + else + { + int samplel = (int)r->buffer_out[ r->read_pos * 2 + 0 ]; + int sampler = (int)r->buffer_out[ r->read_pos * 2 + 1 ]; + if ( ( samplel + 0x8000 ) & 0xffff0000 ) samplel = ( samplel >> 31 ) ^ 0x7fff; + if ( ( sampler + 0x8000 ) & 0xffff0000 ) sampler = ( sampler >> 31 ) ^ 0x7fff; + *ls = (short)samplel; + *rs = (short)sampler; + } +} + +void resampler_remove_sample(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled > 0 ) + { + --r->read_filled; + r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size; + } +} diff --git a/Frameworks/lazyusf/lazyusf/usf/resampler.h b/Frameworks/lazyusf/lazyusf/usf/resampler.h new file mode 100644 index 000000000..c7be3c2de --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/resampler.h @@ -0,0 +1,42 @@ +#ifndef _RESAMPLER_H_ +#define _RESAMPLER_H_ + +// Ugglay +#ifdef RESAMPLER_DECORATE +#define PASTE(a,b) a ## b +#define EVALUATE(a,b) PASTE(a,b) +#define resampler_init EVALUATE(RESAMPLER_DECORATE,_resampler_init) +#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create) +#define resampler_delete EVALUATE(RESAMPLER_DECORATE,_resampler_delete) +#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup) +#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace) +#define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality) +#define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count) +#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample) +#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed) +#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate) +#define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready) +#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear) +#define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count) +#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample) +#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float) +#define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample) +#endif + +void resampler_init(void); + +void * resampler_create(void); +void resampler_delete(void *); +void * resampler_dup(const void *); +void resampler_dup_inplace(void *, const void *); + +int resampler_get_free_count(void *); +void resampler_write_sample(void *, short sample_l, short sample_r); +void resampler_set_rate( void *, double new_factor ); +int resampler_ready(void *); +void resampler_clear(void *); +int resampler_get_sample_count(void *); +void resampler_get_sample(void *, short * sample_l, short * sample_r); +void resampler_remove_sample(void *); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/usf/usf.c b/Frameworks/lazyusf/lazyusf/usf/usf.c new file mode 100644 index 000000000..aaee3ac38 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/usf.c @@ -0,0 +1,470 @@ + +#include +#include + +#include "usf.h" + +#include +#include + +#include "usf_internal.h" + +#include "api/callbacks.h" +#include "main/savestates.h" +#include "r4300/cached_interp.h" +#include "r4300/r4300.h" + +#include "resampler.h" + +#include "barray.h" + +size_t usf_get_state_size() +{ + return sizeof(usf_state_t) + 8192; +} + +void usf_clear(void * state) +{ + size_t offset; + memset(state, 0, usf_get_state_size()); + offset = 4096 - (((uintptr_t)state) & 4095); + USF_STATE_HELPER->offset_to_structure = offset; + + //USF_STATE->enablecompare = 0; + //USF_STATE->enableFIFOfull = 0; + + //USF_STATE->enable_hle_audio = 0; + + // Constants, never written to + USF_STATE->trunc_mode = 0xF3F; + USF_STATE->round_mode = 0x33F; + USF_STATE->ceil_mode = 0xB3F; + USF_STATE->floor_mode = 0x73F; +#ifdef DYNAREC + USF_STATE->precomp_instr_size = sizeof(precomp_instr); +#endif + + // USF_STATE->g_rom = 0; + // USF_STATE->g_rom_size = 0; + + USF_STATE->save_state = calloc( 1, 0x80275c ); + USF_STATE->save_state_size = 0x80275c; + + for (offset = 0; offset < 0x10000; offset += 4) + { + USF_STATE->EmptySpace[offset / 4] = (uint32_t)((offset << 16) | offset); + } + + resampler_init(); + + USF_STATE->resampler = resampler_create(); + +#ifdef DEBUG_INFO + USF_STATE->debug_log = fopen("/tmp/lazyusf.log", "w"); +#endif +} + +void usf_set_compare(void * state, int enable) +{ + USF_STATE->enablecompare = enable; +} + +void usf_set_fifo_full(void * state, int enable) +{ + USF_STATE->enableFIFOfull = enable; +} + +void usf_set_hle_audio(void * state, int enable) +{ + USF_STATE->enable_hle_audio = enable; +} + +void usf_set_trimming_mode(void * state, int enable) +{ + USF_STATE->enable_trimming_mode = enable; +} + +static uint32_t get_le32( const void * _p ) +{ + const uint8_t * p = (const uint8_t *) _p; + return p[0] + p[1] * 0x100 + p[2] * 0x10000 + p[3] * 0x1000000; +} + +int usf_upload_section(void * state, const uint8_t * data, size_t size) +{ + uint32_t temp; + + if ( size < 4 ) return -1; + temp = get_le32( data ); data += 4; size -= 4; + + if(temp == 0x34365253) { //there is a rom section + uint32_t len, start; + + if ( size < 4 ) return -1; + len = get_le32( data ); data += 4; size -= 4; + + while(len) { + if ( size < 4 ) return -1; + start = get_le32( data ); data += 4; size -= 4; + + if ( start + len > USF_STATE->g_rom_size ) + { + void * new_rom; + int old_rom_size = USF_STATE->g_rom_size; + while ( start + len > USF_STATE->g_rom_size ) + { + if (!USF_STATE->g_rom_size) + USF_STATE->g_rom_size = 1024 * 1024; + else + USF_STATE->g_rom_size *= 2; + } + + new_rom = realloc( USF_STATE->g_rom, USF_STATE->g_rom_size ); + if ( !new_rom ) + return -1; + + USF_STATE->g_rom = (unsigned char *) new_rom; + memset(USF_STATE->g_rom + old_rom_size, 0, USF_STATE->g_rom_size - old_rom_size); + } + + memcpy( USF_STATE->g_rom + start, data, len ); + data += len; size -= len; + + if ( size < 4 ) return -1; + len = get_le32( data ); data += 4; size -= 4; + } + } + + if ( size < 4 ) return -1; + temp = get_le32( data ); data += 4; size -= 4; + + if(temp == 0x34365253) { + uint32_t len, start; + + if ( !USF_STATE->save_state ) return -1; + + if ( size < 4 ) return -1; + len = get_le32( data ); data += 4; size -= 4; + + while(len) { + if ( size < 4 ) return -1; + start = get_le32( data ); data += 4; size -= 4; + + if ( size < len ) return -1; + memcpy( USF_STATE->save_state + start, data, len ); + data += len; size -= len; + + if ( size < 4 ) return -1; + len = get_le32( data ); data += 4; size -= 4; + } + } + + return 0; +} + +void usf_upload_rom(void * state, const uint8_t * data, size_t size) +{ + if (USF_STATE->g_rom) + free(USF_STATE->g_rom); + + USF_STATE->g_rom = (unsigned char *) malloc(size); + if (USF_STATE->g_rom) + memcpy(USF_STATE->g_rom, data, size); + USF_STATE->g_rom_size = (uint32_t) size; +} + +void usf_upload_save_state(void * state, const uint8_t * data, size_t size) +{ + if (USF_STATE->save_state) + free(USF_STATE->save_state); + + USF_STATE->save_state = (unsigned char *) malloc(size); + if (USF_STATE->save_state) + memcpy(USF_STATE->save_state, data, size); + USF_STATE->save_state_size = (uint32_t) size; +} + +static int usf_startup(usf_state_t * state) +{ + if (state->g_rom == NULL) + { + state->g_rom_size = 0; + } + + if (state->save_state == NULL) + { + DebugMessage(state, 1, "Save State is missing\n"); + return -1; + } + + // Detect the Ramsize before the memory allocation + if(get_le32(state->save_state + 4) == 0x400000) { + void * savestate; + savestate = realloc(state->save_state, 0x40275c); + if ( savestate ) + state->save_state = savestate; + state->save_state_size = 0x40275c; + } + + open_rom(state); + + if (main_start(state) != M64ERR_SUCCESS) + { + DebugMessage(state, 1, "Invalid Project64 Save State\n"); + return -1; + } + + if (state->enable_trimming_mode) + { + state->barray_rom = bit_array_create(state->g_rom_size / 4); + state->barray_ram_read = bit_array_create(get_le32(state->save_state + 4) / 4); + state->barray_ram_written_first = bit_array_create(get_le32(state->save_state + 4) / 4); + } + + state->MemoryState = 1; + + return 0; +} + +void usf_set_audio_format(void *opaque, unsigned int frequency, unsigned int bits) +{ + usf_state_t * state = (usf_state_t *)opaque; + + state->SampleRate = frequency; +} + +void usf_push_audio_samples(void *opaque, const void * buffer, size_t size) +{ + usf_state_t * state = (usf_state_t *)opaque; + + int16_t * samplePtr = (int16_t *)buffer; + int16_t * samplesOut; + size_t samplesTodo; + size_t i; + size /= 4; + + samplesTodo = size; + if (samplesTodo > state->sample_buffer_count) + samplesTodo = state->sample_buffer_count; + state->sample_buffer_count -= samplesTodo; + + samplesOut = state->sample_buffer; + size -= samplesTodo; + + if (samplesOut) + { + for (i = 0; i < samplesTodo; ++i) + { + *samplesOut++ = samplePtr[1]; + *samplesOut++ = samplePtr[0]; + samplePtr += 2; + } + state->sample_buffer = samplesOut; + } + else + samplePtr += samplesTodo * 2; + + if (size) + { + samplesTodo = 8192 - state->samples_in_buffer; + if (samplesTodo > size) + samplesTodo = size; + + samplesOut = state->samplebuf + state->samples_in_buffer * 2; + size -= samplesTodo; + state->samples_in_buffer += samplesTodo; + + for (i = 0; i < samplesTodo; ++i) + { + *samplesOut++ = samplePtr[1]; + *samplesOut++ = samplePtr[0]; + samplePtr += 2; + } + + state->stop = 1; + } + + if (size) + DebugMessage(state, 1, "Sample buffer full!"); +} + +const char * usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate) +{ + USF_STATE->last_error = 0; + USF_STATE->error_message[0] = '\0'; + + if ( !USF_STATE->MemoryState ) + { + if ( usf_startup( USF_STATE ) < 0 ) + return USF_STATE->last_error; + } + + if ( USF_STATE->samples_in_buffer ) + { + size_t do_max = USF_STATE->samples_in_buffer; + if ( do_max > count ) + do_max = count; + + if ( buffer ) + memcpy( buffer, USF_STATE->samplebuf, sizeof(int16_t) * 2 * do_max ); + + USF_STATE->samples_in_buffer -= do_max; + + if ( sample_rate ) + *sample_rate = USF_STATE->SampleRate; + + if ( USF_STATE->samples_in_buffer ) + { + memmove( USF_STATE->samplebuf, USF_STATE->samplebuf + do_max * 2, sizeof(int16_t) * 2 * USF_STATE->samples_in_buffer ); + return 0; + } + + if ( buffer ) + buffer += 2 * do_max; + count -= do_max; + } + + USF_STATE->sample_buffer = buffer; + USF_STATE->sample_buffer_count = count; + + USF_STATE->stop = 0; + + main_run(USF_STATE); + + if ( sample_rate ) + *sample_rate = USF_STATE->SampleRate; + + return USF_STATE->last_error; +} + +const char * usf_render_resampled(void * state, int16_t * buffer, size_t count, int32_t sample_rate) +{ + if ( !buffer ) + { + unsigned long samples_buffered = resampler_get_sample_count( USF_STATE->resampler ); + resampler_clear(USF_STATE->resampler); + if (samples_buffered) + { + unsigned long samples_to_remove = samples_buffered; + if (samples_to_remove > count) + samples_to_remove = count; + while (samples_to_remove--) + resampler_remove_sample(USF_STATE->resampler); + if (!count) + return 0; + } + count = (size_t)((uint64_t)count * USF_STATE->SampleRate / sample_rate); + if (count > USF_STATE->samples_in_buffer_2) + { + count -= USF_STATE->samples_in_buffer_2; + USF_STATE->samples_in_buffer_2 = 0; + } + else if (count) + { + USF_STATE->samples_in_buffer_2 -= count; + memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + 8192 - USF_STATE->samples_in_buffer_2 * 2, USF_STATE->samples_in_buffer_2 * sizeof(short) * 2); + return 0; + } + return usf_render(state, buffer, count, NULL); + } + while ( count ) + { + const char * err; + + while ( USF_STATE->samples_in_buffer_2 && resampler_get_free_count(USF_STATE->resampler) ) + { + int i = 0, j = resampler_get_free_count(USF_STATE->resampler); + if (j > USF_STATE->samples_in_buffer_2) + j = (int)USF_STATE->samples_in_buffer_2; + for (i = 0; i < j; ++i) + { + resampler_write_sample(USF_STATE->resampler, USF_STATE->samplebuf2[i*2], USF_STATE->samplebuf2[i*2+1]); + } + memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + i * 2, (USF_STATE->samples_in_buffer_2 - i) * sizeof(short) * 2); + USF_STATE->samples_in_buffer_2 -= i; + } + + while ( count && resampler_get_sample_count(USF_STATE->resampler) ) + { + resampler_get_sample(USF_STATE->resampler, buffer, buffer + 1); + resampler_remove_sample(USF_STATE->resampler); + buffer += 2; + --count; + } + + if (!count) + break; + + if (USF_STATE->samples_in_buffer_2) + continue; + + err = usf_render(state, USF_STATE->samplebuf2, 4096, 0); + if (err) + return err; + + USF_STATE->samples_in_buffer_2 = 4096; + + resampler_set_rate(USF_STATE->resampler, (float)USF_STATE->SampleRate / (float)sample_rate); + } + + return 0; +} + +void usf_restart(void * state) +{ + if ( USF_STATE->MemoryState ) + { + r4300_end(USF_STATE); + if (USF_STATE->enable_trimming_mode) + { + bit_array_destroy(USF_STATE->barray_rom); + bit_array_destroy(USF_STATE->barray_ram_read); + bit_array_destroy(USF_STATE->barray_ram_written_first); + USF_STATE->barray_rom = 0; + USF_STATE->barray_ram_read = 0; + USF_STATE->barray_ram_written_first = 0; + } + USF_STATE->MemoryState = 0; + } + + USF_STATE->samples_in_buffer = 0; + USF_STATE->samples_in_buffer_2 = 0; + + resampler_clear(USF_STATE->resampler); +} + +void usf_shutdown(void * state) +{ + r4300_end(USF_STATE); + if (USF_STATE->enable_trimming_mode) + { + if (USF_STATE->barray_rom) + bit_array_destroy(USF_STATE->barray_rom); + if (USF_STATE->barray_ram_read) + bit_array_destroy(USF_STATE->barray_ram_read); + if (USF_STATE->barray_ram_written_first) + bit_array_destroy(USF_STATE->barray_ram_written_first); + USF_STATE->barray_rom = 0; + USF_STATE->barray_ram_read = 0; + USF_STATE->barray_ram_written_first = 0; + } + USF_STATE->MemoryState = 0; + free(USF_STATE->save_state); + USF_STATE->save_state = 0; + close_rom(USF_STATE); +#ifdef DEBUG_INFO + fclose(USF_STATE->debug_log); +#endif + resampler_delete(USF_STATE->resampler); + USF_STATE->resampler = 0; +} + +void * usf_get_rom_coverage_barray(void * state) +{ + return USF_STATE->barray_rom; +} + +void * usf_get_ram_coverage_barray(void * state) +{ + return USF_STATE->barray_ram_read; +} diff --git a/Frameworks/lazyusf/lazyusf/usf.h b/Frameworks/lazyusf/lazyusf/usf/usf.h similarity index 66% rename from Frameworks/lazyusf/lazyusf/usf.h rename to Frameworks/lazyusf/lazyusf/usf/usf.h index 5e0076e41..e88faba6c 100644 --- a/Frameworks/lazyusf/lazyusf/usf.h +++ b/Frameworks/lazyusf/lazyusf/usf/usf.h @@ -30,6 +30,22 @@ void usf_clear(void * state); void usf_set_compare(void * state, int enable); void usf_set_fifo_full(void * state, int enable); +/* This mode will slow the emulator down to cached interpreter mode, + and will keep track of all ROM 32 bit words which are read, and + all RAM words which are read before they are written to. */ +void usf_set_trimming_mode(void * state, int enable); + +/* These will be the valid bit arrays, accessible using the functions + in barray.h, which indicate which words have been accessed up to + the present point in emulation, as long as the above mode is enabled. + If emulation has not started with trimming mode enabled, these will + return NULL. + ROM coverage array will contain as many entries as 1 per 4 bytes of + uploaded ROM data, while RAM coverage will contain 1 per 4 bytes of + system RDRAM, either 4MB or 8MB depending on the save state. */ +void * usf_get_rom_coverage_barray(void * state); +void * usf_get_ram_coverage_barray(void * state); + /* This option should speed up decoding significantly, at the expense of accuracy, and potentially emulation bugs. */ void usf_set_hle_audio(void * state, int enable); @@ -42,6 +58,11 @@ void usf_set_hle_audio(void * state, int enable); Returns -1 on invalid data error, or 0 on success. */ int usf_upload_section(void * state, const uint8_t * data, size_t size); +/* These will upload full ROM or save state images as-is, replacing + whatever is already loaded into the emulator. */ +void usf_upload_rom(void * state, const uint8_t * data, size_t size); +void usf_upload_save_state(void * state, const uint8_t * data, size_t size); + /* Renders at least enough sample DMA blocks to fill the count passed in. A null pointer is acceptable, in which case samples will be discarded. Requesting zero samples with a null pointer is an acceptable way to @@ -56,6 +77,9 @@ int usf_upload_section(void * state, const uint8_t * data, size_t size); Returns 0 on success, or a pointer to the last error message on failure. */ const char * usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate); +/* Same as above, only resampling to the specified rate */ +const char * usf_render_resampled(void * state, int16_t * buffer, size_t count, int32_t sample_rate); + /* Reloads the ROM and save state, effectively restarting emulation. Also discards any buffered sample data. */ void usf_restart(void * state); diff --git a/Frameworks/lazyusf/lazyusf/usf/usf_internal.h b/Frameworks/lazyusf/lazyusf/usf/usf_internal.h new file mode 100644 index 000000000..1678baf57 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/usf/usf_internal.h @@ -0,0 +1,484 @@ +#ifndef _USF_INTERNAL_H_ +#define _USF_INTERNAL_H_ + +#include "osal/preproc.h" + +#include "main/main.h" +#include "main/rom.h" + +#include "ai/ai_controller.h" +#include "memory/memory.h" +#include "pi/pi_controller.h" + +#include "r4300/r4300_core.h" +#include "r4300/ops.h" +#include "r4300/cp0.h" + +#include "rdp/rdp_core.h" +#include "ri/ri_controller.h" +#include "rsp/rsp_core.h" +#include "si/si_controller.h" +#include "vi/vi_controller.h" + +#include "rsp_hle/hle.h" + +#include + +struct usf_state_helper +{ + size_t offset_to_structure; +}; + +#ifdef DEBUG_INFO +#include +#endif + +#ifndef RCPREG_DEFINED +#define RCPREG_DEFINED +typedef uint32_t RCPREG; +#endif + +#if defined(__x86_64__) +typedef struct _jump_table +{ + unsigned int mi_addr; + unsigned int pc_addr; + unsigned int absolute64; +} jump_table; + +typedef struct _riprelative_table +{ + unsigned int pc_addr; /* index in bytes from start of x86_64 code block to the displacement value to write */ + unsigned int extra_bytes; /* number of remaining instruction bytes (immediate data) after 4-byte displacement */ + unsigned char *global_dst; /* 64-bit pointer to the data object */ +} riprelative_table; +#else +typedef struct _jump_table +{ + unsigned int mi_addr; + unsigned int pc_addr; +} jump_table; +#endif + +#ifndef INTERUPT_STRUCTS +#define INTERUPT_STRUCTS +#define POOL_CAPACITY 16 + +struct interrupt_event +{ + int type; + unsigned int count; +}; + + +struct node +{ + struct interrupt_event data; + struct node *next; +}; + +struct pool +{ + struct node nodes[POOL_CAPACITY]; + struct node* stack[POOL_CAPACITY]; + size_t index; +}; + + +struct interrupt_queue +{ + struct pool pool; + struct node* first; +}; +#endif + +#ifndef TLB_STRUCTS +#define TLB_STRUCTS +typedef struct _tlb +{ + short mask; + int vpn2; + char g; + unsigned char asid; + int pfn_even; + char c_even; + char d_even; + char v_even; + int pfn_odd; + char c_odd; + char d_odd; + char v_odd; + char r; + //int check_parity_mask; + + unsigned int start_even; + unsigned int end_even; + unsigned int phys_even; + unsigned int start_odd; + unsigned int end_odd; + unsigned int phys_odd; +} tlb; +#endif + +#ifndef PRECOMP_STRUCTS +#define PRECOMP_STRUCTS + +#if defined(__x86_64__) +#include "r4300/x86_64/assemble_struct.h" +#else +#include "r4300/x86/assemble_struct.h" +#endif + +typedef struct _precomp_instr +{ + void (osal_fastcall *ops)(usf_state_t * state); + union + { + struct + { + long long int *rs; + long long int *rt; + short immediate; + } i; + struct + { + unsigned int inst_index; + } j; + struct + { + long long int *rs; + long long int *rt; + long long int *rd; + unsigned char sa; + unsigned char nrd; + } r; + struct + { + unsigned char base; + unsigned char ft; + short offset; + } lf; + struct + { + unsigned char ft; + unsigned char fs; + unsigned char fd; + } cf; + } f; + unsigned int addr; /* word-aligned instruction address in r4300 address space */ + unsigned int local_addr; /* byte offset to start of corresponding x86_64 instructions, from start of code block */ + reg_cache_struct reg_cache_infos; +} precomp_instr; + +typedef struct _precomp_block +{ + precomp_instr *block; + unsigned int start; + unsigned int end; + unsigned char *code; + unsigned int code_length; + unsigned int max_code_length; + void *jumps_table; + int jumps_number; + void *riprel_table; + int riprel_number; + //unsigned char md5[16]; + unsigned int adler32; +} precomp_block; +#endif + +struct usf_state +{ + // main/main.c + uint32_t g_rdram[RDRAM_MAX_SIZE/4]; + + // RSP vector registers, need to be aligned to 16 bytes + // when SSE2 or SSSE3 is enabled, or for any hope of + // auto vectorization + + // usf_clear takes care of aligning the structure within + // the memory block passed into it, treating the pointer + // as usf_state_helper, and storing an offset from the + // pointer to the actual usf_state structure. The size + // which is indicated for allocation accounts for this + // with two pages of padding. + + int16_t VR[32][8]; + int16_t VACC[3][8]; + + // RSP virtual registers, also needs alignment + int32_t SR[32]; + + // rsp/rsp.c, not necessarily in need of alignment + RCPREG* CR[16]; + + // rsp/vu/cf.h, all need alignment + int16_t ne[8]; /* $vco: high byte "NOTEQUAL" */ + int16_t co[8]; /* $vco: low byte "carry/borrow in/out" */ + int16_t clip[8]; /* $vcc: high byte (clip tests: VCL, VCH, VCR) */ + int16_t comp[8]; /* $vcc: low byte (VEQ, VNE, VLT, VGE, VCL, VCH, VCR) */ + int16_t vce[8]; /* $vce: vector compare extension register */ + + // All further members of the structure need not be aligned + + // rsp/vu/divrom.h + int32_t DivIn; /* buffered numerator of division read from vector file */ + int32_t DivOut; /* global division result set by VRCP/VRCPL/VRSQ/VRSQH */ +#if (0) + int32_t MovIn; /* We do not emulate this register (obsolete, for VMOV). */ +#endif + + int32_t DPH; + + // rsp/rsp.h + int32_t stage; // unused since EMULATE_STATIC_PC is defined by default in rsp/config.h + int32_t temp_PC; + int16_t MFC0_count[32]; + + unsigned char * DMEM; + unsigned char * IMEM; + + // rsp_hle + struct hle_t hle; + + // options from file tags + uint32_t enablecompare, enableFIFOfull; + + // options for decoding + uint32_t enable_hle_audio; + + // trimming helper + uint32_t enable_trimming_mode; + void * barray_rom; + void * barray_ram_read; + void * barray_ram_written_first; + + // save state + unsigned char * save_state; + unsigned int save_state_size; + + // buffering for rendered sample data + size_t sample_buffer_count; + int16_t * sample_buffer; + + // audio.c + // SampleRate is usually guaranteed to stay the same for the duration + // of a given track, and depends on the game. + int32_t SampleRate; + // Audio is rendered in whole Audio Interface DMA transfers, which are + // then copied directly to the caller's buffer. Any left over samples + // from the last DMA transfer that fills the caller's buffer will be + // stored here until the next call to usf_render() + int16_t samplebuf[16384]; + size_t samples_in_buffer; + + void * resampler; + int16_t samplebuf2[8192]; + size_t samples_in_buffer_2; + + // This buffer does not really need to be that large, as it is likely + // to only accumulate a handlful of error messages, at which point + // emulation is immediately halted and the messages are returned to + // the caller. + const char * last_error; + char error_message[16384]; + + uint32_t MemoryState; + + // main/main.c + struct ai_controller g_ai; + struct pi_controller g_pi; + struct ri_controller g_ri; + struct si_controller g_si; + struct vi_controller g_vi; + struct r4300_core g_r4300; + struct rdp_core g_dp; + struct rsp_core g_sp; + + // Compatibility with USF sets dictates that these all remain zero + int g_delay_si/* = 0*/; + int g_delay_ai/* = 0*/; + int g_delay_pi/* = 0*/; + int g_delay_sp/* = 0*/; + int g_delay_dp/* = 0*/; + + int g_gs_vi_counter/* = 0*/; + + unsigned int g_timer_checkpoint; + size_t last_sample_buffer_count; + + // memory/memory.c + unsigned int address, cpu_word; + unsigned char cpu_byte; + unsigned short cpu_hword; + unsigned long long cpu_dword, *rdword; + uint32_t EmptySpace[0x10000/4]; + + void (osal_fastcall *readmem[0x10000])(usf_state_t *); + void (osal_fastcall *readmemb[0x10000])(usf_state_t *); + void (osal_fastcall *readmemh[0x10000])(usf_state_t *); + void (osal_fastcall *readmemd[0x10000])(usf_state_t *); + void (osal_fastcall *writemem[0x10000])(usf_state_t *); + void (osal_fastcall *writememb[0x10000])(usf_state_t *); + void (osal_fastcall *writememh[0x10000])(usf_state_t *); + void (osal_fastcall *writememd[0x10000])(usf_state_t *); + + // main/rom.c + unsigned char* g_rom/* = NULL*/; + int g_rom_size/* = 0*/; + + m64p_rom_header ROM_HEADER; + rom_params ROM_PARAMS; + + // r4300/pure_interp.c + precomp_instr interp_PC; + + // r4300/r4300.c + unsigned int r4300emu/* = 0*/; + unsigned int count_per_op/* = COUNT_PER_OP_DEFAULT*/; + int llbit, rompause; + int stop; + long long int reg[32], hi, lo; + unsigned int next_interupt; + precomp_instr *PC; + long long int local_rs; + unsigned int delay_slot, skip_jump/* = 0*/, dyna_interp/* = 0*/, last_addr; + + cpu_instruction_table current_instruction_table; + + // r4300/reset.c + int reset_hard_job/* = 0*/; + + // r4300/cp0.c + unsigned int g_cp0_regs[CP0_REGS_COUNT]; + + // r4300/cp1.c + float *reg_cop1_simple[32]; + double *reg_cop1_double[32]; + int FCR0, FCR31; + long long int reg_cop1_fgr_64[32]; + + int rounding_mode/* = 0x33F*/; + // These constants won't be written to, but they need to be located within the struct + int trunc_mode/* = 0xF3F*/, round_mode/* = 0x33F*/, + ceil_mode/* = 0xB3F*/, floor_mode/* = 0x73F*/; + + // r4300/interupt.c + int interupt_unsafe_state/* = 0*/; + int SPECIAL_done/* = 0*/; + + struct interrupt_queue q; + + // r4300/tlb.c + tlb tlb_e[32]; + unsigned int tlb_LUT_r[0x100000]; + unsigned int tlb_LUT_w[0x100000]; + + // r4300/instr_counters.c +#ifdef COUNT_INSTR + unsigned int instr_count[132]; +#endif + + // r4300/cached_interp.c + char invalid_code[0x100000]; + precomp_block *blocks[0x100000]; + precomp_block *actual; + unsigned int jump_to_address; + + // r4300/recomp.c + precomp_instr *dst; // destination structure for the recompiled instruction + int code_length; // current real recompiled code length + int max_code_length; // current recompiled code's buffer length + unsigned char **inst_pointer; // output buffer for recompiled code + precomp_block *dst_block; // the current block that we are recompiling + int src; // the current recompiled instruction + int fast_memory; + int no_compiled_jump /* = 0*/; /* use cached interpreter instead of recompiler for jumps */ + + void (*recomp_func)(usf_state_t *); // pointer to the dynarec's generator + // function for the latest decoded opcode + + int *SRC; // currently recompiled instruction in the input stream + int check_nop; // next instruction is nop ? + int delay_slot_compiled/* = 0*/; + + int init_length; + +#ifdef DYNAREC +#ifdef _MSC_VER +#define __i386__ +#endif + + // r4300/(x86|x86_64)/assemble.c + unsigned int g_jump_start8/* = 0*/; + unsigned int g_jump_start32/* = 0*/; + + jump_table *jumps_table/* = NULL*/; + int jumps_number/* = 0*/, max_jumps_number/* = 0*/; + + // r4300/x86_64/assemble.c +#if defined(__x86_64__) + riprelative_table *riprel_table/* = NULL*/; + int riprel_number/* = 0*/, max_riprel_number/* = 0*/; +#endif + + // r4300/(x86|x86_64)/gr4300.c + precomp_instr fake_instr; + + int branch_taken/* = 0*/; + + // r4300/(x86|x86_64)/gspecial.c + unsigned int precomp_instr_size/* = sizeof(precomp_instr)*/; + + // r4300/x86/rjump.c +#if defined(__i386__) + long save_esp; + long save_eip; + + unsigned long *return_address; +#endif + + // r4300/x86_64/rjump.c +#if defined(__x86_64__) + unsigned long long *return_address; + + long long save_rsp/* = 0*/; + long long save_rip/* = 0*/; +#endif + + // r4300/x86/regcache.c +#if defined(__i386__) + unsigned int* reg_content[8]; + precomp_instr* last_access[8]; + precomp_instr* free_since[8]; + int dirty[8]; + int r64[8]; + unsigned int* r0; +#endif + + // r4300/x86_64/regcache.c +#if defined(__x86_64__) + unsigned long long * reg_content[8]; + precomp_instr* last_access[8]; + precomp_instr* free_since[8]; + int dirty[8]; + int is64bits[8]; + unsigned long long *r0; +#endif + +#endif + + // logging +#ifdef DEBUG_INFO + FILE * debug_log; +#endif +}; + +void usf_set_audio_format(void *, unsigned int frequency, unsigned int bits); +void usf_push_audio_samples(void *, const void * buffer, size_t size); + +#define USF_STATE_HELPER ((usf_state_helper_t *)(state)) + +#define USF_STATE ((usf_state_t *)(((uint8_t *)(state))+((usf_state_helper_t *)(state))->offset_to_structure)) + +#endif diff --git a/Frameworks/lazyusf/lazyusf/usf_internal.h b/Frameworks/lazyusf/lazyusf/usf_internal.h deleted file mode 100644 index 8d3eba76e..000000000 --- a/Frameworks/lazyusf/lazyusf/usf_internal.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef _USF_INTERNAL_H_ -#define _USF_INTERNAL_H_ - -#include "cpu.h" -#include "rsp_hle/hle.h" -#include "cpu_hle.h" - -struct usf_state_helper -{ - size_t offset_to_structure; -}; - -#ifndef RCPREG_DEFINED -#define RCPREG_DEFINED -typedef uint32_t RCPREG; -#endif - -#ifdef DEBUG_INFO -#include -#endif - -struct usf_state -{ - // RSP vector registers, need to be aligned to 16 bytes - // when SSE2 or SSSE3 is enabled, or for any hope of - // auto vectorization - - // usf_clear takes care of aligning the structure within - // the memory block passed into it, treating the pointer - // as usf_state_helper, and storing an offset from the - // pointer to the actual usf_state structure. The size - // which is indicated for allocation accounts for this - // with two pages of padding. - - int16_t VR[32][8]; - int16_t VACC[3][8]; - - // RSP virtual registers, also needs alignment - int32_t SR[32]; - - // rsp/rsp.c, not necessarily in need of alignment - RCPREG* CR[16]; - - // rsp/vu/cf.h, all need alignment - int16_t ne[8]; /* $vco: high byte "NOTEQUAL" */ - int16_t co[8]; /* $vco: low byte "carry/borrow in/out" */ - int16_t clip[8]; /* $vcc: high byte (clip tests: VCL, VCH, VCR) */ - int16_t comp[8]; /* $vcc: low byte (VEQ, VNE, VLT, VGE, VCL, VCH, VCR) */ - int16_t vce[8]; /* $vce: vector compare extension register */ - - // All further members of the structure need not be aligned - - // rsp/vu/divrom.h - int32_t DivIn; /* buffered numerator of division read from vector file */ - int32_t DivOut; /* global division result set by VRCP/VRCPL/VRSQ/VRSQH */ -#if (0) - int32_t MovIn; /* We do not emulate this register (obsolete, for VMOV). */ -#endif - - int32_t DPH; - - // rsp/rsp.h - int32_t stage; // unused since EMULATE_STATIC_PC is defined by default in rsp/config.h - int32_t temp_PC; - int16_t MFC0_count[32]; - - // rsp_hle - struct hle_t hle; - - uint32_t cpu_running, cpu_stopped; - - // options from file tags - uint32_t enablecompare, enableFIFOfull; - - // options for decoding - uint32_t enable_hle_audio; - - // buffering for rendered sample data - size_t sample_buffer_count; - int16_t * sample_buffer; - - // audio.c - // SampleRate is usually guaranteed to stay the same for the duration - // of a given track, and depends on the game. - int32_t SampleRate; - // Audio is rendered in whole Audio Interface DMA transfers, which are - // then copied directly to the caller's buffer. Any left over samples - // from the last DMA transfer that fills the caller's buffer will be - // stored here until the next call to usf_render() - int16_t samplebuf[16384]; - size_t samples_in_buffer; - - // This buffer does not really need to be that large, as it is likely - // to only accumulate a handlful of error messages, at which point - // emulation is immediately halted and the messages are returned to - // the caller. - const char * last_error; - char error_message[1024]; - - // cpu.c - uint32_t NextInstruction, JumpToLocation, AudioIntrReg; - CPU_ACTION * CPU_Action; - SYSTEM_TIMERS * Timers; - OPCODE Opcode; - uint32_t CPURunning, SPHack; - uint32_t * WaitMode; - - // interpreter_ops.c - uint32_t SWL_MASK[4], SWR_MASK[4], LWL_MASK[4], LWR_MASK[4]; - int32_t SWL_SHIFT[4], SWR_SHIFT[4], LWL_SHIFT[4], LWR_SHIFT[4]; - int32_t RoundingModel; - - // memory.c - uintptr_t *TLB_Map; - uint8_t * MemChunk; - uint32_t RdramSize, SystemRdramSize, RomFileSize; - uint8_t * N64MEM, * RDRAM, * DMEM, * IMEM, * ROMPages[0x400], * savestatespace, * NOMEM; - - uint32_t WrittenToRom; - uint32_t WroteToRom; - uint32_t TempValue; - uint32_t MemoryState; - - uint8_t EmptySpace; - - // pif.c - uint8_t *PIF_Ram; - - // registers.c - uint32_t PROGRAM_COUNTER, * CP0,*FPCR,*RegRDRAM,*RegSP,*RegDPC,*RegMI,*RegVI,*RegAI,*RegPI, - *RegRI,*RegSI, HalfLine, RegModValue, ViFieldNumber, LLBit, LLAddr; - void * FPRDoubleLocation[32], * FPRFloatLocation[32]; - MIPS_DWORD *GPR, *FPR, HI, LO; - int32_t fpuControl; - N64_REGISTERS * Registers; - - // tlb.c - FASTTLB FastTlb[64]; - TLB tlb[32]; - - uint32_t OLD_VI_V_SYNC_REG/* = 0*/, VI_INTR_TIME/* = 500000*/; - - uint32_t cpu_hle_entry_count; - _HLE_Entry * cpu_hle_entries; - -#ifdef DEBUG_INFO - FILE * debug_log; -#endif -}; - -#define USF_STATE_HELPER ((usf_state_helper_t *)(state)) - -#define USF_STATE ((usf_state_t *)(((uint8_t *)(state))+((usf_state_helper_t *)(state))->offset_to_structure)) - -#endif diff --git a/Frameworks/lazyusf/lazyusf/vi/vi_controller.c b/Frameworks/lazyusf/lazyusf/vi/vi_controller.c new file mode 100644 index 000000000..6293a3567 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/vi/vi_controller.c @@ -0,0 +1,118 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - vi_controller.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "usf/usf.h" + +#include "usf/usf_internal.h" + +#include "vi_controller.h" + +#include "main/main.h" +#include "memory/memory.h" +#include "r4300/r4300_core.h" +#include "r4300/cp0.h" +#include "r4300/interupt.h" + +#include + +void connect_vi(struct vi_controller* vi, + struct r4300_core* r4300) +{ + vi->r4300 = r4300; +} + +void init_vi(struct vi_controller* vi) +{ + memset(vi->regs, 0, VI_REGS_COUNT*sizeof(uint32_t)); + vi->field = 0; + + vi->delay = vi->next_vi = 5000; +} + + +int read_vi_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct vi_controller* vi = (struct vi_controller*)opaque; + uint32_t reg = vi_reg(address); + + if (reg == VI_CURRENT_REG) + { + update_count(vi->r4300->state); + vi->regs[VI_CURRENT_REG] = (vi->delay - (vi->next_vi - vi->r4300->state->g_cp0_regs[CP0_COUNT_REG]))/1500; + vi->regs[VI_CURRENT_REG] = (vi->regs[VI_CURRENT_REG] & (~1)) | vi->field; + } + + *value = vi->regs[reg]; + + return 0; +} + +int write_vi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct vi_controller* vi = (struct vi_controller*)opaque; + uint32_t reg = vi_reg(address); + + switch(reg) + { + case VI_STATUS_REG: + if ((vi->regs[VI_STATUS_REG] & mask) != (value & mask)) + { + masked_write(&vi->regs[VI_STATUS_REG], value, mask); + } + return 0; + + case VI_WIDTH_REG: + if ((vi->regs[VI_WIDTH_REG] & mask) != (value & mask)) + { + masked_write(&vi->regs[VI_WIDTH_REG], value, mask); + } + return 0; + + case VI_CURRENT_REG: + clear_rcp_interrupt(vi->r4300, MI_INTR_VI); + return 0; + } + + masked_write(&vi->regs[reg], value, mask); + + return 0; +} + +void vi_vertical_interrupt_event(struct vi_controller* vi) +{ + usf_state_t * state = vi->r4300->state; + + /* toggle vi field if in interlaced mode */ + vi->field ^= (vi->regs[VI_STATUS_REG] >> 6) & 0x1; + + /* schedule next vertical interrupt */ + vi->delay = (vi->regs[VI_V_SYNC_REG] == 0) + ? 500000 + : (vi->regs[VI_V_SYNC_REG] + 1)*1500; + + vi->next_vi += vi->delay; + + add_interupt_event_count(state, VI_INT, vi->next_vi); + + /* trigger interrupt */ + raise_rcp_interrupt(vi->r4300, MI_INTR_VI); +} + diff --git a/Frameworks/lazyusf/lazyusf/vi/vi_controller.h b/Frameworks/lazyusf/lazyusf/vi/vi_controller.h new file mode 100644 index 000000000..004fb20e9 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/vi/vi_controller.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - vi_controller.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2014 Bobby Smiles * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef M64P_VI_VI_CONTROLLER_H +#define M64P_VI_VI_CONTROLLER_H + +#include + +struct r4300_core; + +enum vi_registers +{ + VI_STATUS_REG, + VI_ORIGIN_REG, + VI_WIDTH_REG, + VI_V_INTR_REG, + VI_CURRENT_REG, + VI_BURST_REG, + VI_V_SYNC_REG, + VI_H_SYNC_REG, + VI_LEAP_REG, + VI_H_START_REG, + VI_V_START_REG, + VI_V_BURST_REG, + VI_X_SCALE_REG, + VI_Y_SCALE_REG, + VI_REGS_COUNT +}; + +struct vi_controller +{ + uint32_t regs[VI_REGS_COUNT]; + unsigned int field; + + unsigned int delay; + unsigned int next_vi; + + struct r4300_core* r4300; +}; + +#include "osal/preproc.h" + +static osal_inline uint32_t vi_reg(uint32_t address) +{ + return (address & 0xffff) >> 2; +} + +void connect_vi(struct vi_controller* vi, + struct r4300_core* r4300); + +void init_vi(struct vi_controller* vi); + +int read_vi_regs(void* opaque, uint32_t address, uint32_t* value); +int write_vi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +void vi_vertical_interrupt_event(struct vi_controller* vi); + +#endif diff --git a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm index e3f0c82a4..d8d434a2a 100644 --- a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm +++ b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm @@ -1007,6 +1007,8 @@ static int usf_info(void * context, const char * name, const char * value) memset( &state, 0, sizeof(state) ); state.emu_state = malloc( usf_get_state_size() ); + if ( !state.emu_state ) + return NO; usf_clear( state.emu_state ); @@ -1019,9 +1021,13 @@ static int usf_info(void * context, const char * name, const char * value) usf_set_compare( state.emu_state, state.enablecompare ); usf_set_fifo_full( state.emu_state, state.enablefifofull ); - - if ( usf_render( state.emu_state, 0, 0, &samplerate ) != 0 ) + + const char * err; + if ( (err = usf_render( state.emu_state, 0, 0, &samplerate ) ) != 0 ) + { + fprintf(stderr, "%s\n", err); return NO; + } sampleRate = samplerate; @@ -1308,8 +1314,12 @@ static int usf_info(void * context, const char * name, const char * value) { int32_t samplerate; - if ( usf_render( emulatorCore, (int16_t*) buf, frames, &samplerate ) != 0 ) + const char * err; + if ( (err = usf_render( emulatorCore, (int16_t*) buf, frames, &samplerate )) != 0 ) + { + fprintf(stderr, "%s\n", err); return 0; + } sampleRate = samplerate; }