summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp48
-rw-r--r--src/core/arm/interpreter/armemu.cpp232
-rw-r--r--src/core/file_sys/archive_backend.h19
-rw-r--r--src/core/file_sys/archive_romfs.cpp11
-rw-r--r--src/core/file_sys/archive_romfs.h8
-rw-r--r--src/core/file_sys/disk_archive.cpp21
-rw-r--r--src/core/file_sys/disk_archive.h1
-rw-r--r--src/core/hle/kernel/kernel.h12
-rw-r--r--src/core/hle/kernel/semaphore.cpp8
-rw-r--r--src/core/hle/kernel/semaphore.h2
-rw-r--r--src/core/hle/kernel/thread.cpp56
-rw-r--r--src/core/hle/kernel/thread.h4
-rw-r--r--src/core/hle/service/fs/archive.cpp21
-rw-r--r--src/core/hle/service/fs/archive.h9
-rw-r--r--src/core/hle/service/fs/fs_user.cpp64
-rw-r--r--src/core/hle/service/gsp_gpu.cpp26
-rw-r--r--src/core/hle/svc.cpp3
-rw-r--r--src/core/loader/3dsx.cpp4
-rw-r--r--src/core/loader/loader.cpp6
19 files changed, 449 insertions, 106 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
1269typedef struct umaal_inst {
1270 unsigned int Rn;
1271 unsigned int Rm;
1272 unsigned int RdHi;
1273 unsigned int RdLo;
1274} umaal_inst;
1275
1269typedef struct _umlal_inst { 1276typedef 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
3010ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); } 3017ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); }
3011ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); } 3018ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); }
3012ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); } 3019ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); }
3013ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UMAAL"); } 3020ARM_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}
3014ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) 3040ARM_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 07d205755..610e04f10 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -5681,11 +5681,8 @@ L_stm_s_takeabort:
5681 /* Attempt to emulate an ARMv6 instruction. 5681 /* Attempt to emulate an ARMv6 instruction.
5682 Returns non-zero upon success. */ 5682 Returns non-zero upon success. */
5683 5683
5684 static int 5684 static int handle_v6_insn(ARMul_State* state, ARMword instr) {
5685 handle_v6_insn (ARMul_State * state, ARMword instr) { 5685 switch (BITS(20, 27)) {
5686 ARMword lhs, temp;
5687
5688 switch (BITS (20, 27)) {
5689 case 0x03: 5686 case 0x03:
5690 printf ("Unhandled v6 insn: ldr\n"); 5687 printf ("Unhandled v6 insn: ldr\n");
5691 break; 5688 break;
@@ -5719,7 +5716,7 @@ L_stm_s_takeabort:
5719 /* strex */ 5716 /* strex */
5720 u32 l = LHSReg; 5717 u32 l = LHSReg;
5721 u32 r = RHSReg; 5718 u32 r = RHSReg;
5722 lhs = LHS; 5719 u32 lhs = LHS;
5723 5720
5724 bool enter = false; 5721 bool enter = false;
5725 5722
@@ -5744,7 +5741,7 @@ L_stm_s_takeabort:
5744 case 0x19: 5741 case 0x19:
5745 /* ldrex */ 5742 /* ldrex */
5746 if (BITS(4, 7) == 0x9) { 5743 if (BITS(4, 7) == 0x9) {
5747 lhs = LHS; 5744 u32 lhs = LHS;
5748 5745
5749 state->currentexaddr = lhs; 5746 state->currentexaddr = lhs;
5750 state->currentexval = ARMul_ReadWord(state, lhs); 5747 state->currentexval = ARMul_ReadWord(state, lhs);
@@ -5763,7 +5760,7 @@ L_stm_s_takeabort:
5763 case 0x1c: 5760 case 0x1c:
5764 if (BITS(4, 7) == 0x9) { 5761 if (BITS(4, 7) == 0x9) {
5765 /* strexb */ 5762 /* strexb */
5766 lhs = LHS; 5763 u32 lhs = LHS;
5767 5764
5768 bool enter = false; 5765 bool enter = false;
5769 5766
@@ -5793,11 +5790,11 @@ L_stm_s_takeabort:
5793 case 0x1d: 5790 case 0x1d:
5794 if ((BITS(4, 7)) == 0x9) { 5791 if ((BITS(4, 7)) == 0x9) {
5795 /* ldrexb */ 5792 /* ldrexb */
5796 temp = LHS; 5793 u32 lhs = LHS;
5797 LoadByte(state, instr, temp, LUNSIGNED); 5794 LoadByte(state, instr, lhs, LUNSIGNED);
5798 5795
5799 state->currentexaddr = temp; 5796 state->currentexaddr = lhs;
5800 state->currentexval = (u32)ARMul_ReadByte(state, temp); 5797 state->currentexval = (u32)ARMul_ReadByte(state, lhs);
5801 5798
5802 //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); 5799 //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]);
5803 //printf("ldrexb\n"); 5800 //printf("ldrexb\n");
@@ -5827,9 +5824,9 @@ L_stm_s_takeabort:
5827 case 0x3f: 5824 case 0x3f:
5828 printf ("Unhandled v6 insn: rbit\n"); 5825 printf ("Unhandled v6 insn: rbit\n");
5829 break; 5826 break;
5830 case 0x61: // SSUB16, SADD16, SSAX, and SASX 5827 case 0x61: // SADD16, SASX, SSAX, and SSUB16
5831 if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 || 5828 if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 ||
5832 (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30) 5829 (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70)
5833 { 5830 {
5834 const u8 rd_idx = BITS(12, 15); 5831 const u8 rd_idx = BITS(12, 15);
5835 const u8 rm_idx = BITS(0, 3); 5832 const u8 rm_idx = BITS(0, 3);
@@ -5842,25 +5839,25 @@ L_stm_s_takeabort:
5842 s32 lo_result; 5839 s32 lo_result;
5843 s32 hi_result; 5840 s32 hi_result;
5844 5841
5845 // SSUB16
5846 if ((instr & 0xFF0) == 0xf70) {
5847 lo_result = (rn_lo - rm_lo);
5848 hi_result = (rn_hi - rm_hi);
5849 }
5850 // SADD16 5842 // SADD16
5851 else if ((instr & 0xFF0) == 0xf10) { 5843 if ((instr & 0xFF0) == 0xf10) {
5852 lo_result = (rn_lo + rm_lo); 5844 lo_result = (rn_lo + rm_lo);
5853 hi_result = (rn_hi + rm_hi); 5845 hi_result = (rn_hi + rm_hi);
5854 } 5846 }
5847 // SASX
5848 else if ((instr & 0xFF0) == 0xf30) {
5849 lo_result = (rn_lo - rm_hi);
5850 hi_result = (rn_hi + rm_lo);
5851 }
5855 // SSAX 5852 // SSAX
5856 else if ((instr & 0xFF0) == 0xf50) { 5853 else if ((instr & 0xFF0) == 0xf50) {
5857 lo_result = (rn_lo + rm_hi); 5854 lo_result = (rn_lo + rm_hi);
5858 hi_result = (rn_hi - rm_lo); 5855 hi_result = (rn_hi - rm_lo);
5859 } 5856 }
5860 // SASX 5857 // SSUB16
5861 else { 5858 else {
5862 lo_result = (rn_lo - rm_hi); 5859 lo_result = (rn_lo - rm_lo);
5863 hi_result = (rn_hi + rm_lo); 5860 hi_result = (rn_hi - rm_hi);
5864 } 5861 }
5865 5862
5866 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); 5863 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
@@ -5881,12 +5878,87 @@ L_stm_s_takeabort:
5881 state->Cpsr &= ~(1 << 19); 5878 state->Cpsr &= ~(1 << 19);
5882 } 5879 }
5883 return 1; 5880 return 1;
5884 } else { 5881 }
5885 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);
5886 } 5956 }
5887 break; 5957 break;
5888 case 0x62: // QSUB16 and QADD16 5958 case 0x62: // QADD16, QASX, QSAX, and QSUB16
5889 if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { 5959 if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 ||
5960 (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70)
5961 {
5890 const u8 rd_idx = BITS(12, 15); 5962 const u8 rd_idx = BITS(12, 15);
5891 const u8 rn_idx = BITS(16, 19); 5963 const u8 rn_idx = BITS(16, 19);
5892 const u8 rm_idx = BITS(0, 3); 5964 const u8 rm_idx = BITS(0, 3);
@@ -5898,15 +5970,26 @@ L_stm_s_takeabort:
5898 s32 lo_result; 5970 s32 lo_result;
5899 s32 hi_result; 5971 s32 hi_result;
5900 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 }
5901 // QSUB16 5988 // QSUB16
5902 if ((instr & 0xFF0) == 0xf70) { 5989 else {
5903 lo_result = (rn_lo - rm_lo); 5990 lo_result = (rn_lo - rm_lo);
5904 hi_result = (rn_hi - rm_hi); 5991 hi_result = (rn_hi - rm_hi);
5905 } 5992 }
5906 else { // QADD16
5907 lo_result = (rn_lo + rm_lo);
5908 hi_result = (rn_hi + rm_hi);
5909 }
5910 5993
5911 if (lo_result > 0x7FFF) 5994 if (lo_result > 0x7FFF)
5912 lo_result = 0x7FFF; 5995 lo_result = 0x7FFF;
@@ -6081,22 +6164,28 @@ L_stm_s_takeabort:
6081 //ichfly 6164 //ichfly
6082 //SSAT16 6165 //SSAT16
6083 { 6166 {
6084 u8 tar = BITS(12, 15); 6167 const u8 rd_idx = BITS(12, 15);
6085 u8 src = BITS(0, 3); 6168 const u8 rn_idx = BITS(0, 3);
6086 u8 val = BITS(16, 19) + 1; 6169 const u8 num_bits = BITS(16, 19) + 1;
6087 s16 a1 = (state->Reg[src]); 6170 const s16 min = -(0x8000 >> (16 - num_bits));
6088 s16 a2 = (state->Reg[src] >> 0x10); 6171 const s16 max = (0x7FFF >> (16 - num_bits));
6089 s16 min = (s16)(0x8000 >> (16 - val)); 6172 s16 rn_lo = (state->Reg[rn_idx]);
6090 s16 max = 0x7FFF >> (16 - val); 6173 s16 rn_hi = (state->Reg[rn_idx] >> 16);
6091 if (min > a1) a1 = min; 6174
6092 if (max < a1) a1 = max; 6175 if (rn_lo > max)
6093 if (min > a2) a2 = min; 6176 rn_lo = max;
6094 if (max < a2) a2 = max; 6177 else if (rn_lo < min)
6095 u32 temp2 = ((u32)(a2)) << 0x10; 6178 rn_lo = min;
6096 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;
6097 } 6187 }
6098 6188
6099 return 1;
6100 default: 6189 default:
6101 break; 6190 break;
6102 } 6191 }
@@ -6109,7 +6198,7 @@ L_stm_s_takeabort:
6109 break; 6198 break;
6110 } 6199 }
6111 6200
6112 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; 6201 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
6113 if (Rm & 0x80) 6202 if (Rm & 0x80)
6114 Rm |= 0xffffff00; 6203 Rm |= 0xffffff00;
6115 6204
@@ -6154,7 +6243,7 @@ L_stm_s_takeabort:
6154 if (ror == -1) 6243 if (ror == -1)
6155 break; 6244 break;
6156 6245
6157 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; 6246 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
6158 if (Rm & 0x8000) 6247 if (Rm & 0x8000)
6159 Rm |= 0xffff0000; 6248 Rm |= 0xffff0000;
6160 6249
@@ -6250,7 +6339,7 @@ L_stm_s_takeabort:
6250 break; 6339 break;
6251 } 6340 }
6252 6341
6253 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; 6342 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
6254 6343
6255 if (BITS(16, 19) == 0xf) 6344 if (BITS(16, 19) == 0xf)
6256 /* UXTB */ 6345 /* UXTB */
@@ -6294,7 +6383,7 @@ L_stm_s_takeabort:
6294 if (ror == -1) 6383 if (ror == -1)
6295 break; 6384 break;
6296 6385
6297 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; 6386 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
6298 6387
6299 /* UXT */ 6388 /* UXT */
6300 /* state->Reg[BITS (12, 15)] = Rm; */ 6389 /* state->Reg[BITS (12, 15)] = Rm; */
@@ -6317,11 +6406,14 @@ L_stm_s_takeabort:
6317 } 6406 }
6318 case 0x70: 6407 case 0x70:
6319 // ichfly 6408 // ichfly
6320 // SMUAD, SMUSD, SMLAD 6409 // SMUAD, SMUSD, SMLAD, and SMLSD
6321 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 {
6322 const u8 rd_idx = BITS(16, 19); 6413 const u8 rd_idx = BITS(16, 19);
6323 const u8 rn_idx = BITS(0, 3); 6414 const u8 rn_idx = BITS(0, 3);
6324 const u8 rm_idx = BITS(8, 11); 6415 const u8 rm_idx = BITS(8, 11);
6416 const u8 ra_idx = BITS(12, 15);
6325 const bool do_swap = (BIT(5) == 1); 6417 const bool do_swap = (BIT(5) == 1);
6326 6418
6327 u32 rm_val = state->Reg[rm_idx]; 6419 u32 rm_val = state->Reg[rm_idx];
@@ -6344,13 +6436,14 @@ L_stm_s_takeabort:
6344 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);
6345 } 6437 }
6346 // SMLAD 6438 // SMLAD
6347 else { 6439 else if ((instr & 0xd0) == 0x10) {
6348 const u8 ra_idx = BITS(12, 15);
6349 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];
6350 } 6441 }
6442 // SMLSD
6443 else {
6444 state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx];
6445 }
6351 return 1; 6446 return 1;
6352 } else {
6353 printf ("Unhandled v6 insn: smlsd\n");
6354 } 6447 }
6355 break; 6448 break;
6356 case 0x74: 6449 case 0x74:
@@ -6360,7 +6453,30 @@ L_stm_s_takeabort:
6360 printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); 6453 printf ("Unhandled v6 insn: smmla/smmls/smmul\n");
6361 break; 6454 break;
6362 case 0x78: 6455 case 0x78:
6363 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 }
6364 break; 6480 break;
6365 case 0x7a: 6481 case 0x7a:
6366 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 065b22e5d..eb1fdaa1f 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:
@@ -200,6 +209,14 @@ public:
200 virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; 209 virtual bool DeleteDirectory(const FileSys::Path& path) const = 0;
201 210
202 /** 211 /**
212 * Create a file specified by its path
213 * @param path Path relative to the Archive
214 * @param size The size of the new file, filled with zeroes
215 * @return File creation result code
216 */
217 virtual ResultCode CreateFile(const Path& path, u32 size) const = 0;
218
219 /**
203 * Create a directory specified by its path 220 * Create a directory specified by its path
204 * @param path Path relative to the archive 221 * @param path Path relative to the archive
205 * @return Whether the directory could be created 222 * @return Whether the directory could be created
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 6ef6ea2fb..ced0794ef 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -5,6 +5,7 @@
5#include <memory> 5#include <memory>
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/make_unique.h"
8 9
9#include "core/file_sys/archive_romfs.h" 10#include "core/file_sys/archive_romfs.h"
10#include "core/file_sys/directory_romfs.h" 11#include "core/file_sys/directory_romfs.h"
@@ -29,7 +30,7 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) {
29 * @return Opened file, or nullptr 30 * @return Opened file, or nullptr
30 */ 31 */
31std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { 32std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const {
32 return std::make_unique<File_RomFS>(this); 33 return Common::make_unique<File_RomFS>(this);
33} 34}
34 35
35/** 36/**
@@ -57,6 +58,12 @@ bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const {
57 return false; 58 return false;
58} 59}
59 60
61ResultCode Archive_RomFS::CreateFile(const Path& path, u32 size) const {
62 LOG_WARNING(Service_FS, "Attempted to create a file in ROMFS.");
63 // TODO: Verify error code
64 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent);
65}
66
60/** 67/**
61 * Create a directory specified by its path 68 * Create a directory specified by its path
62 * @param path Path relative to the archive 69 * @param path Path relative to the archive
@@ -78,7 +85,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys
78 * @return Opened directory, or nullptr 85 * @return Opened directory, or nullptr
79 */ 86 */
80std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { 87std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const {
81 return std::make_unique<Directory_RomFS>(); 88 return Common::make_unique<Directory_RomFS>();
82} 89}
83 90
84} // namespace FileSys 91} // namespace FileSys
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 564c23f70..2fafd0d2a 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -54,6 +54,14 @@ public:
54 bool DeleteDirectory(const FileSys::Path& path) const override; 54 bool DeleteDirectory(const FileSys::Path& path) const override;
55 55
56 /** 56 /**
57 * Create a file specified by its path
58 * @param path Path relative to the Archive
59 * @param size The size of the new file, filled with zeroes
60 * @return File creation result code
61 */
62 ResultCode CreateFile(const Path& path, u32 size) const override;
63
64 /**
57 * Create a directory specified by its path 65 * Create a directory specified by its path
58 * @param path Path relative to the archive 66 * @param path Path relative to the archive
59 * @return Whether the directory could be created 67 * @return Whether the directory could be created
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index fc9ee4acf..1689a1a91 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -35,6 +35,27 @@ bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const {
35 return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); 35 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
36} 36}
37 37
38ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const {
39 std::string full_path = GetMountPoint() + path.AsString();
40
41 if (FileUtil::Exists(full_path))
42 return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info);
43
44 if (size == 0) {
45 FileUtil::CreateEmptyFile(full_path);
46 return RESULT_SUCCESS;
47 }
48
49 FileUtil::IOFile file(full_path, "wb");
50 // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
51 // We do this by seeking to the right size, then writing a single null byte.
52 if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1)
53 return RESULT_SUCCESS;
54
55 return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, ErrorLevel::Info);
56}
57
58
38bool DiskArchive::CreateDirectory(const Path& path) const { 59bool DiskArchive::CreateDirectory(const Path& path) const {
39 return FileUtil::CreateDir(GetMountPoint() + path.AsString()); 60 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
40} 61}
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index 73fce2fce..c1784e870 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -28,6 +28,7 @@ public:
28 bool DeleteFile(const FileSys::Path& path) const override; 28 bool DeleteFile(const FileSys::Path& path) const override;
29 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; 29 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
30 bool DeleteDirectory(const FileSys::Path& path) const override; 30 bool DeleteDirectory(const FileSys::Path& path) const override;
31 ResultCode CreateFile(const Path& path, u32 size) const override;
31 bool CreateDirectory(const Path& path) const override; 32 bool CreateDirectory(const Path& path) const override;
32 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; 33 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
33 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 34 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index dca87d93a..32258d5a0 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -14,6 +14,10 @@ typedef s32 Result;
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17// From kernel.h. Declarations duplicated here to avoid a circular header dependency.
18class Thread;
19Thread* GetCurrentThread();
20
17enum KernelHandle { 21enum 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 1572e8ab2..b81d0b26a 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
52ResultCode CreateSemaphore(Handle* handle, u32 initial_count, 52ResultCode 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 934499e7b..8644ecf0c 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 */
21ResultCode CreateSemaphore(Handle* handle, u32 initial_count, u32 max_count, const std::string& name = "Unknown"); 21ResultCode 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 a47bde9dd..c6a8dc7b9 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -83,8 +83,7 @@ static Thread* current_thread;
83static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup 83static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
84static u32 next_thread_id; ///< The next available thread id 84static u32 next_thread_id; ///< The next available thread id
85 85
86/// Gets the current thread 86Thread* GetCurrentThread() {
87inline 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
152static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { 151static 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
158static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { 156static 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
161static 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
487ResultCode GetThreadId(u32* thread_id, Handle handle) { 499ResultCode GetThreadId(u32* thread_id, Handle handle) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 34333ef6e..9396b6b26 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...
79void ArbitrateAllThreads(u32 arbiter, u32 address); 78void ArbitrateAllThreads(u32 arbiter, u32 address);
80 79
80/// Gets the current thread
81Thread* GetCurrentThread();
82
81/// Gets the current thread handle 83/// Gets the current thread handle
82Handle GetCurrentThreadHandle(); 84Handle GetCurrentThreadHandle();
83 85
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index d92444160..e2a59a069 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/make_unique.h"
10#include "common/math_util.h" 11#include "common/math_util.h"
11 12
12#include "core/file_sys/archive_savedata.h" 13#include "core/file_sys/archive_savedata.h"
@@ -260,7 +261,7 @@ ResultCode CloseArchive(ArchiveHandle handle) {
260// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in 261// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
261// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 262// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
262ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { 263ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) {
263 auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); 264 auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code));
264 265
265 bool inserted = result.second; 266 bool inserted = result.second;
266 _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); 267 _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code");
@@ -281,7 +282,7 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy
281 ErrorSummary::NotFound, ErrorLevel::Status); 282 ErrorSummary::NotFound, ErrorLevel::Status);
282 } 283 }
283 284
284 auto file = std::make_unique<File>(std::move(backend), path); 285 auto file = Common::make_unique<File>(std::move(backend), path);
285 Handle handle = Kernel::g_object_pool.Create(file.release()); 286 Handle handle = Kernel::g_object_pool.Create(file.release());
286 return MakeResult<Handle>(handle); 287 return MakeResult<Handle>(handle);
287} 288}
@@ -329,6 +330,14 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
329 ErrorSummary::Canceled, ErrorLevel::Status); 330 ErrorSummary::Canceled, ErrorLevel::Status);
330} 331}
331 332
333ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size) {
334 Archive* archive = GetArchive(archive_handle);
335 if (archive == nullptr)
336 return InvalidHandle(ErrorModule::FS);
337
338 return archive->backend->CreateFile(path, file_size);
339}
340
332ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { 341ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
333 Archive* archive = GetArchive(archive_handle); 342 Archive* archive = GetArchive(archive_handle);
334 if (archive == nullptr) 343 if (archive == nullptr)
@@ -378,7 +387,7 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F
378 ErrorSummary::NotFound, ErrorLevel::Permanent); 387 ErrorSummary::NotFound, ErrorLevel::Permanent);
379 } 388 }
380 389
381 auto directory = std::make_unique<Directory>(std::move(backend), path); 390 auto directory = Common::make_unique<Directory>(std::move(backend), path);
382 Handle handle = Kernel::g_object_pool.Create(directory.release()); 391 Handle handle = Kernel::g_object_pool.Create(directory.release());
383 return MakeResult<Handle>(handle); 392 return MakeResult<Handle>(handle);
384} 393}
@@ -392,7 +401,7 @@ ResultCode FormatSaveData() {
392 401
393 // Create the SaveData archive 402 // Create the SaveData archive
394 std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); 403 std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX);
395 auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory, 404 auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory,
396 Kernel::g_program_id); 405 Kernel::g_program_id);
397 406
398 if (savedata_archive->Initialize()) { 407 if (savedata_archive->Initialize()) {
@@ -414,14 +423,14 @@ void ArchiveInit() {
414 // archive type is SDMC, so it is the only one getting exposed. 423 // archive type is SDMC, so it is the only one getting exposed.
415 424
416 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); 425 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
417 auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); 426 auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
418 if (sdmc_archive->Initialize()) 427 if (sdmc_archive->Initialize())
419 CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); 428 CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);
420 else 429 else
421 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 430 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
422 431
423 std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX); 432 std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX);
424 auto systemsavedata_archive = std::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory); 433 auto systemsavedata_archive = Common::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory);
425 if (systemsavedata_archive->Initialize()) { 434 if (systemsavedata_archive->Initialize()) {
426 CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData); 435 CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData);
427 } else { 436 } else {
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index df04bdb6b..b39bc41b6 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -83,6 +83,15 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil
83ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); 83ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
84 84
85/** 85/**
86 * Create a File in an Archive
87 * @param archive_handle Handle to an open Archive object
88 * @param path Path to the File inside of the Archive
89 * @param file_size The size of the new file, filled with zeroes
90 * @return File creation result code
91 */
92ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size);
93
94/**
86 * Create a Directory from an Archive 95 * Create a Directory from an Archive
87 * @param archive_handle Handle to an open Archive object 96 * @param archive_handle Handle to an open Archive object
88 * @param path Path to the Directory inside of the Archive 97 * @param path Path to the Directory inside of the Archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 8d11e64b5..5e9b85cc7 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -226,6 +226,35 @@ static void DeleteDirectory(Service::Interface* self) {
226} 226}
227 227
228/* 228/*
229 * FS_User::CreateFile service function
230 * Inputs:
231 * 0 : Command header 0x08080202
232 * 2 : Archive handle lower word
233 * 3 : Archive handle upper word
234 * 4 : File path string type
235 * 5 : File path string size
236 * 7 : File size (filled with zeroes)
237 * 10: File path string data
238 * Outputs:
239 * 1 : Result of function, 0 on success, otherwise error code
240 */
241static void CreateFile(Service::Interface* self) {
242 u32* cmd_buff = Kernel::GetCommandBuffer();
243
244 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
245 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
246 u32 filename_size = cmd_buff[5];
247 u32 file_size = cmd_buff[7];
248 u32 filename_ptr = cmd_buff[10];
249
250 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
251
252 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str());
253
254 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
255}
256
257/*
229 * FS_User::CreateDirectory service function 258 * FS_User::CreateDirectory service function
230 * Inputs: 259 * Inputs:
231 * 2 : Archive handle lower word 260 * 2 : Archive handle lower word
@@ -397,16 +426,44 @@ static void IsSdmcDetected(Service::Interface* self) {
397} 426}
398 427
399/** 428/**
400 * FS_User::FormatSaveData service function 429 * FS_User::FormatSaveData service function,
430 * formats the SaveData specified by the input path.
401 * Inputs: 431 * Inputs:
432 * 0 : 0x084C0242
433 * 1 : Archive ID
434 * 2 : Archive low path type
435 * 3 : Archive low path size
436 * 10 : (LowPathSize << 14) | 2
437 * 11 : Archive low path
402 * Outputs: 438 * Outputs:
403 * 1 : Result of function, 0 on success, otherwise error code 439 * 1 : Result of function, 0 on success, otherwise error code
404 */ 440 */
405static void FormatSaveData(Service::Interface* self) { 441static void FormatSaveData(Service::Interface* self) {
442 // TODO(Subv): Find out what the other inputs and outputs of this function are
406 u32* cmd_buff = Kernel::GetCommandBuffer(); 443 u32* cmd_buff = Kernel::GetCommandBuffer();
407 LOG_DEBUG(Service_FS, "(STUBBED)"); 444 LOG_DEBUG(Service_FS, "(STUBBED)");
408 445
409 // TODO(Subv): Find out what the inputs and outputs of this function are 446 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
447 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
448 u32 archivename_size = cmd_buff[3];
449 u32 archivename_ptr = cmd_buff[11];
450 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
451
452 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
453
454 if (archive_id != FS::ArchiveIdCode::SaveData) {
455 // TODO(Subv): What should happen if somebody attempts to format a different archive?
456 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]);
457 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
458 return;
459 }
460
461 if (archive_path.GetType() != FileSys::LowPathType::Empty) {
462 // TODO(Subv): Implement formatting the SaveData of other games
463 LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
464 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
465 return;
466 }
410 467
411 cmd_buff[1] = FormatSaveData().raw; 468 cmd_buff[1] = FormatSaveData().raw;
412} 469}
@@ -414,6 +471,7 @@ static void FormatSaveData(Service::Interface* self) {
414/** 471/**
415 * FS_User::FormatThisUserSaveData service function 472 * FS_User::FormatThisUserSaveData service function
416 * Inputs: 473 * Inputs:
474 * 0: 0x080F0180
417 * Outputs: 475 * Outputs:
418 * 1 : Result of function, 0 on success, otherwise error code 476 * 1 : Result of function, 0 on success, otherwise error code
419 */ 477 */
@@ -436,7 +494,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
436 {0x08050244, RenameFile, "RenameFile"}, 494 {0x08050244, RenameFile, "RenameFile"},
437 {0x08060142, DeleteDirectory, "DeleteDirectory"}, 495 {0x08060142, DeleteDirectory, "DeleteDirectory"},
438 {0x08070142, nullptr, "DeleteDirectoryRecursively"}, 496 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
439 {0x08080202, nullptr, "CreateFile"}, 497 {0x08080202, CreateFile, "CreateFile"},
440 {0x08090182, CreateDirectory, "CreateDirectory"}, 498 {0x08090182, CreateDirectory, "CreateDirectory"},
441 {0x080A0244, RenameDirectory, "RenameDirectory"}, 499 {0x080A0244, RenameDirectory, "RenameDirectory"},
442 {0x080B0102, OpenDirectory, "OpenDirectory"}, 500 {0x080B0102, OpenDirectory, "OpenDirectory"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 10c157ba6..1f841078a 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -145,6 +145,30 @@ static void SetBufferSwap(Service::Interface* self) {
145} 145}
146 146
147/** 147/**
148 * GSP_GPU::FlushDataCache service function
149 *
150 * This Function is a no-op, We aren't emulating the CPU cache any time soon.
151 *
152 * Inputs:
153 * 1 : Address
154 * 2 : Size
155 * 3 : Value 0, some descriptor for the KProcess Handle
156 * 4 : KProcess handle
157 * Outputs:
158 * 1 : Result of function, 0 on success, otherwise error code
159 */
160static void FlushDataCache(Service::Interface* self) {
161 u32* cmd_buff = Kernel::GetCommandBuffer();
162 u32 address = cmd_buff[1];
163 u32 size = cmd_buff[2];
164 u32 process = cmd_buff[4];
165
166 // TODO(purpasmart96): Verify return header on HW
167
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169}
170
171/**
148 * GSP_GPU::RegisterInterruptRelayQueue service function 172 * GSP_GPU::RegisterInterruptRelayQueue service function
149 * Inputs: 173 * Inputs:
150 * 1 : "Flags" field, purpose is unknown 174 * 1 : "Flags" field, purpose is unknown
@@ -335,7 +359,7 @@ const Interface::FunctionInfo FunctionTable[] = {
335 {0x00050200, SetBufferSwap, "SetBufferSwap"}, 359 {0x00050200, SetBufferSwap, "SetBufferSwap"},
336 {0x00060082, nullptr, "SetCommandList"}, 360 {0x00060082, nullptr, "SetCommandList"},
337 {0x000700C2, nullptr, "RequestDma"}, 361 {0x000700C2, nullptr, "RequestDma"},
338 {0x00080082, nullptr, "FlushDataCache"}, 362 {0x00080082, FlushDataCache, "FlushDataCache"},
339 {0x00090082, nullptr, "InvalidateDataCache"}, 363 {0x00090082, nullptr, "InvalidateDataCache"},
340 {0x000A0044, nullptr, "RegisterInterruptEvents"}, 364 {0x000A0044, nullptr, "RegisterInterruptEvents"},
341 {0x000B0040, nullptr, "SetLcdForceBlack"}, 365 {0x000B0040, nullptr, "SetLcdForceBlack"},
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 4d39e7d0b..c98168e51 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) {
352static void SleepThread(s64 nanoseconds) { 352static 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 5a4f7e7d9..4d072871a 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;
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 74a29ac61..87580cb2a 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -2,7 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <string>
6
7#include "common/make_unique.h"
6 8
7#include "core/file_sys/archive_romfs.h" 9#include "core/file_sys/archive_romfs.h"
8#include "core/loader/3dsx.h" 10#include "core/loader/3dsx.h"
@@ -75,7 +77,7 @@ ResultStatus LoadFile(const std::string& filename) {
75 // Load application and RomFS 77 // Load application and RomFS
76 if (ResultStatus::Success == app_loader.Load()) { 78 if (ResultStatus::Success == app_loader.Load()) {
77 Kernel::g_program_id = app_loader.GetProgramId(); 79 Kernel::g_program_id = app_loader.GetProgramId();
78 Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); 80 Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
79 return ResultStatus::Success; 81 return ResultStatus::Success;
80 } 82 }
81 break; 83 break;