diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 48 | ||||
| -rw-r--r-- | src/core/arm/interpreter/armemu.cpp | 203 | ||||
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 3 | ||||
| -rw-r--r-- | src/core/loader/3dsx.cpp | 4 |
10 files changed, 275 insertions, 76 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 68012bffd..84b4a38f0 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -1266,6 +1266,13 @@ typedef struct _smla_inst { | |||
| 1266 | unsigned int Rn; | 1266 | unsigned int Rn; |
| 1267 | } smla_inst; | 1267 | } smla_inst; |
| 1268 | 1268 | ||
| 1269 | typedef struct umaal_inst { | ||
| 1270 | unsigned int Rn; | ||
| 1271 | unsigned int Rm; | ||
| 1272 | unsigned int RdHi; | ||
| 1273 | unsigned int RdLo; | ||
| 1274 | } umaal_inst; | ||
| 1275 | |||
| 1269 | typedef struct _umlal_inst { | 1276 | typedef struct _umlal_inst { |
| 1270 | unsigned int S; | 1277 | unsigned int S; |
| 1271 | unsigned int Rm; | 1278 | unsigned int Rm; |
| @@ -3010,7 +3017,26 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) { UN | |||
| 3010 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); } | 3017 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); } |
| 3011 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); } | 3018 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); } |
| 3012 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); } | 3019 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); } |
| 3013 | ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UMAAL"); } | 3020 | ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) |
| 3021 | { | ||
| 3022 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst)); | ||
| 3023 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 3024 | |||
| 3025 | inst_base->cond = BITS(inst, 28, 31); | ||
| 3026 | inst_base->idx = index; | ||
| 3027 | inst_base->br = NON_BRANCH; | ||
| 3028 | inst_base->load_r15 = 0; | ||
| 3029 | |||
| 3030 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 3031 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 3032 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 3033 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 3034 | |||
| 3035 | if (CHECK_RM || CHECK_RN) | ||
| 3036 | inst_base->load_r15 = 1; | ||
| 3037 | |||
| 3038 | return inst_base; | ||
| 3039 | } | ||
| 3014 | ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) | 3040 | ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) |
| 3015 | { | 3041 | { |
| 3016 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | 3042 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); |
| @@ -6374,6 +6400,26 @@ unsigned InterpreterMainLoop(ARMul_State* state) | |||
| 6374 | UHSUB8_INST: | 6400 | UHSUB8_INST: |
| 6375 | UHSUBADDX_INST: | 6401 | UHSUBADDX_INST: |
| 6376 | UMAAL_INST: | 6402 | UMAAL_INST: |
| 6403 | { | ||
| 6404 | INC_ICOUNTER; | ||
| 6405 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 6406 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 6407 | |||
| 6408 | const u32 rm = RM; | ||
| 6409 | const u32 rn = RN; | ||
| 6410 | const u32 rd_lo = RDLO; | ||
| 6411 | const u32 rd_hi = RDHI; | ||
| 6412 | |||
| 6413 | const u64 result = (rm * rn) + rd_lo + rd_hi; | ||
| 6414 | |||
| 6415 | RDLO = (result & 0xFFFFFFFF); | ||
| 6416 | RDHI = ((result >> 32) & 0xFFFFFFFF); | ||
| 6417 | } | ||
| 6418 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6419 | INC_PC(sizeof(umaal_inst)); | ||
| 6420 | FETCH_INST; | ||
| 6421 | GOTO_NEXT_INST; | ||
| 6422 | } | ||
| 6377 | UMLAL_INST: | 6423 | UMLAL_INST: |
| 6378 | { | 6424 | { |
| 6379 | INC_ICOUNTER; | 6425 | INC_ICOUNTER; |
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 63cfd03c6..610e04f10 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp | |||
| @@ -5824,9 +5824,9 @@ L_stm_s_takeabort: | |||
| 5824 | case 0x3f: | 5824 | case 0x3f: |
| 5825 | printf ("Unhandled v6 insn: rbit\n"); | 5825 | printf ("Unhandled v6 insn: rbit\n"); |
| 5826 | break; | 5826 | break; |
| 5827 | case 0x61: // SSUB16, SADD16, SSAX, and SASX | 5827 | case 0x61: // SADD16, SASX, SSAX, and SSUB16 |
| 5828 | if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 || | 5828 | if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || |
| 5829 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30) | 5829 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) |
| 5830 | { | 5830 | { |
| 5831 | const u8 rd_idx = BITS(12, 15); | 5831 | const u8 rd_idx = BITS(12, 15); |
| 5832 | const u8 rm_idx = BITS(0, 3); | 5832 | const u8 rm_idx = BITS(0, 3); |
| @@ -5839,25 +5839,25 @@ L_stm_s_takeabort: | |||
| 5839 | s32 lo_result; | 5839 | s32 lo_result; |
| 5840 | s32 hi_result; | 5840 | s32 hi_result; |
| 5841 | 5841 | ||
| 5842 | // SSUB16 | ||
| 5843 | if ((instr & 0xFF0) == 0xf70) { | ||
| 5844 | lo_result = (rn_lo - rm_lo); | ||
| 5845 | hi_result = (rn_hi - rm_hi); | ||
| 5846 | } | ||
| 5847 | // SADD16 | 5842 | // SADD16 |
| 5848 | else if ((instr & 0xFF0) == 0xf10) { | 5843 | if ((instr & 0xFF0) == 0xf10) { |
| 5849 | lo_result = (rn_lo + rm_lo); | 5844 | lo_result = (rn_lo + rm_lo); |
| 5850 | hi_result = (rn_hi + rm_hi); | 5845 | hi_result = (rn_hi + rm_hi); |
| 5851 | } | 5846 | } |
| 5847 | // SASX | ||
| 5848 | else if ((instr & 0xFF0) == 0xf30) { | ||
| 5849 | lo_result = (rn_lo - rm_hi); | ||
| 5850 | hi_result = (rn_hi + rm_lo); | ||
| 5851 | } | ||
| 5852 | // SSAX | 5852 | // SSAX |
| 5853 | else if ((instr & 0xFF0) == 0xf50) { | 5853 | else if ((instr & 0xFF0) == 0xf50) { |
| 5854 | lo_result = (rn_lo + rm_hi); | 5854 | lo_result = (rn_lo + rm_hi); |
| 5855 | hi_result = (rn_hi - rm_lo); | 5855 | hi_result = (rn_hi - rm_lo); |
| 5856 | } | 5856 | } |
| 5857 | // SASX | 5857 | // SSUB16 |
| 5858 | else { | 5858 | else { |
| 5859 | lo_result = (rn_lo - rm_hi); | 5859 | lo_result = (rn_lo - rm_lo); |
| 5860 | hi_result = (rn_hi + rm_lo); | 5860 | hi_result = (rn_hi - rm_hi); |
| 5861 | } | 5861 | } |
| 5862 | 5862 | ||
| 5863 | state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | 5863 | state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); |
| @@ -5878,12 +5878,87 @@ L_stm_s_takeabort: | |||
| 5878 | state->Cpsr &= ~(1 << 19); | 5878 | state->Cpsr &= ~(1 << 19); |
| 5879 | } | 5879 | } |
| 5880 | return 1; | 5880 | return 1; |
| 5881 | } else { | 5881 | } |
| 5882 | printf("Unhandled v6 insn: %08x", BITS(20, 27)); | 5882 | // SADD8/SSUB8 |
| 5883 | else if ((instr & 0xFF0) == 0xf90 || (instr & 0xFF0) == 0xff0) | ||
| 5884 | { | ||
| 5885 | const u8 rd_idx = BITS(12, 15); | ||
| 5886 | const u8 rm_idx = BITS(0, 3); | ||
| 5887 | const u8 rn_idx = BITS(16, 19); | ||
| 5888 | const u32 rm_val = state->Reg[rm_idx]; | ||
| 5889 | const u32 rn_val = state->Reg[rn_idx]; | ||
| 5890 | |||
| 5891 | u8 lo_val1; | ||
| 5892 | u8 lo_val2; | ||
| 5893 | u8 hi_val1; | ||
| 5894 | u8 hi_val2; | ||
| 5895 | |||
| 5896 | // SADD8 | ||
| 5897 | if ((instr & 0xFF0) == 0xf90) { | ||
| 5898 | lo_val1 = (u8)((rn_val & 0xFF) + (rm_val & 0xFF)); | ||
| 5899 | lo_val2 = (u8)(((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF)); | ||
| 5900 | hi_val1 = (u8)(((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF)); | ||
| 5901 | hi_val2 = (u8)(((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF)); | ||
| 5902 | |||
| 5903 | if (lo_val1 & 0x80) | ||
| 5904 | state->Cpsr |= (1 << 16); | ||
| 5905 | else | ||
| 5906 | state->Cpsr &= ~(1 << 16); | ||
| 5907 | |||
| 5908 | if (lo_val2 & 0x80) | ||
| 5909 | state->Cpsr |= (1 << 17); | ||
| 5910 | else | ||
| 5911 | state->Cpsr &= ~(1 << 17); | ||
| 5912 | |||
| 5913 | if (hi_val1 & 0x80) | ||
| 5914 | state->Cpsr |= (1 << 18); | ||
| 5915 | else | ||
| 5916 | state->Cpsr &= ~(1 << 18); | ||
| 5917 | |||
| 5918 | if (hi_val2 & 0x80) | ||
| 5919 | state->Cpsr |= (1 << 19); | ||
| 5920 | else | ||
| 5921 | state->Cpsr &= ~(1 << 19); | ||
| 5922 | } | ||
| 5923 | // SSUB8 | ||
| 5924 | else { | ||
| 5925 | lo_val1 = (u8)((rn_val & 0xFF) - (rm_val & 0xFF)); | ||
| 5926 | lo_val2 = (u8)(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); | ||
| 5927 | hi_val1 = (u8)(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); | ||
| 5928 | hi_val2 = (u8)(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); | ||
| 5929 | |||
| 5930 | if (!(lo_val1 & 0x80)) | ||
| 5931 | state->Cpsr |= (1 << 16); | ||
| 5932 | else | ||
| 5933 | state->Cpsr &= ~(1 << 16); | ||
| 5934 | |||
| 5935 | if (!(lo_val2 & 0x80)) | ||
| 5936 | state->Cpsr |= (1 << 17); | ||
| 5937 | else | ||
| 5938 | state->Cpsr &= ~(1 << 17); | ||
| 5939 | |||
| 5940 | if (!(hi_val1 & 0x80)) | ||
| 5941 | state->Cpsr |= (1 << 18); | ||
| 5942 | else | ||
| 5943 | state->Cpsr &= ~(1 << 18); | ||
| 5944 | |||
| 5945 | if (!(hi_val2 & 0x80)) | ||
| 5946 | state->Cpsr |= (1 << 19); | ||
| 5947 | else | ||
| 5948 | state->Cpsr &= ~(1 << 19); | ||
| 5949 | } | ||
| 5950 | |||
| 5951 | state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24); | ||
| 5952 | return 1; | ||
| 5953 | } | ||
| 5954 | else { | ||
| 5955 | printf("Unhandled v6 insn: %08x", instr); | ||
| 5883 | } | 5956 | } |
| 5884 | break; | 5957 | break; |
| 5885 | case 0x62: // QSUB16 and QADD16 | 5958 | case 0x62: // QADD16, QASX, QSAX, and QSUB16 |
| 5886 | if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { | 5959 | if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || |
| 5960 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) | ||
| 5961 | { | ||
| 5887 | const u8 rd_idx = BITS(12, 15); | 5962 | const u8 rd_idx = BITS(12, 15); |
| 5888 | const u8 rn_idx = BITS(16, 19); | 5963 | const u8 rn_idx = BITS(16, 19); |
| 5889 | const u8 rm_idx = BITS(0, 3); | 5964 | const u8 rm_idx = BITS(0, 3); |
| @@ -5895,15 +5970,26 @@ L_stm_s_takeabort: | |||
| 5895 | s32 lo_result; | 5970 | s32 lo_result; |
| 5896 | s32 hi_result; | 5971 | s32 hi_result; |
| 5897 | 5972 | ||
| 5973 | // QADD16 | ||
| 5974 | if ((instr & 0xFF0) == 0xf10) { | ||
| 5975 | lo_result = (rn_lo + rm_lo); | ||
| 5976 | hi_result = (rn_hi + rm_hi); | ||
| 5977 | } | ||
| 5978 | // QASX | ||
| 5979 | else if ((instr & 0xFF0) == 0xf30) { | ||
| 5980 | lo_result = (rn_lo - rm_hi); | ||
| 5981 | hi_result = (rn_hi + rm_lo); | ||
| 5982 | } | ||
| 5983 | // QSAX | ||
| 5984 | else if ((instr & 0xFF0) == 0xf50) { | ||
| 5985 | lo_result = (rn_lo + rm_hi); | ||
| 5986 | hi_result = (rn_hi - rm_lo); | ||
| 5987 | } | ||
| 5898 | // QSUB16 | 5988 | // QSUB16 |
| 5899 | if ((instr & 0xFF0) == 0xf70) { | 5989 | else { |
| 5900 | lo_result = (rn_lo - rm_lo); | 5990 | lo_result = (rn_lo - rm_lo); |
| 5901 | hi_result = (rn_hi - rm_hi); | 5991 | hi_result = (rn_hi - rm_hi); |
| 5902 | } | 5992 | } |
| 5903 | else { // QADD16 | ||
| 5904 | lo_result = (rn_lo + rm_lo); | ||
| 5905 | hi_result = (rn_hi + rm_hi); | ||
| 5906 | } | ||
| 5907 | 5993 | ||
| 5908 | if (lo_result > 0x7FFF) | 5994 | if (lo_result > 0x7FFF) |
| 5909 | lo_result = 0x7FFF; | 5995 | lo_result = 0x7FFF; |
| @@ -6078,22 +6164,28 @@ L_stm_s_takeabort: | |||
| 6078 | //ichfly | 6164 | //ichfly |
| 6079 | //SSAT16 | 6165 | //SSAT16 |
| 6080 | { | 6166 | { |
| 6081 | u8 tar = BITS(12, 15); | 6167 | const u8 rd_idx = BITS(12, 15); |
| 6082 | u8 src = BITS(0, 3); | 6168 | const u8 rn_idx = BITS(0, 3); |
| 6083 | u8 val = BITS(16, 19) + 1; | 6169 | const u8 num_bits = BITS(16, 19) + 1; |
| 6084 | s16 a1 = (state->Reg[src]); | 6170 | const s16 min = -(0x8000 >> (16 - num_bits)); |
| 6085 | s16 a2 = (state->Reg[src] >> 0x10); | 6171 | const s16 max = (0x7FFF >> (16 - num_bits)); |
| 6086 | s16 min = (s16)(0x8000 >> (16 - val)); | 6172 | s16 rn_lo = (state->Reg[rn_idx]); |
| 6087 | s16 max = 0x7FFF >> (16 - val); | 6173 | s16 rn_hi = (state->Reg[rn_idx] >> 16); |
| 6088 | if (min > a1) a1 = min; | 6174 | |
| 6089 | if (max < a1) a1 = max; | 6175 | if (rn_lo > max) |
| 6090 | if (min > a2) a2 = min; | 6176 | rn_lo = max; |
| 6091 | if (max < a2) a2 = max; | 6177 | else if (rn_lo < min) |
| 6092 | u32 temp2 = ((u32)(a2)) << 0x10; | 6178 | rn_lo = min; |
| 6093 | state->Reg[tar] = (a1 & 0xFFFF) | (temp2); | 6179 | |
| 6180 | if (rn_hi > max) | ||
| 6181 | rn_hi = max; | ||
| 6182 | else if (rn_hi < min) | ||
| 6183 | rn_hi = min; | ||
| 6184 | |||
| 6185 | state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); | ||
| 6186 | return 1; | ||
| 6094 | } | 6187 | } |
| 6095 | 6188 | ||
| 6096 | return 1; | ||
| 6097 | default: | 6189 | default: |
| 6098 | break; | 6190 | break; |
| 6099 | } | 6191 | } |
| @@ -6314,11 +6406,14 @@ L_stm_s_takeabort: | |||
| 6314 | } | 6406 | } |
| 6315 | case 0x70: | 6407 | case 0x70: |
| 6316 | // ichfly | 6408 | // ichfly |
| 6317 | // SMUAD, SMUSD, SMLAD | 6409 | // SMUAD, SMUSD, SMLAD, and SMLSD |
| 6318 | if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || (instr & 0xd0) == 0x10) { | 6410 | if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || |
| 6411 | (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50) | ||
| 6412 | { | ||
| 6319 | const u8 rd_idx = BITS(16, 19); | 6413 | const u8 rd_idx = BITS(16, 19); |
| 6320 | const u8 rn_idx = BITS(0, 3); | 6414 | const u8 rn_idx = BITS(0, 3); |
| 6321 | const u8 rm_idx = BITS(8, 11); | 6415 | const u8 rm_idx = BITS(8, 11); |
| 6416 | const u8 ra_idx = BITS(12, 15); | ||
| 6322 | const bool do_swap = (BIT(5) == 1); | 6417 | const bool do_swap = (BIT(5) == 1); |
| 6323 | 6418 | ||
| 6324 | u32 rm_val = state->Reg[rm_idx]; | 6419 | u32 rm_val = state->Reg[rm_idx]; |
| @@ -6341,13 +6436,14 @@ L_stm_s_takeabort: | |||
| 6341 | state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); | 6436 | state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); |
| 6342 | } | 6437 | } |
| 6343 | // SMLAD | 6438 | // SMLAD |
| 6344 | else { | 6439 | else if ((instr & 0xd0) == 0x10) { |
| 6345 | const u8 ra_idx = BITS(12, 15); | ||
| 6346 | state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; | 6440 | state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; |
| 6347 | } | 6441 | } |
| 6442 | // SMLSD | ||
| 6443 | else { | ||
| 6444 | state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx]; | ||
| 6445 | } | ||
| 6348 | return 1; | 6446 | return 1; |
| 6349 | } else { | ||
| 6350 | printf ("Unhandled v6 insn: smlsd\n"); | ||
| 6351 | } | 6447 | } |
| 6352 | break; | 6448 | break; |
| 6353 | case 0x74: | 6449 | case 0x74: |
| @@ -6357,7 +6453,30 @@ L_stm_s_takeabort: | |||
| 6357 | printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); | 6453 | printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); |
| 6358 | break; | 6454 | break; |
| 6359 | case 0x78: | 6455 | case 0x78: |
| 6360 | printf ("Unhandled v6 insn: usad/usada8\n"); | 6456 | if (BITS(20, 24) == 0x18) |
| 6457 | { | ||
| 6458 | const u8 rm_idx = BITS(8, 11); | ||
| 6459 | const u8 rn_idx = BITS(0, 3); | ||
| 6460 | const u8 rd_idx = BITS(16, 19); | ||
| 6461 | |||
| 6462 | const u32 rm_val = state->Reg[rm_idx]; | ||
| 6463 | const u32 rn_val = state->Reg[rn_idx]; | ||
| 6464 | |||
| 6465 | const u8 diff1 = (u8)std::labs((rn_val & 0xFF) - (rm_val & 0xFF)); | ||
| 6466 | const u8 diff2 = (u8)std::labs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); | ||
| 6467 | const u8 diff3 = (u8)std::labs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); | ||
| 6468 | const u8 diff4 = (u8)std::labs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); | ||
| 6469 | |||
| 6470 | u32 finalDif = (diff1 + diff2 + diff3 + diff4); | ||
| 6471 | |||
| 6472 | // Op is USADA8 if true. | ||
| 6473 | const u8 ra_idx = BITS(12, 15); | ||
| 6474 | if (ra_idx != 15) | ||
| 6475 | finalDif += state->Reg[ra_idx]; | ||
| 6476 | |||
| 6477 | state->Reg[rd_idx] = finalDif; | ||
| 6478 | return 1; | ||
| 6479 | } | ||
| 6361 | break; | 6480 | break; |
| 6362 | case 0x7a: | 6481 | case 0x7a: |
| 6363 | printf ("Unhandled v6 insn: usbfx\n"); | 6482 | printf ("Unhandled v6 insn: usbfx\n"); |
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 1b510b695..43583d206 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -143,7 +143,16 @@ public: | |||
| 143 | case Char: | 143 | case Char: |
| 144 | return std::vector<u8>(string.begin(), string.end()); | 144 | return std::vector<u8>(string.begin(), string.end()); |
| 145 | case Wchar: | 145 | case Wchar: |
| 146 | return std::vector<u8>(u16str.begin(), u16str.end()); | 146 | { |
| 147 | // use two u8 for each character of u16str | ||
| 148 | std::vector<u8> to_return(u16str.size() * 2); | ||
| 149 | for (size_t i = 0; i < u16str.size(); ++i) { | ||
| 150 | u16 tmp_char = u16str.at(i); | ||
| 151 | to_return[i*2] = (tmp_char & 0xFF00) >> 8; | ||
| 152 | to_return[i*2 + 1] = (tmp_char & 0x00FF); | ||
| 153 | } | ||
| 154 | return to_return; | ||
| 155 | } | ||
| 147 | case Empty: | 156 | case Empty: |
| 148 | return {}; | 157 | return {}; |
| 149 | default: | 158 | default: |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7123485be..683fffeee 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -14,6 +14,10 @@ typedef s32 Result; | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | // From kernel.h. Declarations duplicated here to avoid a circular header dependency. | ||
| 18 | class Thread; | ||
| 19 | Thread* GetCurrentThread(); | ||
| 20 | |||
| 17 | enum KernelHandle { | 21 | enum KernelHandle { |
| 18 | CurrentThread = 0xFFFF8000, | 22 | CurrentThread = 0xFFFF8000, |
| 19 | CurrentProcess = 0xFFFF8001, | 23 | CurrentProcess = 0xFFFF8001, |
| @@ -81,6 +85,10 @@ public: | |||
| 81 | 85 | ||
| 82 | template <class T> | 86 | template <class T> |
| 83 | T* Get(Handle handle) { | 87 | T* Get(Handle handle) { |
| 88 | if (handle == CurrentThread) { | ||
| 89 | return reinterpret_cast<T*>(GetCurrentThread()); | ||
| 90 | } | ||
| 91 | |||
| 84 | if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { | 92 | if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { |
| 85 | if (handle != 0) { | 93 | if (handle != 0) { |
| 86 | LOG_ERROR(Kernel, "Bad object handle %08x", handle); | 94 | LOG_ERROR(Kernel, "Bad object handle %08x", handle); |
| @@ -99,6 +107,10 @@ public: | |||
| 99 | // ONLY use this when you know the handle is valid. | 107 | // ONLY use this when you know the handle is valid. |
| 100 | template <class T> | 108 | template <class T> |
| 101 | T *GetFast(Handle handle) { | 109 | T *GetFast(Handle handle) { |
| 110 | if (handle == CurrentThread) { | ||
| 111 | return reinterpret_cast<T*>(GetCurrentThread()); | ||
| 112 | } | ||
| 113 | |||
| 102 | const Handle realHandle = handle - HANDLE_OFFSET; | 114 | const Handle realHandle = handle - HANDLE_OFFSET; |
| 103 | _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); | 115 | _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); |
| 104 | return static_cast<T*>(pool[realHandle]); | 116 | return static_cast<T*>(pool[realHandle]); |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6f56da8a9..f955d1957 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -20,8 +20,8 @@ public: | |||
| 20 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; } | 20 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; } |
| 21 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; } | 21 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; } |
| 22 | 22 | ||
| 23 | u32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have |
| 24 | u32 available_count; ///< Number of free slots left in the semaphore | 24 | s32 available_count; ///< Number of free slots left in the semaphore |
| 25 | std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore | 25 | std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore |
| 26 | std::string name; ///< Name of semaphore (optional) | 26 | std::string name; ///< Name of semaphore (optional) |
| 27 | 27 | ||
| @@ -49,8 +49,8 @@ public: | |||
| 49 | 49 | ||
| 50 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 50 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 51 | 51 | ||
| 52 | ResultCode CreateSemaphore(Handle* handle, u32 initial_count, | 52 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, |
| 53 | u32 max_count, const std::string& name) { | 53 | s32 max_count, const std::string& name) { |
| 54 | 54 | ||
| 55 | if (initial_count > max_count) | 55 | if (initial_count > max_count) |
| 56 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 56 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index f0075fdb8..ad474b875 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h | |||
| @@ -18,7 +18,7 @@ namespace Kernel { | |||
| 18 | * @param name Optional name of semaphore | 18 | * @param name Optional name of semaphore |
| 19 | * @return ResultCode of the error | 19 | * @return ResultCode of the error |
| 20 | */ | 20 | */ |
| 21 | ResultCode CreateSemaphore(Handle* handle, u32 initial_count, u32 max_count, const std::string& name = "Unknown"); | 21 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | * Releases a certain number of slots from a semaphore. | 24 | * Releases a certain number of slots from a semaphore. |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1c04701de..834308926 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -83,8 +83,7 @@ static Thread* current_thread; | |||
| 83 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup | 83 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup |
| 84 | static u32 next_thread_id; ///< The next available thread id | 84 | static u32 next_thread_id; ///< The next available thread id |
| 85 | 85 | ||
| 86 | /// Gets the current thread | 86 | Thread* GetCurrentThread() { |
| 87 | inline Thread* GetCurrentThread() { | ||
| 88 | return current_thread; | 87 | return current_thread; |
| 89 | } | 88 | } |
| 90 | 89 | ||
| @@ -148,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) { | |||
| 148 | } | 147 | } |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | /// Verify that a thread has not been released from waiting | 150 | /// Check if a thread is blocking on a specified wait type |
| 152 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | 151 | static bool CheckWaitType(const Thread* thread, WaitType type) { |
| 153 | _dbg_assert_(Kernel, thread != nullptr); | 152 | return (type == thread->wait_type) && (thread->IsWaiting()); |
| 154 | return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting()); | ||
| 155 | } | 153 | } |
| 156 | 154 | ||
| 157 | /// Verify that a thread has not been released from waiting (with wait address) | 155 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 158 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | 156 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { |
| 159 | _dbg_assert_(Kernel, thread != nullptr); | 157 | return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); |
| 160 | return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address); | 158 | } |
| 159 | |||
| 160 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | ||
| 161 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | ||
| 162 | return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address); | ||
| 161 | } | 163 | } |
| 162 | 164 | ||
| 163 | /// Stops the current thread | 165 | /// Stops the current thread |
| @@ -172,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) { | |||
| 172 | thread->status = THREADSTATUS_DORMANT; | 174 | thread->status = THREADSTATUS_DORMANT; |
| 173 | for (Handle waiting_handle : thread->waiting_threads) { | 175 | for (Handle waiting_handle : thread->waiting_threads) { |
| 174 | Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); | 176 | Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); |
| 175 | if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | 177 | |
| 178 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | ||
| 176 | ResumeThreadFromWait(waiting_handle); | 179 | ResumeThreadFromWait(waiting_handle); |
| 177 | } | ||
| 178 | } | 180 | } |
| 179 | thread->waiting_threads.clear(); | 181 | thread->waiting_threads.clear(); |
| 180 | 182 | ||
| @@ -210,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||
| 210 | for (Handle handle : thread_queue) { | 212 | for (Handle handle : thread_queue) { |
| 211 | Thread* thread = g_object_pool.Get<Thread>(handle); | 213 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 212 | 214 | ||
| 213 | if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) | 215 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 214 | continue; | 216 | continue; |
| 215 | 217 | ||
| 216 | if (thread == nullptr) | 218 | if (thread == nullptr) |
| @@ -235,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) { | |||
| 235 | for (Handle handle : thread_queue) { | 237 | for (Handle handle : thread_queue) { |
| 236 | Thread* thread = g_object_pool.Get<Thread>(handle); | 238 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 237 | 239 | ||
| 238 | if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) | 240 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 239 | ResumeThreadFromWait(handle); | 241 | ResumeThreadFromWait(handle); |
| 240 | } | 242 | } |
| 241 | } | 243 | } |
| @@ -306,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) { | |||
| 306 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); | 308 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); |
| 307 | if (thread) { | 309 | if (thread) { |
| 308 | thread->status &= ~THREADSTATUS_WAIT; | 310 | thread->status &= ~THREADSTATUS_WAIT; |
| 311 | thread->wait_handle = 0; | ||
| 312 | thread->wait_type = WAITTYPE_NONE; | ||
| 309 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 313 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 310 | ChangeReadyState(thread, true); | 314 | ChangeReadyState(thread, true); |
| 311 | } | 315 | } |
| @@ -469,19 +473,27 @@ void Reschedule() { | |||
| 469 | Thread* prev = GetCurrentThread(); | 473 | Thread* prev = GetCurrentThread(); |
| 470 | Thread* next = NextThread(); | 474 | Thread* next = NextThread(); |
| 471 | HLE::g_reschedule = false; | 475 | HLE::g_reschedule = false; |
| 472 | if (next > 0) { | ||
| 473 | LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 474 | 476 | ||
| 477 | if (next != nullptr) { | ||
| 478 | LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 475 | SwitchContext(next); | 479 | SwitchContext(next); |
| 480 | } else { | ||
| 481 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | ||
| 476 | 482 | ||
| 477 | // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep | 483 | for (Handle handle : thread_queue) { |
| 478 | // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. | 484 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 479 | // This results in the current thread yielding on a VBLANK once, and then it will be | 485 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", |
| 480 | // immediately placed back in the queue for execution. | 486 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); |
| 481 | if (prev->wait_type == WAITTYPE_VBLANK) { | ||
| 482 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 483 | } | 487 | } |
| 484 | } | 488 | } |
| 489 | |||
| 490 | // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put | ||
| 491 | // to sleep. So, we'll just immediately set it to "ready" again after an attempted context | ||
| 492 | // switch has occurred. This results in the current thread yielding on a sleep once, and then it | ||
| 493 | // will immediately be placed back in the queue for execution. | ||
| 494 | |||
| 495 | if (CheckWaitType(prev, WAITTYPE_SLEEP)) | ||
| 496 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 485 | } | 497 | } |
| 486 | 498 | ||
| 487 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | 499 | ResultCode GetThreadId(u32* thread_id, Handle handle) { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index be7adface..65e8ef554 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -40,7 +40,6 @@ enum WaitType { | |||
| 40 | WAITTYPE_SEMA, | 40 | WAITTYPE_SEMA, |
| 41 | WAITTYPE_EVENT, | 41 | WAITTYPE_EVENT, |
| 42 | WAITTYPE_THREADEND, | 42 | WAITTYPE_THREADEND, |
| 43 | WAITTYPE_VBLANK, | ||
| 44 | WAITTYPE_MUTEX, | 43 | WAITTYPE_MUTEX, |
| 45 | WAITTYPE_SYNCH, | 44 | WAITTYPE_SYNCH, |
| 46 | WAITTYPE_ARB, | 45 | WAITTYPE_ARB, |
| @@ -78,6 +77,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); | |||
| 78 | /// Arbitrate all threads currently waiting... | 77 | /// Arbitrate all threads currently waiting... |
| 79 | void ArbitrateAllThreads(u32 arbiter, u32 address); | 78 | void ArbitrateAllThreads(u32 arbiter, u32 address); |
| 80 | 79 | ||
| 80 | /// Gets the current thread | ||
| 81 | Thread* GetCurrentThread(); | ||
| 82 | |||
| 81 | /// Gets the current thread handle | 83 | /// Gets the current thread handle |
| 82 | Handle GetCurrentThreadHandle(); | 84 | Handle GetCurrentThreadHandle(); |
| 83 | 85 | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 47e9bf77e..70ef7839c 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) { | |||
| 352 | static void SleepThread(s64 nanoseconds) { | 352 | static void SleepThread(s64 nanoseconds) { |
| 353 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); | 353 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); |
| 354 | 354 | ||
| 355 | // Check for next thread to schedule | 355 | // Sleep current thread and check for next thread to schedule |
| 356 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | ||
| 356 | HLE::Reschedule(__func__); | 357 | HLE::Reschedule(__func__); |
| 357 | } | 358 | } |
| 358 | 359 | ||
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 0437e5374..3d84fc5da 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -223,9 +223,7 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 223 | LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); | 223 | LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); |
| 224 | FileUtil::IOFile file(filename, "rb"); | 224 | FileUtil::IOFile file(filename, "rb"); |
| 225 | if (file.IsOpen()) { | 225 | if (file.IsOpen()) { |
| 226 | 226 | THREEDSXReader::Load3DSXFile(filename, 0x00100000); | |
| 227 | THREEDSXReader reader; | ||
| 228 | reader.Load3DSXFile(filename, 0x00100000); | ||
| 229 | Kernel::LoadExec(0x00100000); | 227 | Kernel::LoadExec(0x00100000); |
| 230 | } else { | 228 | } else { |
| 231 | return ResultStatus::Error; | 229 | return ResultStatus::Error; |