diff options
Diffstat (limited to 'src/core')
26 files changed, 1079 insertions, 874 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 88dedc153..5578fa680 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -54,7 +54,9 @@ set(SRCS              hle/service/fs/archive.cpp              hle/service/fs/fs_user.cpp              hle/service/gsp_gpu.cpp -            hle/service/hid_user.cpp +            hle/service/hid/hid.cpp +            hle/service/hid/hid_user.cpp +            hle/service/hid/hid_spvr.cpp              hle/service/http_c.cpp              hle/service/ir_rst.cpp              hle/service/ir_u.cpp @@ -153,7 +155,9 @@ set(HEADERS              hle/service/fs/archive.h              hle/service/fs/fs_user.h              hle/service/gsp_gpu.h -            hle/service/hid_user.h +            hle/service/hid/hid.h +            hle/service/hid/hid_spvr.h +            hle/service/hid/hid_user.h              hle/service/http_c.h              hle/service/ir_rst.h              hle/service/ir_u.h diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index fce8d8e4f..81427720e 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -24,37 +24,29 @@ using namespace std;  #include "core/hle/hle.h"  enum { -    COND = (1 << 0), -    NON_BRANCH = (1 << 1), -    DIRECT_BRANCH = (1 << 2), +    COND            = (1 << 0), +    NON_BRANCH      = (1 << 1), +    DIRECT_BRANCH   = (1 << 2),      INDIRECT_BRANCH = (1 << 3), -    CALL = (1 << 4), -    RET = (1 << 5), -    END_OF_PAGE = (1 << 6), -    THUMB = (1 << 7) +    CALL            = (1 << 4), +    RET             = (1 << 5), +    END_OF_PAGE     = (1 << 6), +    THUMB           = (1 << 7)  }; -#define USER_MODE_OPT    1 -#define HYBRID_MODE        0 // Enable for JIT mode - -#define THRESHOLD            1000 -#define DURATION            500 - -#define CHECK_RS     if(RS == 15) rs += 8 -#define CHECK_RM     if(RM == 15) rm += 8 -  #undef BITS +#undef BIT  #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))  #define BIT(s, n) ((s >> (n)) & 1)  #define RM    BITS(sht_oper, 0, 3)  #define RS    BITS(sht_oper, 8, 11) -#define glue(x, y)        x ## y -#define DPO(s)            glue(DataProcessingOperands, s) -#define ROTATE_RIGHT(n, i, l)    ((n << (l - i)) | (n >> i)) -#define ROTATE_LEFT(n, i, l)    ((n >> (l - i)) | (n << i)) -#define ROTATE_RIGHT_32(n, i)    ROTATE_RIGHT(n, i, 32) -#define ROTATE_LEFT_32(n, i)    ROTATE_LEFT(n, i, 32) +#define glue(x, y)            x ## y +#define DPO(s)                glue(DataProcessingOperands, s) +#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i)) +#define ROTATE_LEFT(n, i, l)  ((n >> (l - i)) | (n << i)) +#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) +#define ROTATE_LEFT_32(n, i)  ROTATE_LEFT(n, i, 32)  #define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) ) @@ -702,9 +694,6 @@ void LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsign      virt_addr = addr;  } -#define ISNEG(n)    (n < 0) -#define ISPOS(n)    (n >= 0) -  typedef struct _arm_inst {      unsigned int idx;      unsigned int cond; @@ -1324,15 +1313,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));      adc_inst *inst_cream = (adc_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1347,15 +1336,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));      add_inst *inst_cream = (add_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1370,15 +1359,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));      and_inst *inst_cream = (and_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1395,9 +1384,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));      bbl_inst *inst_cream = (bbl_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = DIRECT_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = DIRECT_BRANCH;      if (BIT(inst, 24))          inst_base->br = CALL; @@ -1414,15 +1403,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));      bic_inst *inst_cream = (bic_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1438,9 +1427,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));      blx_inst *inst_cream = (blx_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = INDIRECT_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = INDIRECT_BRANCH;      inst_cream->inst = inst;      if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { @@ -1472,17 +1461,18 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index)  ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));      cdp_inst *inst_cream = (cdp_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; + +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->CRm   = BITS(inst,  0,  3); -    inst_cream->CRd   = BITS(inst, 12, 15); -    inst_cream->CRn   = BITS(inst, 16, 19); +    inst_cream->CRm      = BITS(inst,  0,  3); +    inst_cream->CRd      = BITS(inst, 12, 15); +    inst_cream->CRn      = BITS(inst, 16, 19);      inst_cream->cp_num   = BITS(inst, 8, 11); -    inst_cream->opcode_2   = BITS(inst, 5, 7); -    inst_cream->opcode_1   = BITS(inst, 20, 23); +    inst_cream->opcode_2 = BITS(inst, 5, 7); +    inst_cream->opcode_1 = BITS(inst, 20, 23);      inst_cream->inst = inst;      LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index); @@ -1491,9 +1481,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){  ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      return inst_base;  } @@ -1502,13 +1492,13 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));      clz_inst *inst_cream = (clz_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->Rm   = BITS(inst,  0,  3); -    inst_cream->Rd   = BITS(inst, 12, 15); +    inst_cream->Rm = BITS(inst,  0,  3); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RM)           inst_base->load_r15 = 1; @@ -1519,15 +1509,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));      cmn_inst *inst_cream = (cmn_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    //inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    //inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->Rn = BITS(inst, 16, 19); +      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1539,13 +1528,13 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));      cmp_inst *inst_cream = (cmp_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->Rn     = BITS(inst, 16, 19); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->Rn = BITS(inst, 16, 19);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1557,16 +1546,16 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));      cps_inst *inst_cream = (cps_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->imod0 = BIT(inst, 18);      inst_cream->imod1 = BIT(inst, 19);      inst_cream->mmod  = BIT(inst, 17); -    inst_cream->A      = BIT(inst, 8); -    inst_cream->I      = BIT(inst, 7); -    inst_cream->F      = BIT(inst, 6); +    inst_cream->A     = BIT(inst, 8); +    inst_cream->I     = BIT(inst, 7); +    inst_cream->F     = BIT(inst, 6);      inst_cream->mode  = BITS(inst, 0, 4);      return inst_base; @@ -1576,13 +1565,13 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));      mov_inst *inst_cream = (mov_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst); @@ -1596,15 +1585,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));      eor_inst *inst_cream = (eor_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      if (CHECK_RN)           inst_base->load_r15 = 1;      inst_cream->shifter_operand = BITS(inst, 0, 11); @@ -1617,9 +1606,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)  ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      return inst_base;  } @@ -1629,8 +1618,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1645,9 +1634,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));      sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd     = BITS(inst, 12, 15); @@ -1663,9 +1652,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));      ldst_inst *inst_cream = (ldst_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->inst = inst; @@ -1682,9 +1671,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));      ldst_inst *inst_cream = (ldst_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->inst = inst; @@ -1701,9 +1690,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));      uxth_inst *inst_cream = (uxth_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd     = BITS(inst, 12, 15); @@ -1719,9 +1708,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));      uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rn     = BITS(inst, 16, 19); @@ -1739,8 +1728,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1779,8 +1768,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1819,8 +1808,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1836,8 +1825,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1853,8 +1842,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -1896,9 +1885,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));      mcr_inst *inst_cream = (mcr_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->crn      = BITS(inst, 16, 19);      inst_cream->crm      = BITS(inst,  0,  3); @@ -1915,16 +1904,16 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));      mla_inst *inst_cream = (mla_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 12, 15); -    inst_cream->Rd     = BITS(inst, 16, 19); -    inst_cream->Rs     = BITS(inst,  8, 11); -    inst_cream->Rm     = BITS(inst,  0,  3); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 12, 15); +    inst_cream->Rd = BITS(inst, 16, 19); +    inst_cream->Rs = BITS(inst,  8, 11); +    inst_cream->Rm = BITS(inst,  0,  3);      if (CHECK_RM || CHECK_RN || CHECK_RS)           inst_base->load_r15 = 1; @@ -1936,13 +1925,13 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));      mov_inst *inst_cream = (mov_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst); @@ -1955,9 +1944,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));      mrc_inst *inst_cream = (mrc_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->crn      = BITS(inst, 16, 19);      inst_cream->crm      = BITS(inst,  0,  3); @@ -1974,12 +1963,12 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));      mrs_inst *inst_cream = (mrs_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH; -    inst_cream->Rd   = BITS(inst, 12, 15); -    inst_cream->R    = BIT(inst, 22); +    inst_cream->Rd = BITS(inst, 12, 15); +    inst_cream->R  = BIT(inst, 22);      return inst_base;  } @@ -1988,9 +1977,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));      msr_inst *inst_cream = (msr_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->field_mask = BITS(inst, 16, 19);      inst_cream->R          = BIT(inst, 22); @@ -2003,15 +1992,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));      mul_inst *inst_cream = (mul_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rm     = BITS(inst, 0, 3); -    inst_cream->Rs     = BITS(inst, 8, 11); -    inst_cream->Rd     = BITS(inst, 16, 19); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rm = BITS(inst, 0, 3); +    inst_cream->Rs = BITS(inst, 8, 11); +    inst_cream->Rd = BITS(inst, 16, 19);      if (CHECK_RM || CHECK_RS)           inst_base->load_r15 = 1; @@ -2022,13 +2011,13 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));      mvn_inst *inst_cream = (mvn_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst); @@ -2043,15 +2032,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));      orr_inst *inst_cream = (orr_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rd     = BITS(inst, 12, 15); -    inst_cream->Rn     = BITS(inst, 16, 19); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rd = BITS(inst, 12, 15); +    inst_cream->Rn = BITS(inst, 16, 19);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst); @@ -2090,9 +2079,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      return inst_base; @@ -2199,15 +2188,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));      rsb_inst *inst_cream = (rsb_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst);      if (CHECK_RN)  @@ -2223,15 +2212,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));      rsc_inst *inst_cream = (rsc_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst);      if (CHECK_RN) @@ -2286,15 +2275,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));      sbc_inst *inst_cream = (sbc_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst);      if (CHECK_RN) @@ -2370,15 +2359,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));      smla_inst *inst_cream = (smla_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->x     = BIT(inst, 5); -    inst_cream->y     = BIT(inst, 6); -    inst_cream->Rm     = BITS(inst, 0, 3); -    inst_cream->Rs     = BITS(inst, 8, 11); +    inst_cream->x  = BIT(inst, 5); +    inst_cream->y  = BIT(inst, 6); +    inst_cream->Rm = BITS(inst, 0, 3); +    inst_cream->Rs = BITS(inst, 8, 11);      inst_cream->Rd = BITS(inst, 16, 19);      inst_cream->Rn = BITS(inst, 12, 15); @@ -2423,14 +2412,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));      umlal_inst *inst_cream = (umlal_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rm     = BITS(inst, 0, 3); -    inst_cream->Rs     = BITS(inst, 8, 11); +    inst_cream->S    = BIT(inst, 20); +    inst_cream->Rm   = BITS(inst, 0, 3); +    inst_cream->Rs   = BITS(inst, 8, 11);      inst_cream->RdHi = BITS(inst, 16, 19);      inst_cream->RdLo = BITS(inst, 12, 15); @@ -2537,9 +2526,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));      smul_inst *inst_cream = (smul_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd = BITS(inst, 16, 19); @@ -2559,14 +2548,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));      umull_inst *inst_cream = (umull_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rm     = BITS(inst, 0, 3); -    inst_cream->Rs     = BITS(inst, 8, 11); +    inst_cream->S    = BIT(inst, 20); +    inst_cream->Rm   = BITS(inst, 0, 3); +    inst_cream->Rs   = BITS(inst, 8, 11);      inst_cream->RdHi = BITS(inst, 16, 19);      inst_cream->RdLo = BITS(inst, 12, 15); @@ -2580,14 +2569,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));      smlad_inst *inst_cream = (smlad_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->m     = BIT(inst, 6); -    inst_cream->Rm     = BITS(inst, 8, 11); -    inst_cream->Rn     = BITS(inst, 0, 3); +    inst_cream->m  = BIT(inst, 6); +    inst_cream->Rm = BITS(inst, 8, 11); +    inst_cream->Rn = BITS(inst, 0, 3);      inst_cream->Rd = BITS(inst, 16, 19);      if (CHECK_RM || CHECK_RN)  @@ -2633,9 +2622,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index)  ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)  {      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond = BITS(inst, 28, 31); +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      return inst_base;  } @@ -2645,8 +2634,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -2657,9 +2646,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));      sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd     = BITS(inst, 12, 15); @@ -2676,8 +2665,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -2692,9 +2681,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));      uxth_inst *inst_cream = (uxth_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd     = BITS(inst, 12, 15); @@ -2710,9 +2699,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));      uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; -    inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->Rd     = BITS(inst, 12, 15); @@ -2728,8 +2717,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -2768,8 +2757,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -2812,8 +2801,8 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)      ldst_inst *inst_cream = (ldst_inst *)inst_base->component;      inst_base->cond = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->idx  = index; +    inst_base->br   = NON_BRANCH;      inst_cream->inst = inst;      inst_cream->get_addr = get_calc_addr_op(inst); @@ -2856,15 +2845,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));      sub_inst *inst_cream = (sub_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0; -    inst_cream->I     = BIT(inst, 25); -    inst_cream->S     = BIT(inst, 20); -    inst_cream->Rn     = BITS(inst, 16, 19); -    inst_cream->Rd     = BITS(inst, 12, 15); +    inst_cream->I  = BIT(inst, 25); +    inst_cream->S  = BIT(inst, 20); +    inst_cream->Rn = BITS(inst, 16, 19); +    inst_cream->Rd = BITS(inst, 12, 15);      inst_cream->shifter_operand = BITS(inst, 0, 11);      inst_cream->shtop_func = get_shtop(inst);      if (inst_cream->Rd == 15) { @@ -3125,9 +3114,9 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));      umlal_inst *inst_cream = (umlal_inst *)inst_base->component; -    inst_base->cond  = BITS(inst, 28, 31); -    inst_base->idx     = index; -    inst_base->br     = NON_BRANCH; +    inst_base->cond     = BITS(inst, 28, 31); +    inst_base->idx      = index; +    inst_base->br       = NON_BRANCH;      inst_base->load_r15 = 0;      inst_cream->S    = BIT(inst, 20); @@ -3167,10 +3156,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));      b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; -    inst_cream->imm   = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); +    inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); -    inst_base->idx    = index; -    inst_base->br     = DIRECT_BRANCH; +    inst_base->idx = index; +    inst_base->br  = DIRECT_BRANCH;      return inst_base;  } @@ -3180,10 +3169,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));      b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; -    inst_cream->imm   = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ?    0xFFFFFF00 : 0)); -    inst_cream->cond  = ((tinst >> 8) & 0xf); -    inst_base->idx    = index; -    inst_base->br     = DIRECT_BRANCH; +    inst_cream->imm  = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ?    0xFFFFFF00 : 0)); +    inst_cream->cond = ((tinst >> 8) & 0xf); +    inst_base->idx   = index; +    inst_base->br    = DIRECT_BRANCH;      return inst_base;  } @@ -3193,10 +3182,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));      bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; -    inst_cream->imm    = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); +    inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); -    inst_base->idx     = index; -    inst_base->br      = NON_BRANCH; +    inst_base->idx = index; +    inst_base->br  = NON_BRANCH;      return inst_base;  }  ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) @@ -3204,10 +3193,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)      arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));      bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; -    inst_cream->imm   = (tinst & 0x07FF) << 1; +    inst_cream->imm = (tinst & 0x07FF) << 1; -    inst_base->idx    = index; -    inst_base->br     = DIRECT_BRANCH; +    inst_base->idx = index; +    inst_base->br  = DIRECT_BRANCH;      return inst_base;  }  ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) @@ -3533,7 +3522,6 @@ void insert_bb(unsigned int addr, int start) {      CreamCache[addr] = start;  } -#define TRANS_THRESHOLD                 65000  int find_bb(unsigned int addr, int &start) {      int ret = -1;      bb_map::const_iterator it = CreamCache.find(addr); diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 11570c8b4..5a2edeb4a 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -12,6 +12,7 @@  #include "core/hle/service/service.h"  #include "core/hle/service/fs/archive.h"  #include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/hid/hid.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -70,6 +71,7 @@ void Init() {      Service::Init();      Service::FS::ArchiveInit();      Service::CFG::CFGInit(); +    Service::HID::HIDInit();      RegisterAllModules(); @@ -79,6 +81,7 @@ void Init() {  }  void Shutdown() { +    Service::HID::HIDShutdown();      Service::CFG::CFGShutdown();      Service::FS::ArchiveShutdown();      Service::Shutdown(); diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index b7434aaf2..9e855b0bf 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -30,7 +30,8 @@ public:  /// Arbitrate an address  ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { -    Object* object = Kernel::g_handle_table.GetGeneric(handle).get(); +    AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); +      if (object == nullptr)          return InvalidHandle(ErrorModule::Kernel); @@ -40,24 +41,24 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3      case ArbitrationType::Signal:          // Negative value means resume all threads          if (value < 0) { -            ArbitrateAllThreads(object, address); +            ArbitrateAllThreads(address);          } else {              // Resume first N threads              for(int i = 0; i < value; i++) -                ArbitrateHighestPriorityThread(object, address); +                ArbitrateHighestPriorityThread(address);          }          break;      // Wait current thread (acquire the arbiter)...      case ArbitrationType::WaitIfLessThan:          if ((s32)Memory::Read32(address) <= value) { -            Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); +            Kernel::WaitCurrentThread_ArbitrateAddress(address);              HLE::Reschedule(__func__);          }          break;      case ArbitrationType::WaitIfLessThanWithTimeout:          if ((s32)Memory::Read32(address) <= value) { -            Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); +            Kernel::WaitCurrentThread_ArbitrateAddress(address);              Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);              HLE::Reschedule(__func__);          } @@ -67,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3          s32 memory_value = Memory::Read32(address) - 1;          Memory::Write32(address, memory_value);          if (memory_value <= value) { -            Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); +            Kernel::WaitCurrentThread_ArbitrateAddress(address);              HLE::Reschedule(__func__);          }          break; @@ -77,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3          s32 memory_value = Memory::Read32(address) - 1;          Memory::Write32(address, memory_value);          if (memory_value <= value) { -            Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); +            Kernel::WaitCurrentThread_ArbitrateAddress(address);              Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);              HLE::Reschedule(__func__);          } diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 271190dbe..a48125965 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -14,7 +14,7 @@  namespace Kernel { -class Event : public Object { +class Event : public WaitObject {  public:      std::string GetTypeName() const override { return "Event"; }      std::string GetName() const override { return name; } @@ -25,99 +25,40 @@ public:      ResetType intitial_reset_type;          ///< ResetType specified at Event initialization      ResetType reset_type;                   ///< Current ResetType -    bool locked;                            ///< Event signal wait -    bool permanent_locked;                  ///< Hack - to set event permanent state (for easy passthrough) -    std::vector<Handle> waiting_threads;    ///< Threads that are waiting for the event +    bool signaled;                          ///< Whether the event has already been signaled      std::string name;                       ///< Name of event (optional) -    ResultVal<bool> WaitSynchronization() override { -        bool wait = locked; -        if (locked) { -            Handle thread = GetCurrentThread()->GetHandle(); -            if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { -                waiting_threads.push_back(thread); -            } -            Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); -        } -        if (reset_type != RESETTYPE_STICKY && !permanent_locked) { -            locked = true; -        } -        return MakeResult<bool>(wait); +    bool ShouldWait() override { +        return !signaled;      } -}; - -/** - * Hackish function to set an events permanent lock state, used to pass through synch blocks - * @param handle Handle to event to change - * @param permanent_locked Boolean permanent locked value to set event - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { -    Event* evt = g_handle_table.Get<Event>(handle).get(); -    if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - -    evt->permanent_locked = permanent_locked; -    return RESULT_SUCCESS; -} -/** - * Changes whether an event is locked or not - * @param handle Handle to event to change - * @param locked Boolean locked value to set event - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SetEventLocked(const Handle handle, const bool locked) { -    Event* evt = g_handle_table.Get<Event>(handle).get(); -    if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); +    void Acquire() override { +        _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); -    if (!evt->permanent_locked) { -        evt->locked = locked; +        // Release the event if it's not sticky... +        if (reset_type != RESETTYPE_STICKY) +            signaled = false;      } -    return RESULT_SUCCESS; -} +}; -/** - * Signals an event - * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code - */  ResultCode SignalEvent(const Handle handle) {      Event* evt = g_handle_table.Get<Event>(handle).get(); -    if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - -    // Resume threads waiting for event to signal -    bool event_caught = false; -    for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { -        Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]).get(); -        if (thread != nullptr) -            thread->ResumeFromWait(); - -        // If any thread is signalled awake by this event, assume the event was "caught" and reset -        // the event. This will result in the next thread waiting on the event to block. Otherwise, -        // the event will not be reset, and the next thread to call WaitSynchronization on it will -        // not block. Not sure if this is correct behavior, but it seems to work. -        event_caught = true; -    } -    evt->waiting_threads.clear(); +    if (evt == nullptr) +        return InvalidHandle(ErrorModule::Kernel); + +    evt->signaled = true; +    evt->WakeupAllWaitingThreads(); -    if (!evt->permanent_locked) { -        evt->locked = event_caught; -    }      return RESULT_SUCCESS;  } -/** - * Clears an event - * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code - */  ResultCode ClearEvent(Handle handle) {      Event* evt = g_handle_table.Get<Event>(handle).get(); -    if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); +    if (evt == nullptr) +        return InvalidHandle(ErrorModule::Kernel); + +    evt->signaled = false; -    if (!evt->permanent_locked) { -        evt->locked = true; -    }      return RESULT_SUCCESS;  } @@ -134,20 +75,13 @@ Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string      // TOOD(yuriks): Fix error reporting      handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); -    evt->locked = true; -    evt->permanent_locked = false; +    evt->signaled = false;      evt->reset_type = evt->intitial_reset_type = reset_type;      evt->name = name;      return evt;  } -/** - * Creates an event - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - * @return Handle to newly created Event object - */  Handle CreateEvent(const ResetType reset_type, const std::string& name) {      Handle handle;      Event* evt = CreateEvent(handle, reset_type, name); diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index da793df1a..c08b12ee1 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -12,28 +12,16 @@  namespace Kernel {  /** - * Changes whether an event is locked or not - * @param handle Handle to event to change - * @param locked Boolean locked value to set event - */ -ResultCode SetEventLocked(const Handle handle, const bool locked); - -/** - * Hackish function to set an events permanent lock state, used to pass through synch blocks - * @param handle Handle to event to change - * @param permanent_locked Boolean permanent locked value to set event - */ -ResultCode SetPermanentLock(Handle handle, const bool permanent_locked); - -/**   * Signals an event   * @param handle Handle to event to signal + * @return Result of operation, 0 on success, otherwise error code   */  ResultCode SignalEvent(const Handle handle);  /**   * Clears an event   * @param handle Handle to event to clear + * @return Result of operation, 0 on success, otherwise error code   */  ResultCode ClearEvent(Handle handle); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d3684896f..d7fa4dcea 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -18,6 +18,41 @@ SharedPtr<Thread> g_main_thread = nullptr;  HandleTable g_handle_table;  u64 g_program_id = 0; +void WaitObject::AddWaitingThread(Thread* thread) { +    auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); +    if (itr == waiting_threads.end()) +        waiting_threads.push_back(thread); +} + +void WaitObject::RemoveWaitingThread(Thread* thread) { +    auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); +    if (itr != waiting_threads.end()) +        waiting_threads.erase(itr); +} + +Thread* WaitObject::WakeupNextThread() { +    if (waiting_threads.empty()) +        return nullptr; + +    auto next_thread = waiting_threads.front(); +    waiting_threads.erase(waiting_threads.begin()); + +    next_thread->ReleaseWaitObject(this); + +    return next_thread; +} + +void WaitObject::WakeupAllWaitingThreads() { +    auto waiting_threads_copy = waiting_threads; + +    // We use a copy because ReleaseWaitObject will remove the thread from this object's +    // waiting_threads list +    for (auto thread : waiting_threads_copy) +        thread->ReleaseWaitObject(this); + +    _assert_msg_(Kernel, waiting_threads.empty(), "failed to awaken all waiting threads!"); +} +  HandleTable::HandleTable() {      next_generation = 1;      Clear(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5e5217b78..3828efbea 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,8 @@  #include <array>  #include <string> +#include <vector> +  #include "common/common.h"  #include "core/hle/result.h" @@ -58,17 +60,35 @@ class Object : NonCopyable {  public:      virtual ~Object() {}      Handle GetHandle() const { return handle; } +      virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }      virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }      virtual Kernel::HandleType GetHandleType() const = 0;      /** -     * Wait for kernel object to synchronize. -     * @return True if the current thread should wait as a result of the wait +     * Check if a thread can wait on the object +     * @return True if a thread can wait on the object, otherwise false       */ -    virtual ResultVal<bool> WaitSynchronization() { -        LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); -        return UnimplementedFunction(ErrorModule::Kernel); +    bool IsWaitable() const { +        switch (GetHandleType()) { +        case HandleType::Session: +        case HandleType::Event: +        case HandleType::Mutex: +        case HandleType::Thread: +        case HandleType::Semaphore: +        case HandleType::Timer: +            return true; + +        case HandleType::Unknown: +        case HandleType::Port: +        case HandleType::SharedMemory: +        case HandleType::Redirection: +        case HandleType::Process: +        case HandleType::AddressArbiter: +            return false; +        } + +        return false;      }  private: @@ -92,6 +112,44 @@ inline void intrusive_ptr_release(Object* object) {  template <typename T>  using SharedPtr = boost::intrusive_ptr<T>; +/// Class that represents a Kernel object that a thread can be waiting on +class WaitObject : public Object { +public: + +    /** +     * Check if the current thread should wait until the object is available +     * @return True if the current thread should wait due to this object being unavailable +     */ +    virtual bool ShouldWait() = 0; + +    /// Acquire/lock the object if it is available +    virtual void Acquire() = 0; + +    /** +     * Add a thread to wait on this object +     * @param thread Pointer to thread to add +     */ +    void AddWaitingThread(Thread* thread); + +    /** +     * Removes a thread from waiting on this object (e.g. if it was resumed already) +     * @param thread Pointer to thread to remove +     */ +    void RemoveWaitingThread(Thread* thead); + +    /** +     * Wake up the next thread waiting on this object +     * @return Pointer to the thread that was resumed, nullptr if no threads are waiting +     */ +    Thread* WakeupNextThread(); + +    /// Wake up all threads waiting on this object +    void WakeupAllWaitingThreads(); + +private: +    std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available +}; +  /**   * This class allows the creation of Handles, which are references to objects that can be tested   * for validity and looked up. Here they are used to pass references to kernel objects to/from the @@ -146,14 +204,14 @@ public:      /**       * Looks up a handle. -     * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid. +     * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.       */      SharedPtr<Object> GetGeneric(Handle handle) const;      /**       * Looks up a handle while verifying its type. -     * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its -     *          type differs from the handle type `T::HANDLE_TYPE`. +     * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its +     *         type differs from the handle type `T::HANDLE_TYPE`.       */      template <class T>      SharedPtr<T> Get(Handle handle) const { @@ -164,6 +222,19 @@ public:          return nullptr;      } +    /** +     * Looks up a handle while verifying that it is an object that a thread can wait on +     * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is +     *         not a waitable object. +     */ +    SharedPtr<WaitObject> GetWaitObject(Handle handle) const { +        SharedPtr<Object> object = GetGeneric(handle); +        if (object != nullptr && object->IsWaitable()) { +            return boost::static_pointer_cast<WaitObject>(std::move(object)); +        } +        return nullptr; +    } +      /// Closes all handles held in this table.      void Clear(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 853a5dd74..cd05a1397 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,7 +13,7 @@  namespace Kernel { -class Mutex : public Object { +class Mutex : public WaitObject {  public:      std::string GetTypeName() const override { return "Mutex"; }      std::string GetName() const override { return name; } @@ -23,39 +23,26 @@ public:      bool initial_locked;                        ///< Initial lock state when mutex was created      bool locked;                                ///< Current locked state -    Handle lock_thread;                         ///< Handle to thread that currently has mutex -    std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex      std::string name;                           ///< Name of mutex (optional) +    SharedPtr<Thread> holding_thread;           ///< Thread that has acquired the mutex -    ResultVal<bool> WaitSynchronization() override; +    bool ShouldWait() override; +    void Acquire() override;  };  //////////////////////////////////////////////////////////////////////////////////////////////////// -typedef std::multimap<Handle, Handle> MutexMap; +typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap;  static MutexMap g_mutex_held_locks;  /**   * Acquires the specified mutex for the specified thread   * @param mutex Mutex that is to be acquired - * @param thread Thread that will acquired + * @param thread Thread that will acquire the mutex   */ -void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { -    g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); -    mutex->lock_thread = thread; -} - -bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { -    MutexAcquireLock(mutex, thread_handle); - -    Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get(); -    if (thread == nullptr) { -        LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); -        return false; -    } - -    thread->ResumeFromWait(); -    return true; +void MutexAcquireLock(Mutex* mutex, Thread* thread) { +    g_mutex_held_locks.insert(std::make_pair(thread, mutex)); +    mutex->holding_thread = thread;  }  /** @@ -64,56 +51,41 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) {   */  void ResumeWaitingThread(Mutex* mutex) {      // Find the next waiting thread for the mutex... -    if (mutex->waiting_threads.empty()) { +    auto next_thread = mutex->WakeupNextThread(); +    if (next_thread != nullptr) { +        MutexAcquireLock(mutex, next_thread); +    } else {          // Reset mutex lock thread handle, nothing is waiting          mutex->locked = false; -        mutex->lock_thread = -1; -    } -    else { -        // Resume the next waiting thread and re-lock the mutex -        std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); -        ReleaseMutexForThread(mutex, *iter); -        mutex->waiting_threads.erase(iter); +        mutex->holding_thread = nullptr;      }  } -void MutexEraseLock(Mutex* mutex) { -    Handle handle = mutex->GetHandle(); -    auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); -    for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { -        if (iter->second == handle) { -            g_mutex_held_locks.erase(iter); -            break; -        } -    } -    mutex->lock_thread = -1; -} - -void ReleaseThreadMutexes(Handle thread) { +void ReleaseThreadMutexes(Thread* thread) {      auto locked = g_mutex_held_locks.equal_range(thread);      // Release every mutex that the thread holds, and resume execution on the waiting threads -    for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { -        Mutex* mutex = g_handle_table.Get<Mutex>(iter->second).get(); -        ResumeWaitingThread(mutex); +    for (auto iter = locked.first; iter != locked.second; ++iter) { +        ResumeWaitingThread(iter->second.get());      }      // Erase all the locks that this thread holds      g_mutex_held_locks.erase(thread);  } -bool LockMutex(Mutex* mutex) { -    // Mutex alread locked? +bool ReleaseMutex(Mutex* mutex) {      if (mutex->locked) { -        return false; -    } -    MutexAcquireLock(mutex); -    return true; -} +        auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); -bool ReleaseMutex(Mutex* mutex) { -    MutexEraseLock(mutex); -    ResumeWaitingThread(mutex); +        for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { +            if (iter->second == mutex) { +                g_mutex_held_locks.erase(iter); +                break; +            } +        } + +        ResumeWaitingThread(mutex); +    }      return true;  } @@ -148,15 +120,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name)      mutex->locked = mutex->initial_locked = initial_locked;      mutex->name = name; +    mutex->holding_thread = nullptr;      // Acquire mutex with current thread if initialized as locked... -    if (mutex->locked) { -        MutexAcquireLock(mutex); +    if (mutex->locked) +        MutexAcquireLock(mutex, GetCurrentThread()); -    // Otherwise, reset lock thread handle -    } else { -        mutex->lock_thread = -1; -    }      return mutex;  } @@ -172,17 +141,14 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {      return handle;  } -ResultVal<bool> Mutex::WaitSynchronization() { -    bool wait = locked; -    if (locked) { -        waiting_threads.push_back(GetCurrentThread()->GetHandle()); -        Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); -    } else { -        // Lock the mutex when the first thread accesses it -        locked = true; -        MutexAcquireLock(this); -    } +bool Mutex::ShouldWait() { +    return locked && holding_thread != GetCurrentThread(); +} -    return MakeResult<bool>(wait); +void Mutex::Acquire() { +    _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); +    locked = true; +    MutexAcquireLock(this, GetCurrentThread());  } +  } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index a8ca97014..bb8778c98 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -28,6 +28,6 @@ Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");   * Releases all the mutexes held by the specified thread   * @param thread Thread that is holding the mutexes   */ -void ReleaseThreadMutexes(Handle thread); +void ReleaseThreadMutexes(Thread* thread);  } // namespace diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 88ec9a104..135d8fb2a 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -12,7 +12,7 @@  namespace Kernel { -class Semaphore : public Object { +class Semaphore : public WaitObject {  public:      std::string GetTypeName() const override { return "Semaphore"; }      std::string GetName() const override { return name; } @@ -22,28 +22,15 @@ public:      s32 max_count;                              ///< Maximum number of simultaneous holders the semaphore can have      s32 available_count;                        ///< Number of free slots left in the semaphore -    std::queue<Handle> waiting_threads;         ///< Threads that are waiting for the semaphore      std::string name;                           ///< Name of semaphore (optional) -    /** -     * Tests whether a semaphore still has free slots -     * @return Whether the semaphore is available -     */ -    bool IsAvailable() const { -        return available_count > 0; +    bool ShouldWait() override { +        return available_count <= 0;      } -    ResultVal<bool> WaitSynchronization() override { -        bool wait = !IsAvailable(); - -        if (wait) { -            Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); -            waiting_threads.push(GetCurrentThread()->GetHandle()); -        } else { -            --available_count; -        } - -        return MakeResult<bool>(wait); +    void Acquire() override { +        _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); +        --available_count;      }  }; @@ -83,12 +70,8 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {      // Notify some of the threads that the semaphore has been released      // stop once the semaphore is full again or there are no more waiting threads -    while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { -        Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()).get(); -        if (thread != nullptr) -            thread->ResumeFromWait(); -        semaphore->waiting_threads.pop(); -        --semaphore->available_count; +    while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { +        semaphore->Acquire();      }      return RESULT_SUCCESS; diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 91f3ffc2c..1788e4375 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -41,7 +41,7 @@ inline static u32* GetCommandBuffer(const int offset=0) {   * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as   * opposed to HLE simulations.   */ -class Session : public Object { +class Session : public WaitObject {  public:      std::string GetTypeName() const override { return "Session"; } @@ -53,6 +53,17 @@ public:       * aren't supported yet.       */      virtual ResultVal<bool> SyncRequest() = 0; + +    // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object +    // passed into WaitSynchronization. Figure out the meaning of them. + +    bool ShouldWait() override { +        return true; +    } + +    void Acquire() override { +        _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); +    }  };  } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bc86a7c59..03b492c75 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,17 +22,12 @@  namespace Kernel { -ResultVal<bool> Thread::WaitSynchronization() { -    const bool wait = status != THREADSTATUS_DORMANT; -    if (wait) { -        Thread* thread = GetCurrentThread(); -        if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { -            waiting_threads.push_back(thread); -        } -        WaitCurrentThread(WAITTYPE_THREADEND, this); -    } +bool Thread::ShouldWait() { +    return status != THREADSTATUS_DORMANT; +} -    return MakeResult<bool>(wait); +void Thread::Acquire() { +    _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");  }  // Lists all thread ids that aren't deleted/etc. @@ -67,8 +62,8 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {      if (t->current_priority < lowest_priority) {          t->current_priority = t->initial_priority;      } -    t->wait_type = WAITTYPE_NONE; -    t->wait_object = nullptr; + +    t->wait_objects.clear();      t->wait_address = 0;  } @@ -88,37 +83,32 @@ static void ChangeReadyState(Thread* t, bool ready) {      }  } -/// Check if a thread is blocking on a specified wait type -static bool CheckWaitType(const Thread* thread, WaitType type) { -    return (type == thread->wait_type) && (thread->IsWaiting()); -} +/// Check if a thread is waiting on a the specified wait object +static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { +    auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + +    if (itr != thread->wait_objects.end()) +        return thread->IsWaiting(); -/// Check if a thread is blocking on a specified wait type with a specified handle -static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { -    return CheckWaitType(thread, type) && wait_object == thread->wait_object; +    return false;  } -/// Check if a thread is blocking on a specified wait type with a specified handle and address -static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object, VAddr wait_address) { -    return CheckWaitType(thread, type, wait_object) && (wait_address == thread->wait_address); +/// Check if the specified thread is waiting on the specified address to be arbitrated +static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { +    return thread->IsWaiting() && thread->wait_objects.empty() && wait_address == thread->wait_address;  }  /// Stops the current thread  void Thread::Stop(const char* reason) {      // Release all the mutexes that this thread holds -    ReleaseThreadMutexes(GetHandle()); +    ReleaseThreadMutexes(this);      ChangeReadyState(this, false);      status = THREADSTATUS_DORMANT; -    for (auto& waiting_thread : waiting_threads) { -        if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this)) -            waiting_thread->ResumeFromWait(); -    } -    waiting_threads.clear(); +    WakeupAllWaitingThreads();      // Stopped threads are never waiting. -    wait_type = WAITTYPE_NONE; -    wait_object = nullptr; +    wait_objects.clear();      wait_address = 0;  } @@ -129,26 +119,20 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) {      }      ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);      t->status = new_status; - -    if (new_status == THREADSTATUS_WAIT) { -        if (t->wait_type == WAITTYPE_NONE) { -            LOG_ERROR(Kernel, "Waittype none not allowed"); -        } -    }  }  /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { +Thread* ArbitrateHighestPriorityThread(u32 address) {      Thread* highest_priority_thread = nullptr;      s32 priority = THREADPRIO_LOWEST;      // Iterate through threads, find highest priority thread that is waiting to be arbitrated...      for (auto& thread : thread_list) { -        if (!CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) +        if (!CheckWait_AddressArbiter(thread.get(), address))              continue;          if (thread == nullptr) -            continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. +            continue;          if(thread->current_priority <= priority) {              highest_priority_thread = thread.get(); @@ -165,11 +149,11 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) {  }  /// Arbitrate all threads currently waiting -void ArbitrateAllThreads(Object* arbiter, u32 address) { +void ArbitrateAllThreads(u32 address) {      // Iterate through threads, find highest priority thread that is waiting to be arbitrated...      for (auto& thread : thread_list) { -        if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) +        if (CheckWait_AddressArbiter(thread.get(), address))              thread->ResumeFromWait();      }  } @@ -177,9 +161,6 @@ void ArbitrateAllThreads(Object* arbiter, u32 address) {  /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)  static void CallThread(Thread* t) {      // Stop waiting -    if (t->wait_type != WAITTYPE_NONE) { -        t->wait_type = WAITTYPE_NONE; -    }      ChangeThreadState(t, THREADSTATUS_READY);  } @@ -200,7 +181,6 @@ static void SwitchContext(Thread* t) {          current_thread = t;          ChangeReadyState(t, false);          t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; -        t->wait_type = WAITTYPE_NONE;          Core::g_app_core->LoadContext(t->context);      } else {          current_thread = nullptr; @@ -223,16 +203,27 @@ static Thread* NextThread() {      return next;  } -void WaitCurrentThread(WaitType wait_type, Object* wait_object) { +void WaitCurrentThread_Sleep() {      Thread* thread = GetCurrentThread(); -    thread->wait_type = wait_type; -    thread->wait_object = wait_object;      ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));  } -void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) { -    WaitCurrentThread(wait_type, wait_object); -    GetCurrentThread()->wait_address = wait_address; +void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all) { +    Thread* thread = GetCurrentThread(); +    thread->wait_set_output = wait_set_output; +    thread->wait_all = wait_all; + +    // It's possible to call WaitSynchronizationN without any objects passed in... +    if (wait_object != nullptr) +        thread->wait_objects.push_back(wait_object); + +    ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); +} + +void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { +    Thread* thread = GetCurrentThread(); +    thread->wait_address = wait_address; +    ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));  }  /// Event type for the thread wake up event @@ -247,6 +238,12 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {          return;      } +    thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, +        ErrorSummary::StatusChanged, ErrorLevel::Info)); + +    if (thread->wait_set_output) +        thread->SetWaitSynchronizationOutput(-1); +      thread->ResumeFromWait();  } @@ -261,14 +258,63 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) {      CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle());  } -/// Resumes a thread from waiting by marking it as "ready" +void Thread::ReleaseWaitObject(WaitObject* wait_object) { +    if (wait_objects.empty()) { +        LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); +        return; +    } + +    // Remove this thread from the waiting object's thread list +    wait_object->RemoveWaitingThread(this); + +    unsigned index = 0; +    bool wait_all_failed = false; // Will be set to true if any object is unavailable + +    // Iterate through all waiting objects to check availability... +    for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { +        if ((*itr)->ShouldWait()) +            wait_all_failed = true; + +        // The output should be the last index of wait_object +        if (*itr == wait_object) +            index = itr - wait_objects.begin(); +    } + +    // If we are waiting on all objects... +    if (wait_all) { +        // Resume the thread only if all are available... +        if (!wait_all_failed) { +            SetWaitSynchronizationResult(RESULT_SUCCESS); +            SetWaitSynchronizationOutput(-1); + +            ResumeFromWait(); +        } +    } else { +        // Otherwise, resume +        SetWaitSynchronizationResult(RESULT_SUCCESS); + +        if (wait_set_output) +            SetWaitSynchronizationOutput(index); + +        ResumeFromWait(); +    } +} +  void Thread::ResumeFromWait() {      // Cancel any outstanding wakeup events      CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle());      status &= ~THREADSTATUS_WAIT; -    wait_object = nullptr; -    wait_type = WAITTYPE_NONE; + +    // Remove this thread from all other WaitObjects +    for (auto wait_object : wait_objects) +        wait_object->RemoveWaitingThread(this); + +    wait_objects.clear(); +    wait_set_output = false; +    wait_all = false; +    wait_address = 0; +      if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {          ChangeReadyState(this, true);      } @@ -334,8 +380,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,      thread->stack_size = stack_size;      thread->initial_priority = thread->current_priority = priority;      thread->processor_id = processor_id; -    thread->wait_type = WAITTYPE_NONE; -    thread->wait_object = nullptr; +    thread->wait_set_output = false; +    thread->wait_all = false; +    thread->wait_objects.clear();      thread->wait_address = 0;      thread->name = std::move(name); @@ -419,13 +466,20 @@ void Reschedule() {          LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());          for (auto& thread : thread_list) { -            LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", -                thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, -                (thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE)); +            LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(),  +                      thread->current_priority, thread->status);          }      }  } +void Thread::SetWaitSynchronizationResult(ResultCode result) { +    context.cpu_registers[0] = result.raw; +} + +void Thread::SetWaitSynchronizationOutput(s32 output) { +    context.cpu_registers[1] = output; +} +  ////////////////////////////////////////////////////////////////////////////////////////////////////  void ThreadingInit() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 8c9f63aa5..5fab1ab58 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -38,21 +38,9 @@ enum ThreadStatus {      THREADSTATUS_WAITSUSPEND    = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND  }; -enum WaitType { -    WAITTYPE_NONE, -    WAITTYPE_SLEEP, -    WAITTYPE_SEMA, -    WAITTYPE_EVENT, -    WAITTYPE_THREADEND, -    WAITTYPE_MUTEX, -    WAITTYPE_SYNCH, -    WAITTYPE_ARB, -    WAITTYPE_TIMER, -}; -  namespace Kernel { -class Thread : public Kernel::Object { +class Thread : public WaitObject {  public:      static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,          u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); @@ -70,7 +58,8 @@ public:      inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }      inline bool IsIdle() const { return idle; } -    ResultVal<bool> WaitSynchronization() override; +    bool ShouldWait() override; +    void Acquire() override;      s32 GetPriority() const { return current_priority; }      void SetPriority(s32 priority); @@ -78,9 +67,28 @@ public:      u32 GetThreadId() const { return thread_id; }      void Stop(const char* reason); -    /// Resumes a thread from waiting by marking it as "ready". +     +    /** +     * Release an acquired wait object +     * @param wait_object WaitObject to release +     */ +    void ReleaseWaitObject(WaitObject* wait_object); + +    /// Resumes a thread from waiting by marking it as "ready"      void ResumeFromWait(); +    /** +     * Sets the result after the thread awakens (from either WaitSynchronization SVC) +     * @param result Value to set to the returned result +     */ +    void SetWaitSynchronizationResult(ResultCode result); + +    /** +     * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only) +     * @param output Value to set to the output parameter +     */ +    void SetWaitSynchronizationOutput(s32 output); +      Core::ThreadContext context;      u32 thread_id; @@ -95,11 +103,11 @@ public:      s32 processor_id; -    WaitType wait_type; -    Object* wait_object; -    VAddr wait_address; +    std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on -    std::vector<SharedPtr<Thread>> waiting_threads; +    VAddr wait_address;     ///< If waiting on an AddressArbiter, this is the arbitration address +    bool wait_all;          ///< True if the thread is waiting on all objects before resuming +    bool wait_set_output;   ///< True if the output parameter should be set on thread wakeup      std::string name; @@ -107,6 +115,7 @@ public:      bool idle = false;  private: +      Thread() = default;  }; @@ -117,37 +126,37 @@ SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);  void Reschedule();  /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); +Thread* ArbitrateHighestPriorityThread(u32 address);  /// Arbitrate all threads currently waiting... -void ArbitrateAllThreads(Object* arbiter, u32 address); +void ArbitrateAllThreads(u32 address);  /// Gets the current thread  Thread* GetCurrentThread(); -/** - * Puts the current thread in the wait state for the given type - * @param wait_type Type of wait - * @param wait_object Kernel object that we are waiting on, defaults to current thread - */ -void WaitCurrentThread(WaitType wait_type, Object* wait_object = GetCurrentThread()); +/// Waits the current thread on a sleep +void WaitCurrentThread_Sleep();  /** - * Schedules an event to wake up the specified thread after the specified delay. - * @param thread The thread to wake after the delay. - * @param nanoseconds The time this thread will be allowed to sleep for. + * Waits the current thread from a WaitSynchronization call + * @param wait_object Kernel object that we are waiting on + * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only) + * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)   */ -void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); +void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all);  /** - * Puts the current thread in the wait state for the given type - * @param wait_type Type of wait - * @param wait_object Kernel object that we are waiting on + * Waits the current thread from an ArbitrateAddress call   * @param wait_address Arbitration address used to resume from wait   */ -void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address); - +void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); +/** + * Schedules an event to wake up the specified thread after the specified delay. + * @param handle The thread handle. + * @param nanoseconds The time this thread will be allowed to sleep for. + */ +void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds);  /**   * Sets up the idle thread, this is a thread that is intended to never execute instructions, @@ -156,6 +165,7 @@ void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_addre   * @returns The handle of the idle thread   */  Handle SetupIdleThread(); +  /// Initialize threading  void ThreadingInit(); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 3b0452d4d..ec0b2c323 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -13,7 +13,7 @@  namespace Kernel { -class Timer : public Object { +class Timer : public WaitObject {  public:      std::string GetTypeName() const override { return "Timer"; }      std::string GetName() const override { return name; } @@ -24,19 +24,17 @@ public:      ResetType reset_type;                   ///< The ResetType of this timer      bool signaled;                          ///< Whether the timer has been signaled or not -    std::set<Handle> waiting_threads;       ///< Threads that are waiting for the timer      std::string name;                       ///< Name of timer (optional)      u64 initial_delay;                      ///< The delay until the timer fires for the first time      u64 interval_delay;                     ///< The delay until the timer fires after the first time -    ResultVal<bool> WaitSynchronization() override { -        bool wait = !signaled; -        if (wait) { -            waiting_threads.insert(GetCurrentThread()->GetHandle()); -            Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); -        } -        return MakeResult<bool>(wait); +    bool ShouldWait() override { +        return !signaled; +    } + +    void Acquire() override { +        _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");      }  }; @@ -92,12 +90,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {      timer->signaled = true;      // Resume all waiting threads -    for (Handle thread_handle : timer->waiting_threads) { -        if (SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(thread_handle)) -            thread->ResumeFromWait(); -    } - -    timer->waiting_threads.clear(); +    timer->WakeupAllWaitingThreads();      if (timer->reset_type == RESETTYPE_ONESHOT)          timer->signaled = false; diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 69a7bcf92..d318de3d2 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -50,8 +50,8 @@ void Initialize(Service::Interface* self) {      cmd_buff[3] = notification_event_handle;      cmd_buff[4] = pause_event_handle; -    Kernel::SetEventLocked(notification_event_handle, true); -    Kernel::SetEventLocked(pause_event_handle, false); // Fire start event +    Kernel::ClearEvent(notification_event_handle); +    Kernel::SignalEvent(pause_event_handle); // Fire start event      _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock");      Kernel::ReleaseMutex(lock_handle); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp new file mode 100644 index 000000000..5abcb2596 --- /dev/null +++ b/src/core/hle/service/hid/hid.cpp @@ -0,0 +1,138 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/hid/hid.h" + +#include "core/arm/arm_interface.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace HID { + +Handle g_shared_mem = 0; + +Handle g_event_pad_or_touch_1 = 0; +Handle g_event_pad_or_touch_2 = 0; +Handle g_event_accelerometer = 0; +Handle g_event_gyroscope = 0; +Handle g_event_debug_pad = 0; + +// Next Pad state update information +static PadState next_state = {{0}}; +static u32 next_index = 0; +static s16 next_circle_x = 0; +static s16 next_circle_y = 0; + +/** + * Gets a pointer to the PadData structure inside HID shared memory + */ +static inline PadData* GetPadData() { +    return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(g_shared_mem, 0).ValueOr(nullptr)); +} + +/** + * Circle Pad from keys. + * + * This is implemented as "pushed all the way to an edge (max) or centered (0)". + * + * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. + */ +static void UpdateNextCirclePadState() { +    static const s16 max_value = 0x9C; +    next_circle_x = next_state.circle_left ? -max_value : 0x0; +    next_circle_x += next_state.circle_right ? max_value : 0x0; +    next_circle_y = next_state.circle_down ? -max_value : 0x0; +    next_circle_y += next_state.circle_up ? max_value : 0x0; +} + +/** + * Sets a Pad state (button or button combo) as pressed + */ +void PadButtonPress(const PadState& pad_state) { +    next_state.hex |= pad_state.hex; +    UpdateNextCirclePadState(); +} + +/** + * Sets a Pad state (button or button combo) as released + */ +void PadButtonRelease(const PadState& pad_state) { +    next_state.hex &= ~pad_state.hex; +    UpdateNextCirclePadState(); +} + +/** + * Called after all Pad changes to be included in this update have been made, + * including both Pad key changes and analog circle Pad changes. + */ +void PadUpdateComplete() { +    PadData* pad_data = GetPadData(); + +    if (pad_data == nullptr) { +        return; +    } + +    // Update PadData struct +    pad_data->current_state.hex = next_state.hex; +    pad_data->index = next_index; +    next_index = (next_index + 1) % pad_data->entries.size(); + +    // Get the previous Pad state +    u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); +    PadState old_state = pad_data->entries[last_entry_index].current_state; + +    // Compute bitmask with 1s for bits different from the old state +    PadState changed; +    changed.hex = (next_state.hex ^ old_state.hex); + +    // Compute what was added +    PadState additions; +    additions.hex = changed.hex & next_state.hex; + +    // Compute what was removed +    PadState removals; +    removals.hex = changed.hex & old_state.hex; + +    // Get the current Pad entry +    PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; + +    // Update entry properties +    current_pad_entry->current_state.hex = next_state.hex; +    current_pad_entry->delta_additions.hex = additions.hex; +    current_pad_entry->delta_removals.hex = removals.hex; + +    // Set circle Pad +    current_pad_entry->circle_pad_x = next_circle_x; +    current_pad_entry->circle_pad_y = next_circle_y; + +    // If we just updated index 0, provide a new timestamp +    if (pad_data->index == 0) { +        pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; +        pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); +    } +     +    // Signal both handles when there's an update to Pad or touch +    Kernel::SignalEvent(g_event_pad_or_touch_1); +    Kernel::SignalEvent(g_event_pad_or_touch_2); +} + +void HIDInit() { +    g_shared_mem = Kernel::CreateSharedMemory("HID:SharedMem"); // Create shared memory object + +    // Create event handles +    g_event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); +    g_event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); +    g_event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); +    g_event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventGyroscope"); +    g_event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventDebugPad"); +} + +void HIDShutdown() { + +} + +} +} diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid/hid.h index 5b96dda60..73cdaa527 100644 --- a/src/core/hle/service/hid_user.h +++ b/src/core/hle/service/hid/hid.h @@ -1,19 +1,26 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2015 Citra Emulator Project  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included.  #pragma once -#include "core/hle/service/service.h" +#include <array> + +#include "core/hle/kernel/kernel.h"  #include "common/bit_field.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User +namespace Service { +namespace HID { -// This service is used for interfacing to physical user controls. -// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. +// Handle to shared memory region designated to HID_User service +extern Handle g_shared_mem; -namespace HID_User { +// Event handles +extern Handle g_event_pad_or_touch_1; +extern Handle g_event_pad_or_touch_2; +extern Handle g_event_accelerometer; +extern Handle g_event_gyroscope; +extern Handle g_event_debug_pad;  /**   * Structure of a Pad controller state. @@ -97,16 +104,8 @@ void PadButtonPress(const PadState& pad_state);  void PadButtonRelease(const PadState& pad_state);  void PadUpdateComplete(); -/** - * HID service interface. - */ -class Interface : public Service::Interface { -public: -    Interface(); - -    std::string GetPortName() const override { -        return "hid:USER"; -    } -}; +void HIDInit(); +void HIDShutdown(); -} // namespace +} +} diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp new file mode 100644 index 000000000..76c40b659 --- /dev/null +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -0,0 +1,38 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/hid/hid_spvr.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_SPVR + +namespace HID_User { +    extern void GetIPCHandles(Service::Interface* self); +} + +namespace HID_SPVR { + +const Interface::FunctionInfo FunctionTable[] = { +    {0x000A0000, HID_User::GetIPCHandles,    "GetIPCHandles"}, +    {0x000B0000, nullptr,                    "StartAnalogStickCalibration"}, +    {0x000E0000, nullptr,                    "GetAnalogStickCalibrateParam"}, +    {0x00110000, nullptr,                    "EnableAccelerometer"}, +    {0x00120000, nullptr,                    "DisableAccelerometer"}, +    {0x00130000, nullptr,                    "EnableGyroscopeLow"}, +    {0x00140000, nullptr,                    "DisableGyroscopeLow"}, +    {0x00150000, nullptr,                    "GetGyroscopeLowRawToDpsCoefficient"}, +    {0x00160000, nullptr,                    "GetGyroscopeLowCalibrateParam"}, +    {0x00170000, nullptr,                    "GetSoundVolume"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} +     +} // namespace diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h new file mode 100644 index 000000000..53ddc8569 --- /dev/null +++ b/src/core/hle/service/hid/hid_spvr.h @@ -0,0 +1,23 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_SPVR + +namespace HID_SPVR { + +class Interface : public Service::Interface { +public: +    Interface(); + +    std::string GetPortName() const override { +        return "hid:SPVR"; +    } +}; + +} // namespace diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp new file mode 100644 index 000000000..3a6275707 --- /dev/null +++ b/src/core/hle/service/hid/hid_user.cpp @@ -0,0 +1,75 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/log.h" + +#include "core/hle/hle.h" +#include "core/hle/service/hid/hid.h" +#include "hid_user.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_User + +namespace HID_User { + + +// TODO(peachum): +// Add a method for setting analog input from joystick device for the circle Pad. +// +// This method should: +//     * Be called after both PadButton<Press, Release>(). +//     * Be called before PadUpdateComplete() +//     * Set current PadEntry.circle_pad_<axis> using analog data +//     * Set PadData.raw_circle_pad_data +//     * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 +//     * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 +//     * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 +//     * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 + + +/** + * HID_User::GetIPCHandles service function + *  Inputs: + *      None + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + *      2 : Unused + *      3 : Handle to HID_User shared memory + *      4 : Event signaled by HID_User + *      5 : Event signaled by HID_User + *      6 : Event signaled by HID_User + *      7 : Gyroscope event + *      8 : Event signaled by HID_User + */ +void GetIPCHandles(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); + +    cmd_buff[1] = 0; // No error +    cmd_buff[3] = Service::HID::g_shared_mem; +    cmd_buff[4] = Service::HID::g_event_pad_or_touch_1; +    cmd_buff[5] = Service::HID::g_event_pad_or_touch_2; +    cmd_buff[6] = Service::HID::g_event_accelerometer; +    cmd_buff[7] = Service::HID::g_event_gyroscope; +    cmd_buff[8] = Service::HID::g_event_debug_pad; +} + +const Interface::FunctionInfo FunctionTable[] = { +    {0x000A0000, GetIPCHandles, "GetIPCHandles"}, +    {0x00110000, nullptr,       "EnableAccelerometer"}, +    {0x00120000, nullptr,       "DisableAccelerometer"}, +    {0x00130000, nullptr,       "EnableGyroscopeLow"}, +    {0x00140000, nullptr,       "DisableGyroscopeLow"}, +    {0x00150000, nullptr,       "GetGyroscopeLowRawToDpsCoefficient"}, +    {0x00160000, nullptr,       "GetGyroscopeLowCalibrateParam"}, +    {0x00170000, nullptr,       "GetSoundVolume"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +} // namespace diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h new file mode 100644 index 000000000..1d9929e67 --- /dev/null +++ b/src/core/hle/service/hid/hid_user.h @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_User + +// This service is used for interfacing to physical user controls. +// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. + +namespace HID_User { + +/** + * HID service interface. + */ +class Interface : public Service::Interface { +public: +    Interface(); + +    std::string GetPortName() const override { +        return "hid:USER"; +    } +}; + +} // namespace diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp deleted file mode 100644 index 1403b1de9..000000000 --- a/src/core/hle/service/hid_user.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/log.h" - -#include "core/arm/arm_interface.h" -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/shared_memory.h" -#include "hid_user.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - -namespace HID_User { - -// Handle to shared memory region designated to HID_User service -static Handle shared_mem = 0; - -// Event handles -static Handle event_pad_or_touch_1 = 0; -static Handle event_pad_or_touch_2 = 0; -static Handle event_accelerometer = 0; -static Handle event_gyroscope = 0; -static Handle event_debug_pad = 0; - -// Next Pad state update information -static PadState next_state = {{0}}; -static u32 next_index = 0; -static s16 next_circle_x = 0; -static s16 next_circle_y = 0; - -/** - * Gets a pointer to the PadData structure inside HID shared memory - */ -static inline PadData* GetPadData() { -    return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr)); -} - -/** - * Circle Pad from keys. - * - * This is implemented as "pushed all the way to an edge (max) or centered (0)". - * - * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. - */ -static void UpdateNextCirclePadState() { -    static const s16 max_value = 0x9C; -    next_circle_x = next_state.circle_left ? -max_value : 0x0; -    next_circle_x += next_state.circle_right ? max_value : 0x0; -    next_circle_y = next_state.circle_down ? -max_value : 0x0; -    next_circle_y += next_state.circle_up ? max_value : 0x0; -} - -/** - * Sets a Pad state (button or button combo) as pressed - */ -void PadButtonPress(const PadState& pad_state) { -    next_state.hex |= pad_state.hex; -    UpdateNextCirclePadState(); -} - -/** - * Sets a Pad state (button or button combo) as released - */ -void PadButtonRelease(const PadState& pad_state) { -    next_state.hex &= ~pad_state.hex; -    UpdateNextCirclePadState(); -} - -/** - * Called after all Pad changes to be included in this update have been made, - * including both Pad key changes and analog circle Pad changes. - */ -void PadUpdateComplete() { -    PadData* pad_data = GetPadData(); - -    if (pad_data == nullptr) { -        return; -    } - -    // Update PadData struct -    pad_data->current_state.hex = next_state.hex; -    pad_data->index = next_index; -    next_index = (next_index + 1) % pad_data->entries.size(); - -    // Get the previous Pad state -    u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); -    PadState old_state = pad_data->entries[last_entry_index].current_state; - -    // Compute bitmask with 1s for bits different from the old state -    PadState changed; -    changed.hex = (next_state.hex ^ old_state.hex); - -    // Compute what was added -    PadState additions; -    additions.hex = changed.hex & next_state.hex; - -    // Compute what was removed -    PadState removals; -    removals.hex = changed.hex & old_state.hex; - -    // Get the current Pad entry -    PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; - -    // Update entry properties -    current_pad_entry->current_state.hex = next_state.hex; -    current_pad_entry->delta_additions.hex = additions.hex; -    current_pad_entry->delta_removals.hex = removals.hex; - -    // Set circle Pad -    current_pad_entry->circle_pad_x = next_circle_x; -    current_pad_entry->circle_pad_y = next_circle_y; - -    // If we just updated index 0, provide a new timestamp -    if (pad_data->index == 0) { -        pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; -        pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); -    } - -    // Signal both handles when there's an update to Pad or touch -    Kernel::SignalEvent(event_pad_or_touch_1); -    Kernel::SignalEvent(event_pad_or_touch_2); -} - - -// TODO(peachum): -// Add a method for setting analog input from joystick device for the circle Pad. -// -// This method should: -//     * Be called after both PadButton<Press, Release>(). -//     * Be called before PadUpdateComplete() -//     * Set current PadEntry.circle_pad_<axis> using analog data -//     * Set PadData.raw_circle_pad_data -//     * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 -//     * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 -//     * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 -//     * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 - - -/** - * HID_User::GetIPCHandles service function - *  Inputs: - *      None - *  Outputs: - *      1 : Result of function, 0 on success, otherwise error code - *      2 : Unused - *      3 : Handle to HID_User shared memory - *      4 : Event signaled by HID_User - *      5 : Event signaled by HID_User - *      6 : Event signaled by HID_User - *      7 : Gyroscope event - *      8 : Event signaled by HID_User - */ -static void GetIPCHandles(Service::Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); - -    cmd_buff[1] = 0; // No error -    cmd_buff[3] = shared_mem; -    cmd_buff[4] = event_pad_or_touch_1; -    cmd_buff[5] = event_pad_or_touch_2; -    cmd_buff[6] = event_accelerometer; -    cmd_buff[7] = event_gyroscope; -    cmd_buff[8] = event_debug_pad; -} - -const Interface::FunctionInfo FunctionTable[] = { -    {0x000A0000, GetIPCHandles, "GetIPCHandles"}, -    {0x000B0000, nullptr,       "StartAnalogStickCalibration"}, -    {0x000E0000, nullptr,       "GetAnalogStickCalibrateParam"}, -    {0x00110000, nullptr,       "EnableAccelerometer"}, -    {0x00120000, nullptr,       "DisableAccelerometer"}, -    {0x00130000, nullptr,       "EnableGyroscopeLow"}, -    {0x00140000, nullptr,       "DisableGyroscopeLow"}, -    {0x00150000, nullptr,       "GetGyroscopeLowRawToDpsCoefficient"}, -    {0x00160000, nullptr,       "GetGyroscopeLowCalibrateParam"}, -    {0x00170000, nullptr,       "GetSoundVolume"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { -    shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object - -    // Create event handles -    event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1"); -    event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2"); -    event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer"); -    event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope"); -    event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad"); - -    Register(FunctionTable, ARRAY_SIZE(FunctionTable)); -} - -} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 752dc28cb..444a4eab1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -25,7 +25,8 @@  #include "core/hle/service/fs/fs_user.h"  #include "core/hle/service/frd_u.h"  #include "core/hle/service/gsp_gpu.h" -#include "core/hle/service/hid_user.h" +#include "core/hle/service/hid/hid_spvr.h" +#include "core/hle/service/hid/hid_user.h"  #include "core/hle/service/http_c.h"  #include "core/hle/service/ir_rst.h"  #include "core/hle/service/ir_u.h" @@ -104,6 +105,7 @@ void Init() {      g_manager->AddService(new FRD_U::Interface);      g_manager->AddService(new FS::FSUserInterface);      g_manager->AddService(new GSP_GPU::Interface); +    g_manager->AddService(new HID_SPVR::Interface);      g_manager->AddService(new HID_User::Interface);      g_manager->AddService(new HTTP_C::Interface);      g_manager->AddService(new IR_RST::Interface); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index ac5f30a28..082834cfe 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -24,7 +24,7 @@ static void GetProcSemaphore(Service::Interface* self) {      // TODO(bunnei): Change to a semaphore once these have been implemented      g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event"); -    Kernel::SetEventLocked(g_event_handle, false); +    Kernel::ClearEvent(g_event_handle);      cmd_buff[1] = 0; // No error      cmd_buff[3] = g_event_handle; diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a487f757c..2d922046e 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -29,6 +29,9 @@ using Kernel::SharedPtr;  namespace SVC { +/// An invalid result code that is meant to be overwritten when a thread resumes from waiting +const ResultCode RESULT_INVALID(0xDEADC0DE); +  enum ControlMemoryOperation {      MEMORY_OPERATION_HEAP       = 0x00000003,      MEMORY_OPERATION_GSP_HEAP   = 0x00010003, @@ -103,12 +106,7 @@ static Result SendSyncRequest(Handle handle) {      LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); -    ResultVal<bool> wait = session->SyncRequest(); -    if (wait.Succeeded() && *wait) { -        Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? -    } - -    return wait.Code().raw; +    return session->SyncRequest().Code().raw;  }  /// Close a handle @@ -120,64 +118,122 @@ static Result CloseHandle(Handle handle) {  /// Wait for a handle to synchronize, timeout after the specified nanoseconds  static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { -    SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handle); +    auto object = Kernel::g_handle_table.GetWaitObject(handle);      if (object == nullptr)          return InvalidHandle(ErrorModule::Kernel).raw;      LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,              object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); -    ResultVal<bool> wait = object->WaitSynchronization(); -      // Check for next thread to schedule -    if (wait.Succeeded() && *wait) { +    if (object->ShouldWait()) { + +        object->AddWaitingThread(Kernel::GetCurrentThread()); +        Kernel::WaitCurrentThread_WaitSynchronization(object, false, false); +          // Create an event to wake the thread up after the specified nanosecond delay has passed          Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); +          HLE::Reschedule(__func__); + +        // NOTE: output of this SVC will be set later depending on how the thread resumes +        return RESULT_INVALID.raw;      } -    return wait.Code().raw; +    object->Acquire(); + +    return RESULT_SUCCESS.raw;  }  /// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, -    s64 nano_seconds) { - -    // TODO(bunnei): Do something with nano_seconds, currently ignoring this -    bool unlock_all = true; -    bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated - -    LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", -        handle_count, (wait_all ? "true" : "false"), nano_seconds); - -    // Iterate through each handle, synchronize kernel object -    for (s32 i = 0; i < handle_count; i++) { -        SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]); -        if (object == nullptr) -            return InvalidHandle(ErrorModule::Kernel).raw; - -        LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], -                object->GetTypeName().c_str(), object->GetName().c_str()); - -        // TODO(yuriks): Verify how the real function behaves when an error happens here -        ResultVal<bool> wait_result = object->WaitSynchronization(); -        bool wait = wait_result.Succeeded() && *wait_result; - -        if (!wait && !wait_all) { -            *out = i; -            return RESULT_SUCCESS.raw; -        } else { -            unlock_all = false; +static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { +    bool wait_thread = !wait_all; +    int handle_index = 0; + +    // Check if 'handles' is invalid +    if (handles == nullptr) +        return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; + +    // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If +    // this happens, the running application will crash. +    _assert_msg_(Kernel, out != nullptr, "invalid output pointer specified!"); + +    // Check if 'handle_count' is invalid +    if (handle_count < 0) +        return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; + +    // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if +    // necessary +    if (handle_count != 0) { +        bool selected = false; // True once an object has been selected +        for (int i = 0; i < handle_count; ++i) { +            auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); +            if (object == nullptr) +                return InvalidHandle(ErrorModule::Kernel).raw; + +            // Check if the current thread should wait on this object... +            if (object->ShouldWait()) { + +                // Check we are waiting on all objects... +                if (wait_all) +                    // Wait the thread +                    wait_thread = true; +            } else { +                // Do not wait on this object, check if this object should be selected... +                if (!wait_all && !selected) { +                    // Do not wait the thread +                    wait_thread = false; +                    handle_index = i; +                    selected = true; +                } +            } +        } +    } else { +        // If no handles were passed in, put the thread to sleep only when 'wait_all' is false +        // NOTE: This should deadlock the current thread if no timeout was specified +        if (!wait_all) { +            wait_thread = true; +            Kernel::WaitCurrentThread_WaitSynchronization(nullptr, true, wait_all); +        } +    } + +    // If thread should wait, then set its state to waiting and then reschedule... +    if (wait_thread) { + +        // Actually wait the current thread on each object if we decided to wait... +        for (int i = 0; i < handle_count; ++i) { +            auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); +            object->AddWaitingThread(Kernel::GetCurrentThread()); +            Kernel::WaitCurrentThread_WaitSynchronization(object, true, wait_all);          } + +        // Create an event to wake the thread up after the specified nanosecond delay has passed +        Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); + +        HLE::Reschedule(__func__); + +        // NOTE: output of this SVC will be set later depending on how the thread resumes +        return RESULT_INVALID.raw;      } -    if (wait_all && unlock_all) { -        *out = handle_count; -        return RESULT_SUCCESS.raw; +    // Acquire objects if we did not wait... +    for (int i = 0; i < handle_count; ++i) { +        auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); + +        // Acquire the object if it is not waiting... +        if (!object->ShouldWait()) { +            object->Acquire(); + +            // If this was the first non-waiting object and 'wait_all' is false, don't acquire +            // any other objects +            if (!wait_all) +                break; +        }      } -    // Check for next thread to schedule -    HLE::Reschedule(__func__); +    // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does +    // not seem to set it to any meaningful value. +    *out = wait_all ? 0 : handle_index;      return RESULT_SUCCESS.raw;  } @@ -351,6 +407,7 @@ static Result DuplicateHandle(Handle* out, Handle handle) {  /// Signals an event  static Result SignalEvent(Handle evt) {      LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); +    HLE::Reschedule(__func__);      return Kernel::SignalEvent(evt).raw;  } @@ -391,7 +448,7 @@ static void SleepThread(s64 nanoseconds) {      LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);      // Sleep current thread and check for next thread to schedule -    Kernel::WaitCurrentThread(WAITTYPE_SLEEP); +    Kernel::WaitCurrentThread_Sleep();      // Create an event to wake the thread up after the specified nanosecond delay has passed      Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); | 
