diff options
26 files changed, 395 insertions, 86 deletions
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 9d62a8368..d3f0702bc 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #define MAPS_DIR "maps" | 40 | #define MAPS_DIR "maps" |
| 41 | #define CACHE_DIR "cache" | 41 | #define CACHE_DIR "cache" |
| 42 | #define SDMC_DIR "sdmc" | 42 | #define SDMC_DIR "sdmc" |
| 43 | #define EXTSAVEDATA_DIR "extsavedata" | ||
| 43 | #define SAVEDATA_DIR "savedata" | 44 | #define SAVEDATA_DIR "savedata" |
| 44 | #define SYSDATA_DIR "sysdata" | 45 | #define SYSDATA_DIR "sysdata" |
| 45 | #define SYSSAVEDATA_DIR "syssavedata" | 46 | #define SYSSAVEDATA_DIR "syssavedata" |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index bba830c70..c44ad4ca1 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -676,6 +676,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 676 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 676 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 677 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 677 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 678 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 678 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 679 | paths[D_EXTSAVEDATA] = paths[D_USER_IDX] + EXTSAVEDATA_DIR DIR_SEP; | ||
| 679 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; | 680 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; |
| 680 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; | 681 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; |
| 681 | paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP; | 682 | paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP; |
| @@ -720,6 +721,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 720 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 721 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 721 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 722 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 722 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 723 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 724 | paths[D_EXTSAVEDATA] = paths[D_USER_IDX] + EXTSAVEDATA_DIR DIR_SEP; | ||
| 723 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; | 725 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; |
| 724 | paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP; | 726 | paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP; |
| 725 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 727 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 293c30941..ec2415473 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -27,6 +27,7 @@ enum { | |||
| 27 | D_STATESAVES_IDX, | 27 | D_STATESAVES_IDX, |
| 28 | D_SCREENSHOTS_IDX, | 28 | D_SCREENSHOTS_IDX, |
| 29 | D_SDMC_IDX, | 29 | D_SDMC_IDX, |
| 30 | D_EXTSAVEDATA, | ||
| 30 | D_SAVEDATA_IDX, | 31 | D_SAVEDATA_IDX, |
| 31 | D_SYSDATA_IDX, | 32 | D_SYSDATA_IDX, |
| 32 | D_SYSSAVEDATA_IDX, | 33 | D_SYSSAVEDATA_IDX, |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fdd97c184..89ea70d23 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -17,6 +17,7 @@ set(SRCS | |||
| 17 | arm/skyeye_common/vfp/vfpdouble.cpp | 17 | arm/skyeye_common/vfp/vfpdouble.cpp |
| 18 | arm/skyeye_common/vfp/vfpinstr.cpp | 18 | arm/skyeye_common/vfp/vfpinstr.cpp |
| 19 | arm/skyeye_common/vfp/vfpsingle.cpp | 19 | arm/skyeye_common/vfp/vfpsingle.cpp |
| 20 | file_sys/archive_extsavedata.cpp | ||
| 20 | file_sys/archive_romfs.cpp | 21 | file_sys/archive_romfs.cpp |
| 21 | file_sys/archive_savedata.cpp | 22 | file_sys/archive_savedata.cpp |
| 22 | file_sys/archive_sdmc.cpp | 23 | file_sys/archive_sdmc.cpp |
| @@ -104,6 +105,7 @@ set(HEADERS | |||
| 104 | arm/skyeye_common/vfp/vfp_helper.h | 105 | arm/skyeye_common/vfp/vfp_helper.h |
| 105 | arm/arm_interface.h | 106 | arm/arm_interface.h |
| 106 | file_sys/archive_backend.h | 107 | file_sys/archive_backend.h |
| 108 | file_sys/archive_extsavedata.h | ||
| 107 | file_sys/archive_romfs.h | 109 | file_sys/archive_romfs.h |
| 108 | file_sys/archive_savedata.h | 110 | file_sys/archive_savedata.h |
| 109 | file_sys/archive_sdmc.h | 111 | file_sys/archive_sdmc.h |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 53da7ca9c..ce316ead6 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -2559,7 +2559,22 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) | |||
| 2559 | 2559 | ||
| 2560 | return inst_base; | 2560 | return inst_base; |
| 2561 | } | 2561 | } |
| 2562 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSAT16"); } | 2562 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) |
| 2563 | { | ||
| 2564 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); | ||
| 2565 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 2566 | |||
| 2567 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2568 | inst_base->idx = index; | ||
| 2569 | inst_base->br = NON_BRANCH; | ||
| 2570 | inst_base->load_r15 = 0; | ||
| 2571 | |||
| 2572 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 2573 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2574 | inst_cream->sat_imm = BITS(inst, 16, 19); | ||
| 2575 | |||
| 2576 | return inst_base; | ||
| 2577 | } | ||
| 2563 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSUB8"); } | 2578 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSUB8"); } |
| 2564 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) | 2579 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) |
| 2565 | { | 2580 | { |
| @@ -3165,7 +3180,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) | |||
| 3165 | { | 3180 | { |
| 3166 | return INTERPRETER_TRANSLATE(ssat)(inst, index); | 3181 | return INTERPRETER_TRANSLATE(ssat)(inst, index); |
| 3167 | } | 3182 | } |
| 3168 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USAT16"); } | 3183 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) |
| 3184 | { | ||
| 3185 | return INTERPRETER_TRANSLATE(ssat16)(inst, index); | ||
| 3186 | } | ||
| 3169 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB16"); } | 3187 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB16"); } |
| 3170 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB8"); } | 3188 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB8"); } |
| 3171 | ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUBADDX"); } | 3189 | ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUBADDX"); } |
| @@ -5583,6 +5601,26 @@ unsigned InterpreterMainLoop(ARMul_State* state) { | |||
| 5583 | } | 5601 | } |
| 5584 | 5602 | ||
| 5585 | SSAT16_INST: | 5603 | SSAT16_INST: |
| 5604 | { | ||
| 5605 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 5606 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 5607 | const u8 saturate_to = inst_cream->sat_imm; | ||
| 5608 | |||
| 5609 | bool sat1 = false; | ||
| 5610 | bool sat2 = false; | ||
| 5611 | |||
| 5612 | RD = (ARMul_SignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) | | ||
| 5613 | ARMul_SignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16; | ||
| 5614 | |||
| 5615 | if (sat1 || sat2) | ||
| 5616 | cpu->Cpsr |= (1 << 27); | ||
| 5617 | } | ||
| 5618 | |||
| 5619 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5620 | INC_PC(sizeof(ssat_inst)); | ||
| 5621 | FETCH_INST; | ||
| 5622 | GOTO_NEXT_INST; | ||
| 5623 | } | ||
| 5586 | SSUB8_INST: | 5624 | SSUB8_INST: |
| 5587 | STC_INST: | 5625 | STC_INST: |
| 5588 | { | 5626 | { |
| @@ -6363,6 +6401,27 @@ unsigned InterpreterMainLoop(ARMul_State* state) { | |||
| 6363 | } | 6401 | } |
| 6364 | 6402 | ||
| 6365 | USAT16_INST: | 6403 | USAT16_INST: |
| 6404 | { | ||
| 6405 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 6406 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 6407 | const u8 saturate_to = inst_cream->sat_imm; | ||
| 6408 | |||
| 6409 | bool sat1 = false; | ||
| 6410 | bool sat2 = false; | ||
| 6411 | |||
| 6412 | RD = (ARMul_UnsignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) | | ||
| 6413 | ARMul_UnsignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16; | ||
| 6414 | |||
| 6415 | if (sat1 || sat2) | ||
| 6416 | cpu->Cpsr |= (1 << 27); | ||
| 6417 | } | ||
| 6418 | |||
| 6419 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6420 | INC_PC(sizeof(ssat_inst)); | ||
| 6421 | FETCH_INST; | ||
| 6422 | GOTO_NEXT_INST; | ||
| 6423 | } | ||
| 6424 | |||
| 6366 | USUB16_INST: | 6425 | USUB16_INST: |
| 6367 | USUB8_INST: | 6426 | USUB8_INST: |
| 6368 | USUBADDX_INST: | 6427 | USUBADDX_INST: |
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index 5c036caeb..10d640f37 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp | |||
| @@ -141,7 +141,7 @@ unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* | |||
| 141 | { | 141 | { |
| 142 | if (CoProc == 10 && (OPC_1 & 0xD) == 1) | 142 | if (CoProc == 10 && (OPC_1 & 0xD) == 1) |
| 143 | { | 143 | { |
| 144 | VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS); | 144 | VMOVBRRSS(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, value1, value2); |
| 145 | return ARMul_DONE; | 145 | return ARMul_DONE; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| @@ -175,7 +175,7 @@ unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 v | |||
| 175 | { | 175 | { |
| 176 | if (CoProc == 10 && (OPC_1 & 0xD) == 1) | 176 | if (CoProc == 10 && (OPC_1 & 0xD) == 1) |
| 177 | { | 177 | { |
| 178 | VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS); | 178 | VMOVBRRSS(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, &value1, &value2); |
| 179 | return ARMul_DONE; | 179 | return ARMul_DONE; |
| 180 | } | 180 | } |
| 181 | 181 | ||
| @@ -504,6 +504,22 @@ void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword | |||
| 504 | state->ExtReg[n*2] = *value1; | 504 | state->ExtReg[n*2] = *value1; |
| 505 | } | 505 | } |
| 506 | } | 506 | } |
| 507 | void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2) | ||
| 508 | { | ||
| 509 | DBG("VMOV(BRRSS) :\n"); | ||
| 510 | if (to_arm) | ||
| 511 | { | ||
| 512 | DBG("\tr[%d-%d] <= s[%d-%d]=[%x-%x]\n", t2, t, n+1, n, state->ExtReg[n+1], state->ExtReg[n]); | ||
| 513 | *value1 = state->ExtReg[n+0]; | ||
| 514 | *value2 = state->ExtReg[n+1]; | ||
| 515 | } | ||
| 516 | else | ||
| 517 | { | ||
| 518 | DBG("\ts[%d-%d] <= r[%d-%d]=[%x-%x]\n", n+1, n, t2, t, *value2, *value1); | ||
| 519 | state->ExtReg[n+0] = *value1; | ||
| 520 | state->ExtReg[n+1] = *value2; | ||
| 521 | } | ||
| 522 | } | ||
| 507 | 523 | ||
| 508 | /* ----------- MCR ------------ */ | 524 | /* ----------- MCR ------------ */ |
| 509 | void VMSR(ARMul_State* state, ARMword reg, ARMword Rt) | 525 | void VMSR(ARMul_State* state, ARMword reg, ARMword Rt) |
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index f9e8d521d..539fb0131 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h | |||
| @@ -97,6 +97,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | |||
| 97 | void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); | 97 | void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); |
| 98 | void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); | 98 | void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); |
| 99 | void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); | 99 | void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); |
| 100 | void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); | ||
| 100 | void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); | 101 | void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); |
| 101 | void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); | 102 | void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); |
| 102 | /* MCR */ | 103 | /* MCR */ |
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 765c1f6bc..a9df490ba 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -1064,7 +1064,7 @@ vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, | |||
| 1064 | #define NEG_SUBTRACT (1 << 1) | 1064 | #define NEG_SUBTRACT (1 << 1) |
| 1065 | 1065 | ||
| 1066 | static u32 | 1066 | static u32 |
| 1067 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func) | 1067 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) |
| 1068 | { | 1068 | { |
| 1069 | struct vfp_double vdd, vdp, vdn, vdm; | 1069 | struct vfp_double vdd, vdp, vdn, vdm; |
| 1070 | u32 exceptions; | 1070 | u32 exceptions; |
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 27dc8a008..cc70fc33c 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp | |||
| @@ -2702,7 +2702,7 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index) | |||
| 2702 | inst_cream->t = BITS(inst, 12, 15); | 2702 | inst_cream->t = BITS(inst, 12, 15); |
| 2703 | inst_cream->t2 = BITS(inst, 16, 19); | 2703 | inst_cream->t2 = BITS(inst, 16, 19); |
| 2704 | inst_cream->m = BITS(inst, 0, 3)<<1|BIT(inst, 5); | 2704 | inst_cream->m = BITS(inst, 0, 3)<<1|BIT(inst, 5); |
| 2705 | 2705 | ||
| 2706 | return inst_base; | 2706 | return inst_base; |
| 2707 | } | 2707 | } |
| 2708 | #endif | 2708 | #endif |
| @@ -2711,10 +2711,11 @@ VMOVBRRSS_INST: | |||
| 2711 | { | 2711 | { |
| 2712 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | 2712 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { |
| 2713 | CHECK_VFP_ENABLED; | 2713 | CHECK_VFP_ENABLED; |
| 2714 | 2714 | ||
| 2715 | vmovbrrss_inst *inst_cream = (vmovbrrss_inst *)inst_base->component; | 2715 | vmovbrrss_inst* const inst_cream = (vmovbrrss_inst*)inst_base->component; |
| 2716 | 2716 | ||
| 2717 | VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS); | 2717 | VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, |
| 2718 | &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); | ||
| 2718 | } | 2719 | } |
| 2719 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 2720 | cpu->Reg[15] += GET_INST_SIZE(cpu); |
| 2720 | INC_PC(sizeof(vmovbrrss_inst)); | 2721 | INC_PC(sizeof(vmovbrrss_inst)); |
| @@ -2729,15 +2730,29 @@ DYNCOM_FILL_ACTION(vmovbrrss), | |||
| 2729 | int DYNCOM_TAG(vmovbrrss)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) | 2730 | int DYNCOM_TAG(vmovbrrss)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) |
| 2730 | { | 2731 | { |
| 2731 | int instr_size = INSTR_SIZE; | 2732 | int instr_size = INSTR_SIZE; |
| 2732 | DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); | 2733 | |
| 2733 | arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); | 2734 | arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); |
| 2735 | if (instr >> 28 != 0xE) | ||
| 2736 | *tag |= TAG_CONDITIONAL; | ||
| 2737 | |||
| 2734 | return instr_size; | 2738 | return instr_size; |
| 2735 | } | 2739 | } |
| 2736 | #endif | 2740 | #endif |
| 2737 | #ifdef VFP_DYNCOM_TRANS | 2741 | #ifdef VFP_DYNCOM_TRANS |
| 2738 | int DYNCOM_TRANS(vmovbrrss)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ | 2742 | int DYNCOM_TRANS(vmovbrrss)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc) |
| 2739 | DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); | 2743 | { |
| 2740 | arch_arm_undef(cpu, bb, instr); | 2744 | int to_arm = BIT(20) == 1; |
| 2745 | int t = BITS(12, 15); | ||
| 2746 | int t2 = BITS(16, 19); | ||
| 2747 | int n = BIT(5)<<4 | BITS(0, 3); | ||
| 2748 | if (to_arm) { | ||
| 2749 | LET(t, IBITCAST32(FR32(n + 0))); | ||
| 2750 | LET(t2, IBITCAST32(FR32(n + 1))); | ||
| 2751 | } | ||
| 2752 | else { | ||
| 2753 | LETFPS(n + 0, FPBITCAST32(R(t))); | ||
| 2754 | LETFPS(n + 1, FPBITCAST32(R(t2))); | ||
| 2755 | } | ||
| 2741 | return No_exp; | 2756 | return No_exp; |
| 2742 | } | 2757 | } |
| 2743 | #endif | 2758 | #endif |
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 6c33d8b78..08d0d719f 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp | |||
| @@ -957,7 +957,7 @@ vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_s | |||
| 957 | #define NEG_SUBTRACT (1 << 1) | 957 | #define NEG_SUBTRACT (1 << 1) |
| 958 | 958 | ||
| 959 | static u32 | 959 | static u32 |
| 960 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func) | 960 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) |
| 961 | { | 961 | { |
| 962 | 962 | ||
| 963 | { | 963 | { |
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index e153917ea..1612c35c2 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -46,6 +46,9 @@ public: | |||
| 46 | Path(const char* path) : type(Char), string(path) { | 46 | Path(const char* path) : type(Char), string(path) { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) { | ||
| 50 | } | ||
| 51 | |||
| 49 | Path(LowPathType type, u32 size, u32 pointer) : type(type) { | 52 | Path(LowPathType type, u32 size, u32 pointer) : type(type) { |
| 50 | switch (type) { | 53 | switch (type) { |
| 51 | case Binary: | 54 | case Binary: |
| @@ -175,6 +178,20 @@ public: | |||
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | /** | 180 | /** |
| 181 | * Tries to open the archive of this type with the specified path | ||
| 182 | * @param path Path to the archive | ||
| 183 | * @return ResultCode of the operation | ||
| 184 | */ | ||
| 185 | virtual ResultCode Open(const Path& path) = 0; | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Deletes the archive contents and then re-creates the base folder | ||
| 189 | * @param path Path to the archive | ||
| 190 | * @return ResultCode of the operation, 0 on success | ||
| 191 | */ | ||
| 192 | virtual ResultCode Format(const Path& path) const = 0; | ||
| 193 | |||
| 194 | /** | ||
| 178 | * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) | 195 | * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) |
| 179 | */ | 196 | */ |
| 180 | virtual std::string GetName() const = 0; | 197 | virtual std::string GetName() const = 0; |
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp new file mode 100644 index 000000000..4759ef3ae --- /dev/null +++ b/src/core/file_sys/archive_extsavedata.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/archive_extsavedata.h" | ||
| 11 | #include "core/file_sys/disk_archive.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | static std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) { | ||
| 20 | std::vector<u8> vec_data = path.AsBinary(); | ||
| 21 | const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||
| 22 | u32 media_type = data[0]; | ||
| 23 | u32 save_low = data[1]; | ||
| 24 | u32 save_high = data[2]; | ||
| 25 | return Common::StringFromFormat("%s%s/%08X/%08X/", mount_point.c_str(), media_type == 0 ? "nand" : "sdmc", save_high, save_low); | ||
| 26 | } | ||
| 27 | |||
| 28 | Archive_ExtSaveData::Archive_ExtSaveData(const std::string& mount_point) | ||
| 29 | : DiskArchive(mount_point), concrete_mount_point(mount_point) { | ||
| 30 | LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", this->mount_point.c_str()); | ||
| 31 | } | ||
| 32 | |||
| 33 | bool Archive_ExtSaveData::Initialize() { | ||
| 34 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 35 | LOG_ERROR(Service_FS, "Unable to create ExtSaveData base path."); | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | |||
| 39 | return true; | ||
| 40 | } | ||
| 41 | |||
| 42 | ResultCode Archive_ExtSaveData::Open(const Path& path) { | ||
| 43 | std::string fullpath = GetExtSaveDataPath(mount_point, path); | ||
| 44 | if (!FileUtil::Exists(fullpath)) { | ||
| 45 | // TODO(Subv): Check error code, this one is probably wrong | ||
| 46 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 47 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 48 | } | ||
| 49 | concrete_mount_point = fullpath; | ||
| 50 | return RESULT_SUCCESS; | ||
| 51 | } | ||
| 52 | |||
| 53 | ResultCode Archive_ExtSaveData::Format(const Path& path) const { | ||
| 54 | std::string fullpath = GetExtSaveDataPath(mount_point, path); | ||
| 55 | FileUtil::CreateFullPath(fullpath); | ||
| 56 | return RESULT_SUCCESS; | ||
| 57 | } | ||
| 58 | |||
| 59 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h new file mode 100644 index 000000000..a3a144799 --- /dev/null +++ b/src/core/file_sys/archive_extsavedata.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/disk_archive.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the ExtSaveData archive | ||
| 18 | class Archive_ExtSaveData final : public DiskArchive { | ||
| 19 | public: | ||
| 20 | Archive_ExtSaveData(const std::string& mount_point); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return true if it initialized successfully | ||
| 25 | */ | ||
| 26 | bool Initialize(); | ||
| 27 | |||
| 28 | ResultCode Open(const Path& path) override; | ||
| 29 | ResultCode Format(const Path& path) const override; | ||
| 30 | std::string GetName() const override { return "ExtSaveData"; } | ||
| 31 | |||
| 32 | const std::string& GetMountPoint() const override { | ||
| 33 | return concrete_mount_point; | ||
| 34 | } | ||
| 35 | |||
| 36 | protected: | ||
| 37 | /** | ||
| 38 | * This holds the full directory path for this archive, it is only set after a successful call to Open, | ||
| 39 | * this is formed as <base extsavedatapath>/<type>/<high>/<low>. | ||
| 40 | * See GetExtSaveDataPath for the code that extracts this data from an archive path. | ||
| 41 | */ | ||
| 42 | std::string concrete_mount_point; | ||
| 43 | }; | ||
| 44 | |||
| 45 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index fdaf73179..2fc3831b7 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -62,4 +62,9 @@ std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) | |||
| 62 | return Common::make_unique<Directory_RomFS>(); | 62 | return Common::make_unique<Directory_RomFS>(); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | ResultCode Archive_RomFS::Format(const Path& path) const { | ||
| 66 | LOG_WARNING(Service_FS, "Attempted to format ROMFS."); | ||
| 67 | return UnimplementedFunction(ErrorModule::FS); | ||
| 68 | } | ||
| 69 | |||
| 65 | } // namespace FileSys | 70 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 5e918f92d..d4b1eb7f2 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -83,6 +83,12 @@ public: | |||
| 83 | */ | 83 | */ |
| 84 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 84 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 85 | 85 | ||
| 86 | ResultCode Open(const Path& path) override { | ||
| 87 | return RESULT_SUCCESS; | ||
| 88 | } | ||
| 89 | |||
| 90 | ResultCode Format(const Path& path) const override; | ||
| 91 | |||
| 86 | private: | 92 | private: |
| 87 | friend class File_RomFS; | 93 | friend class File_RomFS; |
| 88 | 94 | ||
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 97853567c..280d4ff5d 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp | |||
| @@ -16,18 +16,29 @@ | |||
| 16 | 16 | ||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| 18 | 18 | ||
| 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id) | 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point) |
| 20 | : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) { | 20 | : DiskArchive(mount_point) { |
| 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); | 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | bool Archive_SaveData::Initialize() { | 24 | ResultCode Archive_SaveData::Open(const Path& path) { |
| 25 | if (!FileUtil::CreateFullPath(mount_point)) { | 25 | if (concrete_mount_point.empty()) |
| 26 | LOG_ERROR(Service_FS, "Unable to create SaveData path."); | 26 | concrete_mount_point = Common::StringFromFormat("%s%016X", mount_point.c_str(), Kernel::g_program_id) + DIR_SEP; |
| 27 | return false; | 27 | if (!FileUtil::Exists(concrete_mount_point)) { |
| 28 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 29 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 30 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 31 | // with the files and folders that it expects. | ||
| 32 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 33 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 28 | } | 34 | } |
| 35 | return RESULT_SUCCESS; | ||
| 36 | } | ||
| 29 | 37 | ||
| 30 | return true; | 38 | ResultCode Archive_SaveData::Format(const Path& path) const { |
| 39 | FileUtil::DeleteDirRecursively(concrete_mount_point); | ||
| 40 | FileUtil::CreateFullPath(concrete_mount_point); | ||
| 41 | return RESULT_SUCCESS; | ||
| 31 | } | 42 | } |
| 32 | 43 | ||
| 33 | } // namespace FileSys | 44 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h index 5b0ce29e6..07c7f7eff 100644 --- a/src/core/file_sys/archive_savedata.h +++ b/src/core/file_sys/archive_savedata.h | |||
| @@ -17,15 +17,20 @@ namespace FileSys { | |||
| 17 | /// File system interface to the SaveData archive | 17 | /// File system interface to the SaveData archive |
| 18 | class Archive_SaveData final : public DiskArchive { | 18 | class Archive_SaveData final : public DiskArchive { |
| 19 | public: | 19 | public: |
| 20 | Archive_SaveData(const std::string& mount_point, u64 program_id); | 20 | Archive_SaveData(const std::string& mount_point); |
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return true if it initialized successfully | ||
| 25 | */ | ||
| 26 | bool Initialize(); | ||
| 27 | 21 | ||
| 28 | std::string GetName() const override { return "SaveData"; } | 22 | std::string GetName() const override { return "SaveData"; } |
| 23 | |||
| 24 | ResultCode Open(const Path& path) override; | ||
| 25 | |||
| 26 | ResultCode Format(const Path& path) const override; | ||
| 27 | |||
| 28 | const std::string& GetMountPoint() const override { | ||
| 29 | return concrete_mount_point; | ||
| 30 | } | ||
| 31 | |||
| 32 | protected: | ||
| 33 | std::string concrete_mount_point; | ||
| 29 | }; | 34 | }; |
| 30 | 35 | ||
| 31 | } // namespace FileSys | 36 | } // namespace FileSys |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index 018ebd2ed..f18d96f5a 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -25,6 +25,7 @@ public: | |||
| 25 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} | 25 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} |
| 26 | 26 | ||
| 27 | virtual std::string GetName() const = 0; | 27 | virtual std::string GetName() const = 0; |
| 28 | virtual ResultCode Format(const Path& path) const { return RESULT_SUCCESS; } | ||
| 28 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | 29 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; |
| 29 | bool DeleteFile(const Path& path) const override; | 30 | bool DeleteFile(const Path& path) const override; |
| 30 | bool RenameFile(const Path& src_path, const Path& dest_path) const override; | 31 | bool RenameFile(const Path& src_path, const Path& dest_path) const override; |
| @@ -34,11 +35,15 @@ public: | |||
| 34 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 35 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 35 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 36 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 36 | 37 | ||
| 38 | virtual ResultCode Open(const Path& path) override { | ||
| 39 | return RESULT_SUCCESS; | ||
| 40 | } | ||
| 41 | |||
| 37 | /** | 42 | /** |
| 38 | * Getter for the path used for this Archive | 43 | * Getter for the path used for this Archive |
| 39 | * @return Mount point of that passthrough archive | 44 | * @return Mount point of that passthrough archive |
| 40 | */ | 45 | */ |
| 41 | const std::string& GetMountPoint() const { | 46 | virtual const std::string& GetMountPoint() const { |
| 42 | return mount_point; | 47 | return mount_point; |
| 43 | } | 48 | } |
| 44 | 49 | ||
diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp index dcf5ec4fe..4b0f761d9 100644 --- a/src/core/hle/service/apt_a.cpp +++ b/src/core/hle/service/apt_a.cpp | |||
| @@ -6,22 +6,31 @@ | |||
| 6 | #include "core/hle/hle.h" | 6 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/service/apt_a.h" | 7 | #include "core/hle/service/apt_a.h" |
| 8 | 8 | ||
| 9 | namespace APT_U { | ||
| 10 | extern void Initialize(Service::Interface* self); | ||
| 11 | extern void GetLockHandle(Service::Interface* self); | ||
| 12 | extern void ReceiveParameter(Service::Interface* self); | ||
| 13 | extern void GlanceParameter(Service::Interface* self); | ||
| 14 | } | ||
| 15 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // Namespace APT_A | 17 | // Namespace APT_A |
| 11 | 18 | ||
| 12 | namespace APT_A { | 19 | namespace APT_A { |
| 13 | 20 | ||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | 21 | const Interface::FunctionInfo FunctionTable[] = { |
| 15 | {0x00010040, nullptr, "GetLockHandle?"}, | 22 | {0x00010040, APT_U::GetLockHandle, "GetLockHandle?"}, |
| 16 | {0x00020080, nullptr, "Initialize?"}, | 23 | {0x00020080, APT_U::Initialize, "Initialize?"}, |
| 17 | {0x00030040, nullptr, "Enable?"}, | 24 | {0x00030040, nullptr, "Enable?"}, |
| 18 | {0x00040040, nullptr, "Finalize?"}, | 25 | {0x00040040, nullptr, "Finalize?"}, |
| 19 | {0x00050040, nullptr, "GetAppletManInfo?"}, | 26 | {0x00050040, nullptr, "GetAppletManInfo?"}, |
| 20 | {0x00060040, nullptr, "GetAppletInfo?"}, | 27 | {0x00060040, nullptr, "GetAppletInfo?"}, |
| 21 | {0x003B0040, nullptr, "CancelLibraryApplet?"}, | 28 | {0x003B0040, nullptr, "CancelLibraryApplet?"}, |
| 22 | {0x00430040, nullptr, "NotifyToWait?"}, | 29 | {0x00430040, nullptr, "NotifyToWait?"}, |
| 23 | {0x004B00C2, nullptr, "AppletUtility?"}, | 30 | {0x004B00C2, nullptr, "AppletUtility?"}, |
| 24 | {0x00550040, nullptr, "WriteInputToNsState?"}, | 31 | {0x00550040, nullptr, "WriteInputToNsState?"}, |
| 32 | {0x000D0080, APT_U::ReceiveParameter, "ReceiveParameter" }, | ||
| 33 | {0x000E0080, APT_U::GlanceParameter, "GlanceParameter" }, | ||
| 25 | }; | 34 | }; |
| 26 | 35 | ||
| 27 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 36 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 487bf3aa7..f19ca3a9f 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 12 | 12 | ||
| 13 | #include "core/file_sys/archive_savedata.h" | 13 | #include "core/file_sys/archive_savedata.h" |
| 14 | #include "core/file_sys/archive_extsavedata.h" | ||
| 14 | #include "core/file_sys/archive_backend.h" | 15 | #include "core/file_sys/archive_backend.h" |
| 15 | #include "core/file_sys/archive_sdmc.h" | 16 | #include "core/file_sys/archive_sdmc.h" |
| 16 | #include "core/file_sys/directory_backend.h" | 17 | #include "core/file_sys/directory_backend.h" |
| @@ -224,25 +225,20 @@ static Archive* GetArchive(ArchiveHandle handle) { | |||
| 224 | return (itr == handle_map.end()) ? nullptr : itr->second; | 225 | return (itr == handle_map.end()) ? nullptr : itr->second; |
| 225 | } | 226 | } |
| 226 | 227 | ||
| 227 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | 228 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { |
| 228 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); | 229 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); |
| 229 | 230 | ||
| 230 | auto itr = id_code_map.find(id_code); | 231 | auto itr = id_code_map.find(id_code); |
| 231 | if (itr == id_code_map.end()) { | 232 | if (itr == id_code_map.end()) { |
| 232 | if (id_code == ArchiveIdCode::SaveData) { | ||
| 233 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 234 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 235 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 236 | // with the files and folders that it expects. | ||
| 237 | // The FormatSaveData service call will create the SaveData archive when it is called. | ||
| 238 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 239 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 240 | } | ||
| 241 | // TODO: Verify error against hardware | 233 | // TODO: Verify error against hardware |
| 242 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 234 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 243 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 235 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 244 | } | 236 | } |
| 245 | 237 | ||
| 238 | ResultCode res = itr->second->backend->Open(archive_path); | ||
| 239 | if (!res.IsSuccess()) | ||
| 240 | return res; | ||
| 241 | |||
| 246 | // This should never even happen in the first place with 64-bit handles, | 242 | // This should never even happen in the first place with 64-bit handles, |
| 247 | while (handle_map.count(next_handle) != 0) { | 243 | while (handle_map.count(next_handle) != 0) { |
| 248 | ++next_handle; | 244 | ++next_handle; |
| @@ -395,25 +391,14 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||
| 395 | } | 391 | } |
| 396 | 392 | ||
| 397 | ResultCode FormatSaveData() { | 393 | ResultCode FormatSaveData() { |
| 398 | // TODO(Subv): Actually wipe the savedata folder after creating or opening it | ||
| 399 | |||
| 400 | // Do not create the archive again if it already exists | 394 | // Do not create the archive again if it already exists |
| 401 | if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end()) | 395 | auto archive_itr = id_code_map.find(ArchiveIdCode::SaveData); |
| 402 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code | 396 | if (archive_itr == id_code_map.end()) { |
| 403 | 397 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error | |
| 404 | // Create the SaveData archive | ||
| 405 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 406 | auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory, | ||
| 407 | Kernel::g_program_id); | ||
| 408 | |||
| 409 | if (savedata_archive->Initialize()) { | ||
| 410 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 411 | return RESULT_SUCCESS; | ||
| 412 | } else { | ||
| 413 | LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s", | ||
| 414 | savedata_archive->GetMountPoint().c_str()); | ||
| 415 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code | ||
| 416 | } | 398 | } |
| 399 | |||
| 400 | // Use an empty path, we do not use it when formatting the savedata | ||
| 401 | return archive_itr->second->backend->Format(FileSys::Path()); | ||
| 417 | } | 402 | } |
| 418 | 403 | ||
| 419 | /// Initialize archives | 404 | /// Initialize archives |
| @@ -430,6 +415,26 @@ void ArchiveInit() { | |||
| 430 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); | 415 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 431 | else | 416 | else |
| 432 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 417 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 418 | |||
| 419 | // Create the SaveData archive | ||
| 420 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 421 | auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory); | ||
| 422 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 423 | |||
| 424 | std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 425 | auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory); | ||
| 426 | if (extsavedata_archive->Initialize()) | ||
| 427 | CreateArchive(std::move(extsavedata_archive), ArchiveIdCode::ExtSaveData); | ||
| 428 | else | ||
| 429 | LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_directory.c_str()); | ||
| 430 | |||
| 431 | std::string sharedextsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 432 | auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sharedextsavedata_directory); | ||
| 433 | if (sharedextsavedata_archive->Initialize()) | ||
| 434 | CreateArchive(std::move(sharedextsavedata_archive), ArchiveIdCode::SharedExtSaveData); | ||
| 435 | else | ||
| 436 | LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", | ||
| 437 | sharedextsavedata_directory.c_str()); | ||
| 433 | } | 438 | } |
| 434 | 439 | ||
| 435 | /// Shutdown archives | 440 | /// Shutdown archives |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index b39bc41b6..c23b8cc46 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -29,9 +29,10 @@ typedef u64 ArchiveHandle; | |||
| 29 | /** | 29 | /** |
| 30 | * Opens an archive | 30 | * Opens an archive |
| 31 | * @param id_code IdCode of the archive to open | 31 | * @param id_code IdCode of the archive to open |
| 32 | * @param archive_path Path to the archive, used with Binary paths | ||
| 32 | * @return Handle to the opened archive | 33 | * @return Handle to the opened archive |
| 33 | */ | 34 | */ |
| 34 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code); | 35 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path); |
| 35 | 36 | ||
| 36 | /** | 37 | /** |
| 37 | * Closes an archive | 38 | * Closes an archive |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index b1a465274..7eb32146d 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -107,14 +107,7 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 107 | LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", | 107 | LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", |
| 108 | archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); | 108 | archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); |
| 109 | 109 | ||
| 110 | if (archive_path.GetType() != FileSys::Empty) { | 110 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); |
| 111 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||
| 112 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 113 | cmd_buff[3] = 0; | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id); | ||
| 118 | if (archive_handle.Failed()) { | 111 | if (archive_handle.Failed()) { |
| 119 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 112 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 120 | cmd_buff[1] = archive_handle.Code().raw; | 113 | cmd_buff[1] = archive_handle.Code().raw; |
| @@ -376,13 +369,7 @@ static void OpenArchive(Service::Interface* self) { | |||
| 376 | 369 | ||
| 377 | LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); | 370 | LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); |
| 378 | 371 | ||
| 379 | if (archive_path.GetType() != FileSys::Empty) { | 372 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path); |
| 380 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||
| 381 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | |||
| 385 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id); | ||
| 386 | cmd_buff[1] = handle.Code().raw; | 373 | cmd_buff[1] = handle.Code().raw; |
| 387 | if (handle.Succeeded()) { | 374 | if (handle.Succeeded()) { |
| 388 | cmd_buff[2] = *handle & 0xFFFFFFFF; | 375 | cmd_buff[2] = *handle & 0xFFFFFFFF; |
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp index d1498f05c..9cc700c46 100644 --- a/src/core/hle/service/ptm_u.cpp +++ b/src/core/hle/service/ptm_u.cpp | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/log.h" | 5 | #include "common/log.h" |
| 6 | #include "common/make_unique.h" | ||
| 7 | #include "core/file_sys/archive_extsavedata.h" | ||
| 6 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/service/ptm_u.h" | 9 | #include "core/hle/service/ptm_u.h" |
| 8 | 10 | ||
| @@ -11,6 +13,24 @@ | |||
| 11 | 13 | ||
| 12 | namespace PTM_U { | 14 | namespace PTM_U { |
| 13 | 15 | ||
| 16 | /** | ||
| 17 | * Represents the gamecoin file structure in the SharedExtData archive | ||
| 18 | * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) | ||
| 19 | */ | ||
| 20 | struct GameCoin { | ||
| 21 | u32 magic; ///< Magic number: 0x4F00 | ||
| 22 | u16 total_coins; ///< Total Play Coins | ||
| 23 | u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. | ||
| 24 | u32 step_count; ///< Total step count at the time a new Play Coin was obtained. | ||
| 25 | u32 last_step_count; ///< Step count for the day the last Play Coin was obtained | ||
| 26 | u16 year; | ||
| 27 | u8 month; | ||
| 28 | u8 day; | ||
| 29 | }; | ||
| 30 | static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; | ||
| 31 | static std::unique_ptr<FileSys::Archive_ExtSaveData> ptm_shared_extsavedata; | ||
| 32 | static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; | ||
| 33 | |||
| 14 | /// Charge levels used by PTM functions | 34 | /// Charge levels used by PTM functions |
| 15 | enum class ChargeLevels : u32 { | 35 | enum class ChargeLevels : u32 { |
| 16 | CriticalBattery = 1, | 36 | CriticalBattery = 1, |
| @@ -120,6 +140,33 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 120 | 140 | ||
| 121 | Interface::Interface() { | 141 | Interface::Interface() { |
| 122 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 142 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 143 | // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file | ||
| 144 | // TODO(Subv): In the future we should use the FS service to query this archive | ||
| 145 | std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 146 | ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory); | ||
| 147 | if (!ptm_shared_extsavedata->Initialize()) { | ||
| 148 | LOG_CRITICAL(Service_PTM, "Could not initialize ExtSaveData archive for the PTM:U service"); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | FileSys::Path archive_path(ptm_shared_extdata_id); | ||
| 152 | ResultCode result = ptm_shared_extsavedata->Open(archive_path); | ||
| 153 | // If the archive didn't exist, create the files inside | ||
| 154 | if (result.description == ErrorDescription::FS_NotFormatted) { | ||
| 155 | // Format the archive to clear the directories | ||
| 156 | ptm_shared_extsavedata->Format(archive_path); | ||
| 157 | // Open it again to get a valid archive now that the folder exists | ||
| 158 | ptm_shared_extsavedata->Open(archive_path); | ||
| 159 | FileSys::Path gamecoin_path("gamecoin.dat"); | ||
| 160 | FileSys::Mode open_mode = {}; | ||
| 161 | open_mode.write_flag = 1; | ||
| 162 | open_mode.create_flag = 1; | ||
| 163 | // Open the file and write the default gamecoin information | ||
| 164 | auto gamecoin = ptm_shared_extsavedata->OpenFile(gamecoin_path, open_mode); | ||
| 165 | if (gamecoin != nullptr) { | ||
| 166 | gamecoin->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); | ||
| 167 | gamecoin->Close(); | ||
| 168 | } | ||
| 169 | } | ||
| 123 | } | 170 | } |
| 124 | 171 | ||
| 125 | } // namespace | 172 | } // namespace |
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index eea6c5bf1..a14e8303e 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp | |||
| @@ -21,6 +21,7 @@ u8* g_heap = nullptr; ///< Application heap (main memory) | |||
| 21 | u8* g_heap_linear = nullptr; ///< Linear heap | 21 | u8* g_heap_linear = nullptr; ///< Linear heap |
| 22 | u8* g_vram = nullptr; ///< Video memory (VRAM) pointer | 22 | u8* g_vram = nullptr; ///< Video memory (VRAM) pointer |
| 23 | u8* g_shared_mem = nullptr; ///< Shared memory | 23 | u8* g_shared_mem = nullptr; ///< Shared memory |
| 24 | u8* g_dsp_mem = nullptr; ///< DSP memory | ||
| 24 | u8* g_kernel_mem; ///< Kernel memory | 25 | u8* g_kernel_mem; ///< Kernel memory |
| 25 | 26 | ||
| 26 | static u8* physical_bootrom = nullptr; ///< Bootrom physical memory | 27 | static u8* physical_bootrom = nullptr; ///< Bootrom physical memory |
| @@ -32,6 +33,7 @@ static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM) | |||
| 32 | static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory | 33 | static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory |
| 33 | static u8* physical_vram = nullptr; ///< Video physical memory (VRAM) | 34 | static u8* physical_vram = nullptr; ///< Video physical memory (VRAM) |
| 34 | static u8* physical_shared_mem = nullptr; ///< Physical shared memory | 35 | static u8* physical_shared_mem = nullptr; ///< Physical shared memory |
| 36 | static u8* physical_dsp_mem = nullptr; ///< Physical DSP memory | ||
| 35 | static u8* physical_kernel_mem; ///< Kernel memory | 37 | static u8* physical_kernel_mem; ///< Kernel memory |
| 36 | 38 | ||
| 37 | // We don't declare the IO region in here since its handled by other means. | 39 | // We don't declare the IO region in here since its handled by other means. |
| @@ -41,6 +43,7 @@ static MemoryView g_views[] = { | |||
| 41 | {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, | 43 | {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, |
| 42 | {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, | 44 | {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, |
| 43 | {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, | 45 | {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, |
| 46 | {&g_dsp_mem, &physical_dsp_mem, DSP_MEMORY_VADDR, DSP_MEMORY_SIZE, 0}, | ||
| 44 | {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, | 47 | {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, |
| 45 | {&g_heap_linear, &physical_heap_gsp, HEAP_LINEAR_VADDR, HEAP_LINEAR_SIZE, 0}, | 48 | {&g_heap_linear, &physical_heap_gsp, HEAP_LINEAR_VADDR, HEAP_LINEAR_SIZE, 0}, |
| 46 | }; | 49 | }; |
diff --git a/src/core/mem_map.h b/src/core/mem_map.h index a2ef9d3af..fad40ae0c 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h | |||
| @@ -134,6 +134,7 @@ extern u8* g_heap; ///< Application heap (main memory) | |||
| 134 | extern u8* g_vram; ///< Video memory (VRAM) | 134 | extern u8* g_vram; ///< Video memory (VRAM) |
| 135 | extern u8* g_shared_mem; ///< Shared memory | 135 | extern u8* g_shared_mem; ///< Shared memory |
| 136 | extern u8* g_kernel_mem; ///< Kernel memory | 136 | extern u8* g_kernel_mem; ///< Kernel memory |
| 137 | extern u8* g_dsp_mem; ///< DSP memory | ||
| 137 | extern u8* g_system_mem; ///< System memory | 138 | extern u8* g_system_mem; ///< System memory |
| 138 | extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here | 139 | extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here |
| 139 | 140 | ||
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index fdf382ed6..97ef1c5a3 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp | |||
| @@ -82,6 +82,10 @@ inline void Read(T &var, const VAddr vaddr) { | |||
| 82 | } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { | 82 | } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { |
| 83 | ConfigMem::Read<T>(var, vaddr); | 83 | ConfigMem::Read<T>(var, vaddr); |
| 84 | 84 | ||
| 85 | // DSP memory | ||
| 86 | } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) { | ||
| 87 | var = *((const T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR]); | ||
| 88 | |||
| 85 | // VRAM | 89 | // VRAM |
| 86 | } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { | 90 | } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { |
| 87 | var = *((const T*)&g_vram[vaddr - VRAM_VADDR]); | 91 | var = *((const T*)&g_vram[vaddr - VRAM_VADDR]); |
| @@ -122,8 +126,10 @@ inline void Write(const VAddr vaddr, const T data) { | |||
| 122 | } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { | 126 | } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { |
| 123 | *(T*)&g_vram[vaddr - VRAM_VADDR] = data; | 127 | *(T*)&g_vram[vaddr - VRAM_VADDR] = data; |
| 124 | 128 | ||
| 125 | //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) { | 129 | // DSP memory |
| 126 | // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); | 130 | } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) { |
| 131 | *(T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR] = data; | ||
| 132 | |||
| 127 | //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { | 133 | //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { |
| 128 | // _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); | 134 | // _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); |
| 129 | //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { | 135 | //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { |