diff options
Diffstat (limited to 'src/core')
68 files changed, 3945 insertions, 2421 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index aefbe3375..f41d52e80 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -30,13 +30,23 @@ set(SRCS hle/kernel/mutex.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp - hle/service/apt.cpp - hle/service/fs.cpp - hle/service/gsp.cpp - hle/service/hid.cpp - hle/service/ndm.cpp + hle/service/ac_u.cpp + hle/service/apt_u.cpp + hle/service/cfg_u.cpp + hle/service/dsp_dsp.cpp + hle/service/err_f.cpp + hle/service/fs_user.cpp + hle/service/frd_u.cpp + hle/service/gsp_gpu.cpp + hle/service/hid_user.cpp + hle/service/mic_u.cpp + hle/service/ndm_u.cpp + hle/service/nwm_uds.cpp + hle/service/ptm_u.cpp hle/service/service.cpp + hle/service/soc_u.cpp hle/service/srv.cpp + hle/service/ssl_c.cpp hle/config_mem.cpp hle/hle.cpp hle/svc.cpp @@ -91,13 +101,23 @@ set(HEADERS hle/kernel/mutex.h hle/kernel/shared_memory.h hle/kernel/thread.h - hle/service/apt.h - hle/service/fs.h - hle/service/gsp.h - hle/service/hid.h - hle/service/ndm.h + hle/service/ac_u.h + hle/service/apt_u.h + hle/service/cfg_u.h + hle/service/dsp_dsp.h + hle/service/err_f.h + hle/service/fs_user.h + hle/service/frd_u.h + hle/service/gsp_gpu.h + hle/service/hid_user.h + hle/service/mic_u.h + hle/service/ndm_u.h + hle/service/nwm_uds.h + hle/service/ptm_u.h hle/service/service.h + hle/service/soc_u.h hle/service/srv.h + hle/service/ssl_c.h hle/config_mem.h hle/function_wrappers.h hle/hle.h diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index be677ae20..4b93d3313 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -16,7 +16,7 @@ public: num_instructions = 0; } - ~ARM_Interface() { + virtual ~ARM_Interface() { } /** diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 669b612fc..a3ed3e31e 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -60,7 +60,7 @@ void ARM_DynCom::SetPC(u32 pc) { * @return Returns current PC */ u32 ARM_DynCom::GetPC() const { - return state->pc; + return state->Reg[15]; } /** @@ -110,9 +110,12 @@ u64 ARM_DynCom::GetTicks() const { * @param num_instructions Number of instructions to executes */ void ARM_DynCom::ExecuteInstructions(int num_instructions) { - ticks += num_instructions; state->NumInstrsToExecute = num_instructions; - InterpreterMainLoop(state.get()); + + // Dyncom only breaks on instruction dispatch. This only happens on every instruction when + // executing one instruction at a time. Otherwise, if a block is being executed, more + // instructions may actually be executed than specified. + ticks += InterpreterMainLoop(state.get()); } /** @@ -126,7 +129,7 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) { ctx.sp = state->Reg[13]; ctx.lr = state->Reg[14]; - ctx.pc = state->pc; + ctx.pc = state->Reg[15]; ctx.cpsr = state->Cpsr; ctx.fpscr = state->VFP[1]; diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 9f88dd139..1f8cd3a3a 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -21,7 +21,7 @@ public: * Set the Program Counter to an address * @param addr Address to set PC to */ - void SetPC(u32 pc); + void SetPC(u32 pc) override; /* * Get the current Program Counter @@ -41,7 +41,7 @@ public: * @param index Register index (0-15) * @param value Value to set register to */ - void SetReg(int index, u32 value); + void SetReg(int index, u32 value) override; /** * Get the current CPSR register @@ -53,7 +53,7 @@ public: * Set the current CPSR register * @param cpsr Value to set CPSR to */ - void SetCPSR(u32 cpsr); + void SetCPSR(u32 cpsr) override; /** * Returns the number of clock ticks since the last reset @@ -65,22 +65,22 @@ public: * Saves the current CPU context * @param ctx Thread context to save */ - void SaveContext(ThreadContext& ctx); + void SaveContext(ThreadContext& ctx) override; /** * Loads a CPU context * @param ctx Thread context to load */ - void LoadContext(const ThreadContext& ctx); + void LoadContext(const ThreadContext& ctx) override; /// Prepare core for thread reschedule (if needed to correctly handle state) - void PrepareReschedule(); + void PrepareReschedule() override; /** * Executes the given number of instructions * @param num_instructions Number of instructions to executes */ - void ExecuteInstructions(int num_instructions); + void ExecuteInstructions(int num_instructions) override; private: diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index fe1501b59..f899e2e8a 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3718,7 +3718,7 @@ static bool InAPrivilegedMode(arm_core_t *core) } /* r15 = r15 + 8 */ -void InterpreterMainLoop(ARMul_State* state) +unsigned InterpreterMainLoop(ARMul_State* state) { #define CRn inst_cream->crn #define OPCODE_2 inst_cream->opcode_2 @@ -3747,16 +3747,22 @@ void InterpreterMainLoop(ARMul_State* state) #endif #define FETCH_INST if (inst_base->br != NON_BRANCH) \ - goto PROFILING; \ + goto DISPATCH; \ inst_base = (arm_inst *)&inst_buf[ptr] #define INC_PC(l) ptr += sizeof(arm_inst) + l // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a // clunky switch statement. #if defined __GNUC__ || defined __clang__ -#define GOTO_NEXT_INST goto *InstLabel[inst_base->idx] +#define GOTO_NEXT_INST \ + if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ + num_instrs++; \ + goto *InstLabel[inst_base->idx] #else -#define GOTO_NEXT_INST switch(inst_base->idx) { \ +#define GOTO_NEXT_INST \ + if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ + num_instrs++; \ + switch(inst_base->idx) { \ case 0: goto VMLA_INST; \ case 1: goto VMLS_INST; \ case 2: goto VNMLA_INST; \ @@ -4028,20 +4034,15 @@ void InterpreterMainLoop(ARMul_State* state) unsigned int addr; unsigned int phys_addr; unsigned int last_pc = 0; + unsigned int num_instrs = 0; fault_t fault; static unsigned int last_physical_base = 0, last_logical_base = 0; int ptr; + bool single_step = (cpu->NumInstrsToExecute == 1); LOAD_NZCVT; DISPATCH: { - if (cpu->NumInstrsToExecute == 0) - return; - - cpu->NumInstrsToExecute--; - - //NOTICE_LOG(ARM11, "instr!"); - if (!cpu->NirqSig) { if (!(cpu->Cpsr & 0x80)) { goto END; @@ -4179,10 +4180,6 @@ void InterpreterMainLoop(ARMul_State* state) inst_base = (arm_inst *)&inst_buf[ptr]; GOTO_NEXT_INST; } - PROFILING: - { - goto DISPATCH; - } ADC_INST: { INC_ICOUNTER; @@ -4207,7 +4204,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(adc_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4241,7 +4238,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(add_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4272,7 +4269,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(and_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4290,11 +4287,11 @@ void InterpreterMainLoop(ARMul_State* state) } SET_PC; INC_PC(sizeof(bbl_inst)); - goto PROFILING; + goto DISPATCH; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(bbl_inst)); - goto PROFILING; + goto DISPATCH; } BIC_INST: { @@ -4322,7 +4319,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(bic_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4358,12 +4355,12 @@ void InterpreterMainLoop(ARMul_State* state) //DEBUG_MSG; } INC_PC(sizeof(blx_inst)); - goto PROFILING; + goto DISPATCH; } cpu->Reg[15] += GET_INST_SIZE(cpu); // INC_PC(sizeof(bx_inst)); INC_PC(sizeof(blx_inst)); - goto PROFILING; + goto DISPATCH; } BX_INST: { @@ -4376,12 +4373,12 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; // cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; INC_PC(sizeof(bx_inst)); - goto PROFILING; + goto DISPATCH; } cpu->Reg[15] += GET_INST_SIZE(cpu); // INC_PC(sizeof(bx_inst)); INC_PC(sizeof(bx_inst)); - goto PROFILING; + goto DISPATCH; } BXJ_INST: CDP_INST: @@ -4393,7 +4390,8 @@ void InterpreterMainLoop(ARMul_State* state) #define CP_ACCESS_ALLOW 0 if(CP_ACCESS_ALLOW){ /* undefined instruction here */ - return; + cpu->NumInstrsToExecute = 0; + return num_instrs; } ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]); unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst); @@ -4522,7 +4520,7 @@ void InterpreterMainLoop(ARMul_State* state) // RD = RM; if ((inst_cream->Rd == 15)) { INC_PC(sizeof(mov_inst)); - goto PROFILING; + goto DISPATCH; } } // DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]); @@ -4558,7 +4556,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(eor_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4717,7 +4715,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (BIT(inst, 15)) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4764,7 +4762,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->TFlag = value & 0x1; cpu->Reg[15] &= 0xFFFFFFFE; INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } //} cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4794,7 +4792,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->TFlag = value & 0x1; cpu->Reg[15] &= 0xFFFFFFFE; INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4848,7 +4846,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4869,7 +4867,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4926,7 +4924,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4953,7 +4951,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4980,7 +4978,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5006,7 +5004,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5031,7 +5029,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5058,7 +5056,7 @@ void InterpreterMainLoop(ARMul_State* state) if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5228,7 +5226,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(mla_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5260,7 +5258,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(mov_inst)); - goto PROFILING; + goto DISPATCH; } // return; } @@ -5422,7 +5420,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(mul_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5451,7 +5449,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(mvn_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5483,7 +5481,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(orr_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5575,7 +5573,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(rsb_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5612,7 +5610,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(rsc_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5653,7 +5651,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(sbc_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -6066,7 +6064,7 @@ void InterpreterMainLoop(ARMul_State* state) } cpu->Reg[15] += GET_INST_SIZE(cpu); //if (BITS(inst_cream->inst, 12, 15) == 15) - // goto PROFILING; + // goto DISPATCH; INC_PC(sizeof(ldst_inst)); FETCH_INST; GOTO_NEXT_INST; @@ -6175,7 +6173,7 @@ void InterpreterMainLoop(ARMul_State* state) } cpu->Reg[15] += GET_INST_SIZE(cpu); //if (BITS(inst_cream->inst, 12, 15) == 15) - // goto PROFILING; + // goto DISPATCH; INC_PC(sizeof(ldst_inst)); FETCH_INST; GOTO_NEXT_INST; @@ -6225,7 +6223,7 @@ void InterpreterMainLoop(ARMul_State* state) } if (inst_cream->Rd == 15) { INC_PC(sizeof(sub_inst)); - goto PROFILING; + goto DISPATCH; } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -6449,7 +6447,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); INC_PC(sizeof(b_2_thumb)); - goto PROFILING; + goto DISPATCH; } B_COND_THUMB: { @@ -6461,7 +6459,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[15] += 2; //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]); INC_PC(sizeof(b_cond_thumb)); - goto PROFILING; + goto DISPATCH; } BL_1_THUMB: { @@ -6487,7 +6485,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->Reg[14] = tmp; //DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); INC_PC(sizeof(bl_2_thumb)); - goto PROFILING; + goto DISPATCH; } BLX_1_THUMB: { @@ -6503,7 +6501,7 @@ void InterpreterMainLoop(ARMul_State* state) cpu->TFlag = 0; //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); INC_PC(sizeof(blx_1_thumb)); - goto PROFILING; + goto DISPATCH; } UQADD16_INST: @@ -6532,12 +6530,14 @@ void InterpreterMainLoop(ARMul_State* state) cpu->AbortAddr = addr; cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff; cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; - return; + cpu->NumInstrsToExecute = 0; + return num_instrs; } END: { SAVE_NZCVT; - return; + cpu->NumInstrsToExecute = 0; + return num_instrs; } INIT_INST_LENGTH: { @@ -6557,7 +6557,8 @@ void InterpreterMainLoop(ARMul_State* state) DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]); DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]); #endif - return; + cpu->NumInstrsToExecute = 0; + return num_instrs; } } diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h index d73f8f65f..c65eb23f7 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.h +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h @@ -4,4 +4,4 @@ #pragma once -void InterpreterMainLoop(ARMul_State* state); +unsigned InterpreterMainLoop(ARMul_State* state); diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 49ae01a0c..ceb1be438 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h @@ -20,60 +20,60 @@ public: * Set the Program Counter to an address * @param addr Address to set PC to */ - void SetPC(u32 pc); + void SetPC(u32 pc) override; /* * Get the current Program Counter * @return Returns current PC */ - u32 GetPC() const; + u32 GetPC() const override; /** * Get an ARM register * @param index Register index (0-15) * @return Returns the value in the register */ - u32 GetReg(int index) const; + u32 GetReg(int index) const override; /** * Set an ARM register * @param index Register index (0-15) * @param value Value to set register to */ - void SetReg(int index, u32 value); + void SetReg(int index, u32 value) override; /** * Get the current CPSR register * @return Returns the value of the CPSR register */ - u32 GetCPSR() const; + u32 GetCPSR() const override; /** * Set the current CPSR register * @param cpsr Value to set CPSR to */ - void SetCPSR(u32 cpsr); + void SetCPSR(u32 cpsr) override; /** * Returns the number of clock ticks since the last reset * @return Returns number of clock ticks */ - u64 GetTicks() const; + u64 GetTicks() const override; /** * Saves the current CPU context * @param ctx Thread context to save */ - void SaveContext(ThreadContext& ctx); + void SaveContext(ThreadContext& ctx) override; /** * Loads a CPU context * @param ctx Thread context to load */ - void LoadContext(const ThreadContext& ctx); + void LoadContext(const ThreadContext& ctx) override; /// Prepare core for thread reschedule (if needed to correctly handle state) - void PrepareReschedule(); + void PrepareReschedule() override; protected: @@ -81,7 +81,7 @@ protected: * Executes the given number of instructions * @param num_instructions Number of instructions to executes */ - void ExecuteInstructions(int num_instructions); + void ExecuteInstructions(int num_instructions) override; private: diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index cdcf47ee1..73223874e 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -63,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); static void Handle_Load_Double (ARMul_State *, ARMword); static void Handle_Store_Double (ARMul_State *, ARMword); -void -XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far); -int -XScale_debug_moe (ARMul_State * state, int moe); -unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum); - static int handle_v6_insn (ARMul_State * state, ARMword instr); @@ -376,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state) #endif { /* The PC pipeline value depends on whether ARM - or Thumb instructions are being + or Thumb instructions are being d. */ ARMword isize; ARMword instr; /* The current instruction. */ @@ -538,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state) state->AbortAddr = 1; instr = ARMul_LoadInstrN (state, pc, isize); + //chy 2006-04-12, for ICE debug have_bp=ARMul_ICE_debug(state,instr,pc); #if 0 @@ -562,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state) } printf("\n"); #endif + instr = ARMul_LoadInstrN (state, pc, isize); state->last_instr = state->CurrInstr; state->CurrInstr = instr; @@ -952,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state) case t_decoded: /* ARM instruction available. */ //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); - - if (armOp == 0xDEADC0DE) - { + + if (armOp == 0xDEADC0DE) { DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); } @@ -967,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state) } } #endif - /* Check the condition codes. */ if ((temp = TOPBITS (28)) == AL) { /* Vile deed in the need for speed. */ @@ -1124,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state) //chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... + /* Actual execution of instructions begins here. */ /* If the condition codes don't match, stop here. */ if (temp) { @@ -2308,12 +2302,9 @@ mainswitch: if (state->Aborted) { TAKEABORT; } - if (enter) - { + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } break; @@ -3063,7 +3054,27 @@ mainswitch: break; case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { + //ichfly PKHBT PKHTB todo check this + if ((instr & 0x70) == 0x10) //pkhbt + { + u8 idest = BITS(12, 15); + u8 rfis = BITS(16, 19); + u8 rlast = BITS(0, 3); + u8 ishi = BITS(7,11); + state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); + break; + } + else if ((instr & 0x70) == 0x50)//pkhtb + { + u8 idest = BITS(12, 15); + u8 rfis = BITS(16, 19); + u8 rlast = BITS(0, 3); + u8 ishi = BITS(7, 11); + if (ishi == 0)ishi = 0x20; + state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); + break; + } + else if (BIT (4)) { #ifdef MODE32 if (state->is_v6 && handle_v6_insn (state, instr)) @@ -3675,7 +3686,13 @@ mainswitch: /* Co-Processor Data Transfers. */ case 0xc4: - if (state->is_v5) { + if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 + { + state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)]; + state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; + break; + } + else if (state->is_v5) { /* Reading from R15 is UNPREDICTABLE. */ if (BITS (12, 15) == 15 || BITS (16, 19) == 15) ARMul_UndefInstr (state, instr); @@ -3695,13 +3712,21 @@ mainswitch: break; case 0xc5: - if (state->is_v5) { + if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 + { + state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1]; + state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; + break; + } + else if (state->is_v5) { /* Writes to R15 are UNPREDICATABLE. */ if (DESTReg == 15 || LHSReg == 15) ARMul_UndefInstr (state, instr); /* Is access to the coprocessor allowed ? */ else if (!CP_ACCESS_ALLOWED(state, CPNum)) - ARMul_UndefInstr (state, instr); + { + ARMul_UndefInstr(state, instr); + } else { /* MRRC, ARMv5TE and up */ ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); @@ -4059,9 +4084,11 @@ TEST_EMULATE: // continue; else if (state->Emulate != RUN) break; - } - while (state->NumInstrsToExecute--); + + } + while (state->NumInstrsToExecute); +exit: state->decoded = decoded; state->loaded = loaded; state->pc = pc; @@ -5686,12 +5713,98 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; +#endif case 0x61: - printf ("Unhandled v6 insn: sadd/ssub\n"); + if ((instr & 0xFF0) == 0xf70)//ssub16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf10)//sadd16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf50)//ssax + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf30)//sasx + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); + return 1; + } + else printf ("Unhandled v6 insn: sadd/ssub\n"); break; case 0x62: - printf ("Unhandled v6 insn: qadd/qsub\n"); + if ((instr & 0xFF0) == 0xf70)//QSUB16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + s32 res1 = (a1 - b1); + s32 res2 = (a2 - b2); + if (res1 > 0x7FFF) res1 = 0x7FFF; + if (res2 > 0x7FFF) res2 = 0x7FFF; + if (res1 < 0x7FFF) res1 = -0x8000; + if (res2 < 0x7FFF) res2 = -0x8000; + state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf10)//QADD16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + s32 res1 = (a1 + b1); + s32 res2 = (a2 + b2); + if (res1 > 0x7FFF) res1 = 0x7FFF; + if (res2 > 0x7FFF) res2 = 0x7FFF; + if (res1 < 0x7FFF) res1 = -0x8000; + if (res2 < 0x7FFF) res2 = -0x8000; + state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); + return 1; + } + else printf ("Unhandled v6 insn: qadd/qsub\n"); break; +#if 0 case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break; @@ -5709,10 +5822,65 @@ L_stm_s_takeabort: break; #endif case 0x6c: - printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); + if ((instr & 0xf03f0) == 0xf0070) //uxtb16 + { + u8 src1 = BITS(0, 3); + u8 tar = BITS(12, 15); + u32 base = state->Reg[src1]; + u32 shamt = BITS(9,10)* 8; + u32 in = ((base << (32 - shamt)) | (base >> shamt)); + state->Reg[tar] = in & 0x00FF00FF; + return 1; + } + else + printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break; case 0x70: - printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); + if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 swap = BIT(5); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 + b1*b2; + return 1; + + } + else if ((instr & 0xf0d0) == 0xf050)//smusd + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 swap = BIT(5); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 - b1*b2; + return 1; + } + else if ((instr & 0xd0) == 0x10)//smlad + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 src3 = BITS(12, 15); + u8 swap = BIT(5); + + u32 a3 = state->Reg[src3]; + + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 + b1*b2 + a3; + return 1; + } + else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break; case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); @@ -5750,13 +5918,10 @@ L_stm_s_takeabort: if (state->Aborted) { TAKEABORT; } - - if (enter) - { + + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } @@ -5795,12 +5960,9 @@ L_stm_s_takeabort: } - if (enter) - { + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } @@ -5853,8 +6015,25 @@ L_stm_s_takeabort: case 0x01: case 0xf3: - printf ("Unhandled v6 insn: ssat\n"); - return 0; + //ichfly + //SSAT16 + { + u8 tar = BITS(12,15); + u8 src = BITS(0, 3); + u8 val = BITS(16, 19) + 1; + s16 a1 = (state->Reg[src]); + s16 a2 = (state->Reg[src] >> 0x10); + s16 min = (s16)(0x8000) >> (16 - val); + s16 max = 0x7FFF >> (16 - val); + if (min > a1) a1 = min; + if (max < a1) a1 = max; + if (min > a2) a2 = min; + if (max < a2) a2 = max; + u32 temp2 = ((u32)(a2)) << 0x10; + state->Reg[tar] = (a1&0xFFFF) | (temp2); + } + + return 1; default: break; } @@ -5944,8 +6123,21 @@ L_stm_s_takeabort: case 0x01: case 0xf3: - printf ("Unhandled v6 insn: usat\n"); - return 0; + //ichfly + //USAT16 + { + u8 tar = BITS(12, 15); + u8 src = BITS(0, 3); + u8 val = BITS(16, 19); + s16 a1 = (state->Reg[src]); + s16 a2 = (state->Reg[src] >> 0x10); + s16 max = 0xFFFF >> (16 - val); + if (max < a1) a1 = max; + if (max < a2) a2 = max; + u32 temp2 = ((u32)(a2)) << 0x10; + state->Reg[tar] = (a1 & 0xFFFF) | (temp2); + } + return 1; default: break; } diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index e4fa3c20a..454f60099 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp @@ -28,230 +28,270 @@ #include "core/arm/skyeye_common/armdefs.h" #include "core/arm/skyeye_common/vfp/vfp.h" +#define DEBUG DBG + //ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ unsigned VFPInit (ARMul_State *state) { - state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | - VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; - state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; - state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; - - //persistent_state = state; - /* Reset only specify VFP_FPEXC_EN = '0' */ - - return No_exp; + state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | + VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; + state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; + state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; + + //persistent_state = state; + /* Reset only specify VFP_FPEXC_EN = '0' */ + + return 0; } unsigned -VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) +VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value) { - /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MRC_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_MRC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", - instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); - - return ARMul_CANT; + /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (21, 23); + int Rt = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 10 || CoProc == 11) { +#define VFP_MRC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; } unsigned -VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) +VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value) { - /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MCR_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_MCR_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", - instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); - - return ARMul_CANT; + /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (21, 23); + int Rt = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + if (CoProc == 10 || CoProc == 11) { +#define VFP_MCR_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCR_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; } unsigned -VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2) +VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2) { - /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MRRC_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_MRRC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", - instr, CoProc, OPC_1, Rt, Rt2, CRm); - - return ARMul_CANT; + /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (4, 7); + int Rt = BITS (12, 15); + int Rt2 = BITS (16, 19); + int CRm = BITS (0, 3); + + if (CoProc == 10 || CoProc == 11) { +#define VFP_MRRC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRRC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; } unsigned -VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2) +VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2) { - /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 11 || CoProc == 10) - { - #define VFP_MCRR_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_MCRR_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", - instr, CoProc, OPC_1, Rt, Rt2, CRm); - - return ARMul_CANT; + /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (4, 7); + int Rt = BITS (12, 15); + int Rt2 = BITS (16, 19); + int CRm = BITS (0, 3); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 11 || CoProc == 10) { +#define VFP_MCRR_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCRR_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; } unsigned -VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) +VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value) { - /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); - - /* TODO check access permission */ - - /* VSTM */ - if ( (P|U|D|W) == 0 ) - { - DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); - } - if (CoProc == 10 || CoProc == 11) - { - #if 1 - if (P == 0 && U == 0 && W == 0) - { - DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1); - } - if (P == U && W == 1) - { - DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1); - } - #endif - - #define VFP_STC_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_STC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", - instr, CoProc, CRd, Rn, imm8, P, U, D, W); - - return ARMul_CANT; + /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int CRd = BITS (12, 15); + int Rn = BITS (16, 19); + int imm8 = BITS (0, 7); + int P = BIT(24); + int U = BIT(23); + int D = BIT(22); + int W = BIT(21); + + /* TODO check access permission */ + + /* VSTM */ + if ( (P|U|D|W) == 0 ) { + DEBUG("In %s, UNDEFINED\n", __FUNCTION__); + exit(-1); + } + if (CoProc == 10 || CoProc == 11) { +#if 1 + if (P == 0 && U == 0 && W == 0) { + DEBUG("VSTM Related encodings\n"); + exit(-1); + } + if (P == U && W == 1) { + DEBUG("UNDEFINED\n"); + exit(-1); + } +#endif + +#define VFP_STC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_STC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", + instr, CoProc, CRd, Rn, imm8, P, U, D, W); + + return ARMul_CANT; } unsigned -VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value) +VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value) { - /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); - - /* TODO check access permission */ - - if ( (P|U|D|W) == 0 ) - { - DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); - } - if (CoProc == 10 || CoProc == 11) - { - #define VFP_LDC_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_LDC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", - instr, CoProc, CRd, Rn, imm8, P, U, D, W); - - return ARMul_CANT; + /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int CRd = BITS (12, 15); + int Rn = BITS (16, 19); + int imm8 = BITS (0, 7); + int P = BIT(24); + int U = BIT(23); + int D = BIT(22); + int W = BIT(21); + + /* TODO check access permission */ + + if ( (P|U|D|W) == 0 ) { + DEBUG("In %s, UNDEFINED\n", __FUNCTION__); + exit(-1); + } + if (CoProc == 10 || CoProc == 11) { +#define VFP_LDC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_LDC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", + instr, CoProc, CRd, Rn, imm8, P, U, D, W); + + return ARMul_CANT; } unsigned -VFPCDP (ARMul_State * state, unsigned type, ARMword instr) +VFPCDP (ARMul_State * state, unsigned type, u32 instr) { - /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (20, 23); - int CRd = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_CDP_TRANS - #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" - #undef VFP_CDP_TRANS - - int exceptions = 0; - if (CoProc == 10) - exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - else - exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - - vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - - return ARMul_DONE; - } - DEBUG_LOG(ARM11, "Can't identify %x\n", instr); - return ARMul_CANT; + /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (20, 23); + int CRd = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + //ichfly + /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6) + { + struct vfp_double vdd; + struct vfp_single vsd; + int dn = BITS(12, 15) + (BIT(22) << 4); + int sd = (BITS(0, 3) << 1) + BIT(5); + s32 n = vfp_get_float(state, sd); + vfp_single_unpack(&vsd, n); + if (vsd.exponent & 0x80) + { + vdd.exponent = (vsd.exponent&~0x80) | 0x400; + } + else + { + vdd.exponent = vsd.exponent | 0x380; + } + vdd.sign = vsd.sign; + vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand + vfp_put_double(state, vfp_double_pack(&vdd), dn); + return ARMul_DONE; + } + if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6 + { + struct vfp_double vdd; + struct vfp_single vsd; + int sd = BITS(0, 3) + (BIT(5) << 4); + int dn = (BITS(12, 15) << 1) + BIT(22); + vfp_double_unpack(&vdd, vfp_get_double(state, sd)); + if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert + { + vsd.exponent = (vdd.exponent) | 0x80; + } + else + { + vsd.exponent = vdd.exponent & ~0x80; + } + vsd.exponent &= 0xFF; + // vsd.exponent = vdd.exponent >> 3; + vsd.sign = vdd.sign; + vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000; + vfp_put_float(state, vfp_single_pack(&vsd), dn); + return ARMul_DONE; + }*/ + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 10 || CoProc == 11) { +#define VFP_CDP_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_CDP_TRANS + + int exceptions = 0; + if (CoProc == 10) + exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + else + exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + + vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + + return ARMul_DONE; + } + DEBUG("Can't identify %x\n", instr); + return ARMul_CANT; } @@ -301,29 +341,29 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr) /* Miscellaneous functions */ int32_t vfp_get_float(arm_core_t* state, unsigned int reg) { - DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); - return state->ExtReg[reg]; + DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); + return state->ExtReg[reg]; } void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) { - DBG("VFP put float: s%d <= [%08x]\n", reg, val); - state->ExtReg[reg] = val; + DEBUG("VFP put float: s%d <= [%08x]\n", reg, val); + state->ExtReg[reg] = val; } uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) { - uint64_t result; - result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; - DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); - return result; + uint64_t result; + result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; + DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); + return result; } void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) { - DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); - state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); - state->ExtReg[reg*2+1] = (uint32_t) (val>>32); + DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); + state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); + state->ExtReg[reg*2+1] = (uint32_t) (val>>32); } @@ -333,25 +373,25 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) */ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) { - int si_code = 0; + int si_code = 0; - vfpdebug("VFP: raising exceptions %08x\n", exceptions); + vfpdebug("VFP: raising exceptions %08x\n", exceptions); - if (exceptions == VFP_EXCEPTION_ERROR) { - DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst); - exit(-1); - return; - } + if (exceptions == VFP_EXCEPTION_ERROR) { + DEBUG("unhandled bounce %x\n", inst); + exit(-1); + return; + } - /* - * If any of the status flags are set, update the FPSCR. - * Comparison instructions always return at least one of - * these flags set. - */ - if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) - fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); + /* + * If any of the status flags are set, update the FPSCR. + * Comparison instructions always return at least one of + * these flags set. + */ + if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) + fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); - fpscr |= exceptions; + fpscr |= exceptions; - state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; + state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; } diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index ed627d41f..7256701f3 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h @@ -88,21 +88,21 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); /* MRC */ -inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); -inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); -inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); -inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); -inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); +void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); +void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); +void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); +void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); +void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); /* MCR */ -inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); +void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); /* STC */ -inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); -inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); -inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); /* LDC */ -inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); -inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); -inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); +int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); +int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); +int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); #ifdef __cplusplus } diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 5076e59f7..b1949603a 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -44,7 +44,7 @@ #define pr_info //printf #define pr_debug //printf -static u32 vfp_fls(int x); +static u32 fls(ARMword x); #define do_div(n, base) {n/=base;} /* From vfpinstr.h */ @@ -502,7 +502,7 @@ struct op { u32 flags; }; -static u32 vfp_fls(int x) +static u32 fls(ARMword x) { int r = 32; @@ -532,4 +532,9 @@ static u32 vfp_fls(int x) } +u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); +u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); +u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); +u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr); + #endif diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 13411ad80..765c1f6bc 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -56,163 +56,291 @@ #include "core/arm/skyeye_common/vfp/asm_vfp.h" static struct vfp_double vfp_double_default_qnan = { - //.exponent = 2047, - //.sign = 0, - //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN, + 2047, + 0, + VFP_DOUBLE_SIGNIFICAND_QNAN, }; static void vfp_double_dump(const char *str, struct vfp_double *d) { - pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", - str, d->sign != 0, d->exponent, d->significand); + pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", + str, d->sign != 0, d->exponent, d->significand); } static void vfp_double_normalise_denormal(struct vfp_double *vd) { - int bits = 31 - vfp_fls(vd->significand >> 32); - if (bits == 31) - bits = 63 - vfp_fls(vd->significand); + int bits = 31 - fls((ARMword)(vd->significand >> 32)); + if (bits == 31) + bits = 63 - fls((ARMword)vd->significand); - vfp_double_dump("normalise_denormal: in", vd); + vfp_double_dump("normalise_denormal: in", vd); - if (bits) { - vd->exponent -= bits - 1; - vd->significand <<= bits; - } + if (bits) { + vd->exponent -= bits - 1; + vd->significand <<= bits; + } - vfp_double_dump("normalise_denormal: out", vd); + vfp_double_dump("normalise_denormal: out", vd); } -u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) +u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) { - u64 significand, incr; - int exponent, shift, underflow; - u32 rmode; - - vfp_double_dump("pack: in", vd); - - /* - * Infinities and NaNs are a special case. - */ - if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vd->significand == 0) { - vd->exponent = 0; - goto pack; - } - - exponent = vd->exponent; - significand = vd->significand; - - shift = 32 - vfp_fls(significand >> 32); - if (shift == 32) - shift = 64 - vfp_fls(significand); - if (shift) { - exponent -= shift; - significand <<= shift; - } + u64 significand, incr; + int exponent, shift, underflow; + u32 rmode; + + vfp_double_dump("pack: in", vd); + + /* + * Infinities and NaNs are a special case. + */ + if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vd->significand == 0) { + vd->exponent = 0; + goto pack; + } + + exponent = vd->exponent; + significand = vd->significand; + + shift = 32 - fls((ARMword)(significand >> 32)); + if (shift == 32) + shift = 64 - fls((ARMword)significand); + if (shift) { + exponent -= shift; + significand <<= shift; + } #if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: normalised", vd); + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: normalised", vd); #endif - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright64jamming(significand, -exponent); - exponent = 0; + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright64jamming(significand, -exponent); + exponent = 0; #if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: tiny number", vd); + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: tiny number", vd); #endif - if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) - underflow = 0; - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1ULL << VFP_DOUBLE_LOW_BITS; - if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) - incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; - - pr_debug("VFP: rounding increment = 0x%08llx\n", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; + if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1ULL << VFP_DOUBLE_LOW_BITS; + if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) + incr -= 1; + } + else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } + else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) + incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08llx\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; #if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: overflow", vd); + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: overflow", vd); #endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 2046) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vd->exponent = 2045; - vd->significand = 0x7fffffffffffffffULL; - } else { - vd->exponent = 2047; /* infinity */ - vd->significand = 0; - } - } else { - if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x8000000000000000ULL) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vd->exponent = exponent; - vd->significand = significand >> 1; - } - + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 2046) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vd->exponent = 2045; + vd->significand = 0x7fffffffffffffffULL; + } + else { + vd->exponent = 2047; /* infinity */ + vd->significand = 0; + } + } + else { + if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x8000000000000000ULL) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vd->exponent = exponent; + vd->significand = significand >> 1; + } pack: - vfp_double_dump("pack: final", vd); - { - s64 d = vfp_double_pack(vd); - pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, - dd, d, exceptions); - vfp_put_double(state, d, dd); - } - return exceptions; + return 0; +} + +u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) +{ + u64 significand, incr; + int exponent, shift, underflow; + u32 rmode; + + vfp_double_dump("pack: in", vd); + + /* + * Infinities and NaNs are a special case. + */ + if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vd->significand == 0) { + vd->exponent = 0; + goto pack; + } + + exponent = vd->exponent; + significand = vd->significand; + + shift = 32 - fls((ARMword)(significand >> 32)); + if (shift == 32) + shift = 64 - fls((ARMword)significand); + if (shift) { + exponent -= shift; + significand <<= shift; + } + +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: normalised", vd); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright64jamming(significand, -exponent); + exponent = 0; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: tiny number", vd); +#endif + if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1ULL << VFP_DOUBLE_LOW_BITS; + if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) + incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08llx\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: overflow", vd); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 2046) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vd->exponent = 2045; + vd->significand = 0x7fffffffffffffffULL; + } else { + vd->exponent = 2047; /* infinity */ + vd->significand = 0; + } + } else { + if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x8000000000000000ULL) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vd->exponent = exponent; + vd->significand = significand >> 1; + } + +pack: + vfp_double_dump("pack: final", vd); + { + s64 d = vfp_double_pack(vd); + pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, + dd, d, exceptions); + vfp_put_double(state, d, dd); + } + return exceptions; } /* @@ -221,43 +349,43 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, */ static u32 vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) + struct vfp_double *vdm, u32 fpscr) { - struct vfp_double *nan; - int tn, tm = 0; - - tn = vfp_double_type(vdn); - - if (vdm) - tm = vfp_double_type(vdm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_double_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vdn; - else - nan = vdm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - } - - *vdd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; + struct vfp_double *nan; + int tn, tm = 0; + + tn = vfp_double_type(vdn); + + if (vdm) + tm = vfp_double_type(vdm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_double_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vdn; + else + nan = vdm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + } + + *vdd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; } /* @@ -265,108 +393,108 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, */ static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); - return 0; + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); + return 0; } static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_get_double(state, dm), dd); - return 0; + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_get_double(state, dm), dd); + return 0; } static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); - return 0; + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); + return 0; } static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - struct vfp_double vdm, vdd, *vdp; - int ret, tm; - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - tm = vfp_double_type(&vdm); - if (tm & (VFP_NAN|VFP_INFINITY)) { - vdp = &vdd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); - else if (vdm.sign == 0) { - sqrt_copy: - vdp = &vdm; - ret = 0; - } else { - sqrt_invalid: - vdp = &vfp_double_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_double(state, vfp_double_pack(vdp), dd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * sqrt(<0) = invalid - */ - if (vdm.sign) - goto sqrt_invalid; - - vfp_double_dump("sqrt", &vdm); - - /* - * Estimate the square root. - */ - vdd.sign = 0; - vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; - vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; - - vfp_double_dump("sqrt estimate1", &vdd); - - vdm.significand >>= 1 + (vdm.exponent & 1); - vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); - - vfp_double_dump("sqrt estimate2", &vdd); - - /* - * And now adjust. - */ - if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { - if (vdd.significand < 2) { - vdd.significand = ~0ULL; - } else { - u64 termh, terml, remh, reml; - vdm.significand <<= 2; - mul64to128(&termh, &terml, vdd.significand, vdd.significand); - sub128(&remh, &reml, vdm.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - shift64left(&termh, &terml, vdd.significand); - terml |= 1; - add128(&remh, &reml, remh, reml, termh, terml); - } - vdd.significand |= (remh | reml) != 0; - } - } - vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); + pr_debug("In %s\n", __FUNCTION__); + vfp_double vdm, vdd, *vdp; + int ret, tm; + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + tm = vfp_double_type(&vdm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + vdp = &vdd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); + else if (vdm.sign == 0) { +sqrt_copy: + vdp = &vdm; + ret = 0; + } else { +sqrt_invalid: + vdp = &vfp_double_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_double(state, vfp_double_pack(vdp), dd); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * sqrt(<0) = invalid + */ + if (vdm.sign) + goto sqrt_invalid; + + vfp_double_dump("sqrt", &vdm); + + /* + * Estimate the square root. + */ + vdd.sign = 0; + vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; + vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; + + vfp_double_dump("sqrt estimate1", &vdd); + + vdm.significand >>= 1 + (vdm.exponent & 1); + vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); + + vfp_double_dump("sqrt estimate2", &vdd); + + /* + * And now adjust. + */ + if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { + if (vdd.significand < 2) { + vdd.significand = ~0ULL; + } else { + u64 termh, terml, remh, reml; + vdm.significand <<= 2; + mul64to128(&termh, &terml, vdd.significand, vdd.significand); + sub128(&remh, &reml, vdm.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + shift64left(&termh, &terml, vdd.significand); + terml |= 1; + add128(&remh, &reml, remh, reml, termh, terml); + } + vdd.significand |= (remh | reml) != 0; + } + } + vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); } /* @@ -377,319 +505,362 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 */ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) { - s64 d, m; - u32 ret = 0; - - pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); - m = vfp_get_double(state, dm); - if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - d = vfp_get_double(state, dd); - if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); - if (d == m || vfp_double_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_Z | FPSCR_C; - //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); - } else if (vfp_double_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_double_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_N; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_C; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_N; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_C; - } - } - pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); - - return ret; + s64 d, m; + u32 ret = 0; + + pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); + m = vfp_get_double(state, dm); + if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + d = vfp_get_double(state, dd); + if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); + if (d == m || vfp_double_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); + } else if (vfp_double_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_double_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); + + return ret; } static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 0, dm, fpscr); + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 0, dm, fpscr); } static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 1, dm, fpscr); + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 1, dm, fpscr); } static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); } static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); +} + +u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only +{ + struct vfp_single vsd; + int tm; + u32 exceptions = 0; + + pr_debug("In %s\n", __FUNCTION__); + + tm = vfp_double_type(dm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(dm); + + vsd.sign = dm->sign; + vsd.significand = vfp_hi64to32jamming(dm->significand); + + /* + * If we have an infinity or a NaN, the exponent must be 255 + */ + if (tm & (VFP_INFINITY | VFP_NAN)) { + vsd.exponent = 255; + if (tm == VFP_QNAN) + vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + goto pack_nan; + } + else if (tm & VFP_ZERO) + vsd.exponent = 0; + else + vsd.exponent = dm->exponent - (1023 - 127); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); + +pack_nan: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; } static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - struct vfp_single vsd; - int tm; - u32 exceptions = 0; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - tm = vfp_double_type(&vdm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - vsd.sign = vdm.sign; - vsd.significand = vfp_hi64to32jamming(vdm.significand); - - /* - * If we have an infinity or a NaN, the exponent must be 255 - */ - if (tm & (VFP_INFINITY|VFP_NAN)) { - vsd.exponent = 255; - if (tm == VFP_QNAN) - vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vsd.exponent = 0; - else - vsd.exponent = vdm.exponent - (1023 - 127); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); - - pack_nan: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; + struct vfp_double vdm; + struct vfp_single vsd; + int tm; + u32 exceptions = 0; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + tm = vfp_double_type(&vdm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + vsd.sign = vdm.sign; + vsd.significand = vfp_hi64to32jamming(vdm.significand); + + /* + * If we have an infinity or a NaN, the exponent must be 255 + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vsd.exponent = 255; + if (tm == VFP_QNAN) + vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vsd.exponent = 0; + else + vsd.exponent = vdm.exponent - (1023 - 127); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); + +pack_nan: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; } static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); + struct vfp_double vdm; + u32 m = vfp_get_float(state, dm); - pr_debug("In %s\n", __FUNCTION__); - vdm.sign = 0; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = (u64)m; + pr_debug("In %s\n", __FUNCTION__); + vdm.sign = 0; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = (u64)m; - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); } static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); + struct vfp_double vdm; + u32 m = vfp_get_float(state, dm); - pr_debug("In %s\n", __FUNCTION__); - vdm.sign = (m & 0x80000000) >> 16; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = vdm.sign ? -m : m; + pr_debug("In %s\n", __FUNCTION__); + vdm.sign = (m & 0x80000000) >> 16; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = vdm.sign ? -m : m; - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); } static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - /* - * Do we have a denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vdm.sign = 0; - - if (vdm.exponent >= 1023 + 32) { - d = vdm.sign ? 0 : 0xffffffff; - exceptions = FPSCR_IOC; - } else if (vdm.exponent >= 1023 - 1) { - int shift = 1023 + 63 - vdm.exponent; - u64 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (vdm.significand << 1) >> shift; - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vdm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } - } - } - - pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + /* + * Do we have a denormalised number? + */ + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vdm.sign = 0; + + if (vdm.exponent >= 1023 + 32) { + d = vdm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; + u64 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (ARMword)((vdm.significand << 1) >> shift); + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, d, sd); + + return exceptions; } static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); } static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - vfp_double_dump("VDM", &vdm); - - /* - * Do we have denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023 + 32) { - d = 0x7fffffff; - if (vdm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023 - 1) { - int shift = 1023 + 63 - vdm.exponent; /* 58 */ - u64 rem, incr = 0; - - d = (vdm.significand << 1) >> shift; - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > 0x7fffffff + (vdm.sign != 0)) { - d = 0x7fffffff + (vdm.sign != 0); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vdm.sign) - d = -d; - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) - d = -1; - } - } - - pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + vfp_double_dump("VDM", &vdm); + + /* + * Do we have denormalised number? + */ + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 + 32) { + d = 0x7fffffff; + if (vdm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; /* 58 */ + u64 rem, incr = 0; + + d = (ARMword)((vdm.significand << 1) >> shift); + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > (0x7fffffff + (vdm.sign != 0))) { + d = (0x7fffffff + (vdm.sign != 0)); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vdm.sign) + d = -d; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, (s32)d, sd); + + return exceptions; } static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); } static struct op fops_ext[] = { @@ -728,197 +899,195 @@ static struct op fops_ext[] = { static u32 vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) + struct vfp_double *vdm, u32 fpscr) { - struct vfp_double *vdp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_double_type(vdn); - tm = vfp_double_type(vdm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vdn->sign ^ vdm->sign) { - /* - * different signs -> invalid - */ - exceptions = FPSCR_IOC; - vdp = &vfp_double_default_qnan; - } else { - /* - * same signs -> valid - */ - vdp = vdn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vdp = vdn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - } - *vdd = *vdp; - return exceptions; + struct vfp_double *vdp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_double_type(vdn); + tm = vfp_double_type(vdm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vdn->sign ^ vdm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vdp = &vfp_double_default_qnan; + } else { + /* + * same signs -> valid + */ + vdp = vdn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vdp = vdn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + } + *vdd = *vdp; + return exceptions; } -static u32 -vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) +u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr) { - u32 exp_diff; - u64 m_sig; - - if (vdn->significand & (1ULL << 63) || - vdm->significand & (1ULL << 63)) { - pr_info("VFP: bad FP values\n"); - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - struct vfp_double *t = vdn; - vdn = vdm; - vdm = t; - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vdn->exponent == 2047) - return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); - - /* - * We have two proper numbers, where 'vdn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vdd = *vdn; - - /* - * Align 'm' with the result. - */ - exp_diff = vdn->exponent - vdm->exponent; - m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vdn->sign ^ vdm->sign) { - m_sig = vdn->significand - m_sig; - if ((s64)m_sig < 0) { - vdd->sign = vfp_sign_negate(vdd->sign); - m_sig = -m_sig; - } else if (m_sig == 0) { - vdd->sign = (fpscr & FPSCR_RMODE_MASK) == - FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig += vdn->significand; - } - vdd->significand = m_sig; - - return 0; + u32 exp_diff; + u64 m_sig; + + if (vdn->significand & (1ULL << 63) || + vdm->significand & (1ULL << 63)) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vdn->exponent == 2047) + return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); + + /* + * We have two proper numbers, where 'vdn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vdd = *vdn; + + /* + * Align 'm' with the result. + */ + exp_diff = vdn->exponent - vdm->exponent; + m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vdn->sign ^ vdm->sign) { + m_sig = vdn->significand - m_sig; + if ((s64)m_sig < 0) { + vdd->sign = vfp_sign_negate(vdd->sign); + m_sig = -m_sig; + } else if (m_sig == 0) { + vdd->sign = (fpscr & FPSCR_RMODE_MASK) == + FPSCR_ROUND_MINUSINF ? 0x8000 : 0; + } + } else { + m_sig += vdn->significand; + } + vdd->significand = m_sig; + + return 0; } -static u32 +u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) + struct vfp_double *vdm, u32 fpscr) { - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - struct vfp_double *t = vdn; - vdn = vdm; - vdm = t; - pr_debug("VFP: swapping M <-> N\n"); - } - - vdd->sign = vdn->sign ^ vdm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vdn->exponent == 2047) { - if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - if ((vdm->exponent | vdm->significand) == 0) { - *vdd = vfp_double_default_qnan; - return FPSCR_IOC; - } - vdd->exponent = vdn->exponent; - vdd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vdm->exponent | vdm->significand) == 0) { - vdd->exponent = 0; - vdd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason - * as the addition case - though this time we have +1 from - * each input operand. - */ - vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; - vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); - - vfp_double_dump("VDD", vdd); - return 0; + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vdd->sign = vdn->sign ^ vdm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vdn->exponent == 2047) { + if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + if ((vdm->exponent | vdm->significand) == 0) { + *vdd = vfp_double_default_qnan; + return FPSCR_IOC; + } + vdd->exponent = vdn->exponent; + vdd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vdm->exponent | vdm->significand) == 0) { + vdd->exponent = 0; + vdd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason + * as the addition case - though this time we have +1 from + * each input operand. + */ + vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; + vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); + + vfp_double_dump("VDD", vdd); + return 0; } #define NEG_MULTIPLY (1 << 0) #define NEG_SUBTRACT (1 << 1) static u32 -vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) +vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func) { - struct vfp_double vdd, vdp, vdn, vdm; - u32 exceptions; + struct vfp_double vdd, vdp, vdn, vdm; + u32 exceptions; - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); - exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); - if (negate & NEG_MULTIPLY) - vdp.sign = vfp_sign_negate(vdp.sign); + exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); + if (negate & NEG_MULTIPLY) + vdp.sign = vfp_sign_negate(vdp.sign); - vfp_double_unpack(&vdn, vfp_get_double(state, dd)); - if (negate & NEG_SUBTRACT) - vdn.sign = vfp_sign_negate(vdn.sign); + vfp_double_unpack(&vdn, vfp_get_double(state, dd)); + if (negate & NEG_SUBTRACT) + vdn.sign = vfp_sign_negate(vdn.sign); - exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); + exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); } /* @@ -930,8 +1099,8 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f */ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); } /* @@ -939,8 +1108,8 @@ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr */ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); } /* @@ -948,8 +1117,8 @@ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpsc */ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); } /* @@ -957,8 +1126,8 @@ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr */ static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); } /* @@ -966,20 +1135,20 @@ static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpsc */ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions; + struct vfp_double vdd, vdn, vdm; + u32 exceptions; - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); - exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); } /* @@ -987,22 +1156,22 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr */ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions; + struct vfp_double vdd, vdn, vdm; + u32 exceptions; - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); - exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - vdd.sign = vfp_sign_negate(vdd.sign); + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + vdd.sign = vfp_sign_negate(vdd.sign); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); } /* @@ -1010,21 +1179,21 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc */ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions; + struct vfp_double vdd, vdn, vdm; + u32 exceptions; - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); - exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); } /* @@ -1032,26 +1201,26 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr */ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions; + struct vfp_double vdd, vdn, vdm; + u32 exceptions; - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); - /* - * Subtraction is like addition, but with a negated operand. - */ - vdm.sign = vfp_sign_negate(vdm.sign); + /* + * Subtraction is like addition, but with a negated operand. + */ + vdm.sign = vfp_sign_negate(vdm.sign); - exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); } /* @@ -1059,120 +1228,120 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr */ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - int tm, tn; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - vdd.sign = vdn.sign ^ vdm.sign; - - tn = vfp_double_type(&vdn); - tm = vfp_double_type(&vdm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vdn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vdm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY|VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exceptions - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdn); - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; - vdm.significand <<= 1; - if (vdm.significand <= (2 * vdn.significand)) { - vdn.significand >>= 1; - vdd.exponent++; - } - vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); - if ((vdd.significand & 0x1ff) <= 2) { - u64 termh, terml, remh, reml; - mul64to128(&termh, &terml, vdm.significand, vdd.significand); - sub128(&remh, &reml, vdn.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - add128(&remh, &reml, remh, reml, 0, vdm.significand); - } - vdd.significand |= (reml != 0); - } - return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); - - vdn_nan: - exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); - pack: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; - - vdm_nan: - exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); - goto pack; - - zero: - vdd.exponent = 0; - vdd.significand = 0; - goto pack; - - divzero: - exceptions = FPSCR_DZC; - infinity: - vdd.exponent = 2047; - vdd.significand = 0; - goto pack; - - invalid: - vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); - return FPSCR_IOC; + struct vfp_double vdd, vdn, vdm; + u32 exceptions = 0; + int tm, tn; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + vdd.sign = vdn.sign ^ vdm.sign; + + tn = vfp_double_type(&vdn); + tm = vfp_double_type(&vdm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vdn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vdm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exceptions + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdn); + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; + vdm.significand <<= 1; + if (vdm.significand <= (2 * vdn.significand)) { + vdn.significand >>= 1; + vdd.exponent++; + } + vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); + if ((vdd.significand & 0x1ff) <= 2) { + u64 termh, terml, remh, reml; + mul64to128(&termh, &terml, vdm.significand, vdd.significand); + sub128(&remh, &reml, vdn.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + add128(&remh, &reml, remh, reml, 0, vdm.significand); + } + vdd.significand |= (reml != 0); + } + return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); + +vdn_nan: + exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); +pack: + vfp_put_double(state, vfp_double_pack(&vdd), dd); + return exceptions; + +vdm_nan: + exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); + goto pack; + +zero: + vdd.exponent = 0; + vdd.significand = 0; + goto pack; + +divzero: + exceptions = FPSCR_DZC; +infinity: + vdd.exponent = 2047; + vdd.significand = 0; + goto pack; + +invalid: + vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); + return FPSCR_IOC; } static struct op fops[] = { - { vfp_double_fmac, 0 }, - { vfp_double_fmsc, 0 }, - { vfp_double_fmul, 0 }, - { vfp_double_fadd, 0 }, - { vfp_double_fnmac, 0 }, - { vfp_double_fnmsc, 0 }, - { vfp_double_fnmul, 0 }, - { vfp_double_fsub, 0 }, - { vfp_double_fdiv, 0 }, + { vfp_double_fmac, 0 }, + { vfp_double_fmsc, 0 }, + { vfp_double_fmul, 0 }, + { vfp_double_fadd, 0 }, + { vfp_double_fnmac, 0 }, + { vfp_double_fnmsc, 0 }, + { vfp_double_fnmul, 0 }, + { vfp_double_fsub, 0 }, + { vfp_double_fdiv, 0 }, }; #define FREG_BANK(x) ((x) & 0x0c) @@ -1180,84 +1349,84 @@ static struct op fops[] = { u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int dn = vfp_get_dn(inst); - unsigned int dm; - unsigned int vecitr, veclen, vecstride; - struct op *fop; - - pr_debug("In %s\n", __FUNCTION__); - vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtds takes an sN register number as destination, not dN. - * It also always operates on scalars. - */ - if (fop->flags & OP_SD) - dest = vfp_get_sd(inst); - else - dest = vfp_get_dd(inst); - - /* - * f[us]ito takes a sN operand, not a dN operand. - */ - if (fop->flags & OP_SM) - dm = vfp_get_sm(inst); - else - dm = vfp_get_dm(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, - (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - u32 except; - char type; - - type = fop->flags & OP_SD ? 's' : 'd'; - if (op == FOP_EXT) - pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", - vecitr >> FPSCR_LENGTH_BIT, - type, dest, dn, dm); - else - pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", - vecitr >> FPSCR_LENGTH_BIT, - type, dest, dn, FOP_TO_IDX(op), dm); - - except = fop->fn(state, dest, dn, dm, fpscr); - pr_debug("VFP: itr%d: exceptions=%08x\n", - vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); - dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); - if (FREG_BANK(dm) != 0) - dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); - } - return exceptions; - - invalid: - return ~0; + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int dest; + unsigned int dn = vfp_get_dn(inst); + unsigned int dm; + unsigned int vecitr, veclen, vecstride; + struct op *fop; + + pr_debug("In %s\n", __FUNCTION__); + vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); + + fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; + + /* + * fcvtds takes an sN register number as destination, not dN. + * It also always operates on scalars. + */ + if (fop->flags & OP_SD) + dest = vfp_get_sd(inst); + else + dest = vfp_get_dd(inst); + + /* + * f[us]ito takes a sN operand, not a dN operand. + */ + if (fop->flags & OP_SM) + dm = vfp_get_sm(inst); + else + dm = vfp_get_dm(inst); + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) + veclen = 0; + else + veclen = fpscr & FPSCR_LENGTH_MASK; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + if (!fop->fn) { + printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); + goto invalid; + } + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + u32 except; + char type; + + type = fop->flags & OP_SD ? 's' : 'd'; + if (op == FOP_EXT) + pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + type, dest, dn, dm); + else + pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + type, dest, dn, FOP_TO_IDX(op), dm); + + except = fop->fn(state, dest, dn, dm, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); + dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); + if (FREG_BANK(dm) != 0) + dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); + } + return exceptions; + +invalid: + return ~0; } diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 8bcbd4fe9..07d0c1f44 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -56,167 +56,167 @@ #include "core/arm/skyeye_common/vfp/vfp.h" static struct vfp_single vfp_single_default_qnan = { - //.exponent = 255, - //.sign = 0, - //.significand = VFP_SINGLE_SIGNIFICAND_QNAN, + 255, + 0, + VFP_SINGLE_SIGNIFICAND_QNAN, }; static void vfp_single_dump(const char *str, struct vfp_single *s) { - pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", - str, s->sign != 0, s->exponent, s->significand); + pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", + str, s->sign != 0, s->exponent, s->significand); } static void vfp_single_normalise_denormal(struct vfp_single *vs) { - int bits = 31 - vfp_fls(vs->significand); + int bits = 31 - fls(vs->significand); - vfp_single_dump("normalise_denormal: in", vs); + vfp_single_dump("normalise_denormal: in", vs); - if (bits) { - vs->exponent -= bits - 1; - vs->significand <<= bits; - } + if (bits) { + vs->exponent -= bits - 1; + vs->significand <<= bits; + } - vfp_single_dump("normalise_denormal: out", vs); + vfp_single_dump("normalise_denormal: out", vs); } u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) { - u32 significand, incr, rmode; - int exponent, shift, underflow; - - vfp_single_dump("pack: in", vs); - - /* - * Infinities and NaNs are a special case. - */ - if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vs->significand == 0) { - vs->exponent = 0; - goto pack; - } - - exponent = vs->exponent; - significand = vs->significand; - - /* - * Normalise first. Note that we shift the significand up to - * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least - * significant bit. - */ - shift = 32 - vfp_fls(significand); - if (shift < 32 && shift) { - exponent -= shift; - significand <<= shift; - } + u32 significand, incr, rmode; + int exponent, shift, underflow; + + vfp_single_dump("pack: in", vs); + + /* + * Infinities and NaNs are a special case. + */ + if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vs->significand == 0) { + vs->exponent = 0; + goto pack; + } + + exponent = vs->exponent; + significand = vs->significand; + + /* + * Normalise first. Note that we shift the significand up to + * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least + * significant bit. + */ + shift = 32 - fls(significand); + if (shift < 32 && shift) { + exponent -= shift; + significand <<= shift; + } #if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: normalised", vs); + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: normalised", vs); #endif - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright32jamming(significand, -exponent); - exponent = 0; + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright32jamming(significand, -exponent); + exponent = 0; #if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: tiny number", vs); + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: tiny number", vs); #endif - if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) - underflow = 0; - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1 << VFP_SINGLE_LOW_BITS; - if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) - incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; - - pr_debug("VFP: rounding increment = 0x%08x\n", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; + if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1 << VFP_SINGLE_LOW_BITS; + if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) + incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08x\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; #if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: overflow", vs); + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: overflow", vs); #endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 254) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vs->exponent = 253; - vs->significand = 0x7fffffff; - } else { - vs->exponent = 255; /* infinity */ - vs->significand = 0; - } - } else { - if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x80000000) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vs->exponent = exponent; - vs->significand = significand >> 1; - } - - pack: - vfp_single_dump("pack: final", vs); - { - s32 d = vfp_single_pack(vs); + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 254) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vs->exponent = 253; + vs->significand = 0x7fffffff; + } else { + vs->exponent = 255; /* infinity */ + vs->significand = 0; + } + } else { + if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x80000000) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vs->exponent = exponent; + vs->significand = significand >> 1; + } + +pack: + vfp_single_dump("pack: final", vs); + { + s32 d = vfp_single_pack(vs); #if 1 - pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, - sd, d, exceptions); + pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, + sd, d, exceptions); #endif - vfp_put_float(state, d, sd); - } + vfp_put_float(state, d, sd); + } - return exceptions; + return exceptions; } /* @@ -225,43 +225,43 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, */ static u32 vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) + struct vfp_single *vsm, u32 fpscr) { - struct vfp_single *nan; - int tn, tm = 0; - - tn = vfp_single_type(vsn); - - if (vsm) - tm = vfp_single_type(vsm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_single_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vsn; - else - nan = vsm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - } - - *vsd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; + struct vfp_single *nan; + int tn, tm = 0; + + tn = vfp_single_type(vsn); + + if (vsm) + tm = vfp_single_type(vsm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_single_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vsn; + else + nan = vsm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + } + + *vsd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; } @@ -270,140 +270,140 @@ vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, */ static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, vfp_single_packed_abs(m), sd); - return 0; + vfp_put_float(state, vfp_single_packed_abs(m), sd); + return 0; } static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, m, sd); - return 0; + vfp_put_float(state, m, sd); + return 0; } static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, vfp_single_packed_negate(m), sd); - return 0; + vfp_put_float(state, vfp_single_packed_negate(m), sd); + return 0; } static const u16 sqrt_oddadjust[] = { - 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, - 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 + 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, + 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 }; static const u16 sqrt_evenadjust[] = { - 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, - 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 + 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, + 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 }; u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) { - int index; - u32 z, a; - - if ((significand & 0xc0000000) != 0x40000000) { - pr_debug("VFP: estimate_sqrt: invalid significand\n"); - } - - a = significand << 1; - index = (a >> 27) & 15; - if (exponent & 1) { - z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; - z = ((a / z) << 14) + (z << 15); - a >>= 1; - } else { - z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; - z = a / z + z; - z = (z >= 0x20000) ? 0xffff8000 : (z << 15); - if (z <= a) - return (s32)a >> 1; - } - { - u64 v = (u64)a << 31; - do_div(v, z); - return v + (z >> 1); - } + int index; + u32 z, a; + + if ((significand & 0xc0000000) != 0x40000000) { + pr_debug("VFP: estimate_sqrt: invalid significand\n"); + } + + a = significand << 1; + index = (a >> 27) & 15; + if (exponent & 1) { + z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; + z = ((a / z) << 14) + (z << 15); + a >>= 1; + } else { + z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; + z = a / z + z; + z = (z >= 0x20000) ? 0xffff8000 : (z << 15); + if (z <= a) + return (s32)a >> 1; + } + { + u64 v = (u64)a << 31; + do_div(v, z); + return (u32)(v + (z >> 1)); + } } static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm, vsd, *vsp; - int ret, tm; - - vfp_single_unpack(&vsm, m); - tm = vfp_single_type(&vsm); - if (tm & (VFP_NAN|VFP_INFINITY)) { - vsp = &vsd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); - else if (vsm.sign == 0) { - sqrt_copy: - vsp = &vsm; - ret = 0; - } else { - sqrt_invalid: - vsp = &vfp_single_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_float(state, vfp_single_pack(vsp), sd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * sqrt(<0) = invalid - */ - if (vsm.sign) - goto sqrt_invalid; - - vfp_single_dump("sqrt", &vsm); - - /* - * Estimate the square root. - */ - vsd.sign = 0; - vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; - vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; - - vfp_single_dump("sqrt estimate", &vsd); - - /* - * And now adjust. - */ - if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { - if (vsd.significand < 2) { - vsd.significand = 0xffffffff; - } else { - u64 term; - s64 rem; - vsm.significand <<= !(vsm.exponent & 1); - term = (u64)vsd.significand * vsd.significand; - rem = ((u64)vsm.significand << 32) - term; - - pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); - - while (rem < 0) { - vsd.significand -= 1; - rem += ((u64)vsd.significand << 1) | 1; - } - vsd.significand |= rem != 0; - } - } - vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); + struct vfp_single vsm, vsd, *vsp; + int ret, tm; + + vfp_single_unpack(&vsm, m); + tm = vfp_single_type(&vsm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + vsp = &vsd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); + else if (vsm.sign == 0) { +sqrt_copy: + vsp = &vsm; + ret = 0; + } else { +sqrt_invalid: + vsp = &vfp_single_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_float(state, vfp_single_pack(vsp), sd); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * sqrt(<0) = invalid + */ + if (vsm.sign) + goto sqrt_invalid; + + vfp_single_dump("sqrt", &vsm); + + /* + * Estimate the square root. + */ + vsd.sign = 0; + vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; + vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; + + vfp_single_dump("sqrt estimate", &vsd); + + /* + * And now adjust. + */ + if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { + if (vsd.significand < 2) { + vsd.significand = 0xffffffff; + } else { + u64 term; + s64 rem; + vsm.significand <<= !(vsm.exponent & 1); + term = (u64)vsd.significand * vsd.significand; + rem = ((u64)vsm.significand << 32) - term; + + pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); + + while (rem < 0) { + vsd.significand -= 1; + rem += ((u64)vsd.significand << 1) | 1; + } + vsd.significand |= rem != 0; + } + } + vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); } /* @@ -414,305 +414,346 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f */ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) { - s32 d; - u32 ret = 0; - - d = vfp_get_float(state, sd); - if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - if (d == m || vfp_single_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_Z | FPSCR_C; - } else if (vfp_single_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_single_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_N; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_C; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_N; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_C; - } - } - return ret; + s32 d; + u32 ret = 0; + + d = vfp_get_float(state, sd); + if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + if (d == m || vfp_single_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + } else if (vfp_single_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_single_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + return ret; } static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 0, m, fpscr); + return vfp_compare(state, sd, 0, m, fpscr); } static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 1, m, fpscr); + return vfp_compare(state, sd, 1, m, fpscr); } static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 0, 0, fpscr); + return vfp_compare(state, sd, 0, 0, fpscr); } static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 1, 0, fpscr); + return vfp_compare(state, sd, 1, 0, fpscr); +} + +static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only +{ + struct vfp_single vsm; + struct vfp_double vdd; + int tm; + u32 exceptions = 0; + + vfp_single_unpack(&vsm, m); + + tm = vfp_single_type(&vsm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + vdd.sign = vsm.sign; + vdd.significand = (u64)vsm.significand << 32; + + /* + * If we have an infinity or NaN, the exponent must be 2047. + */ + if (tm & (VFP_INFINITY | VFP_NAN)) { + vdd.exponent = 2047; + if (tm == VFP_QNAN) + vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + goto pack_nan; + } + else if (tm & VFP_ZERO) + vdd.exponent = 0; + else + vdd.exponent = vsm.exponent + (1023 - 127); +pack_nan: + vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd"); + return vfp_double_pack(&vdd); } static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - struct vfp_double vdd; - int tm; - u32 exceptions = 0; - - vfp_single_unpack(&vsm, m); - - tm = vfp_single_type(&vsm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - vdd.sign = vsm.sign; - vdd.significand = (u64)vsm.significand << 32; - - /* - * If we have an infinity or NaN, the exponent must be 2047. - */ - if (tm & (VFP_INFINITY|VFP_NAN)) { - vdd.exponent = 2047; - if (tm == VFP_QNAN) - vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vdd.exponent = 0; - else - vdd.exponent = vsm.exponent + (1023 - 127); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); - - pack_nan: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; + struct vfp_single vsm; + struct vfp_double vdd; + int tm; + u32 exceptions = 0; + + vfp_single_unpack(&vsm, m); + + tm = vfp_single_type(&vsm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + vdd.sign = vsm.sign; + vdd.significand = (u64)vsm.significand << 32; + + /* + * If we have an infinity or NaN, the exponent must be 2047. + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vdd.exponent = 2047; + if (tm == VFP_QNAN) + vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vdd.exponent = 0; + else + vdd.exponent = vsm.exponent + (1023 - 127); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); + +pack_nan: + vfp_put_double(state, vfp_double_pack(&vdd), dd); + return exceptions; } static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vs; + struct vfp_single vs; - vs.sign = 0; - vs.exponent = 127 + 31 - 1; - vs.significand = (u32)m; + vs.sign = 0; + vs.exponent = 127 + 31 - 1; + vs.significand = (u32)m; - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); } static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vs; + struct vfp_single vs; - vs.sign = (m & 0x80000000) >> 16; - vs.exponent = 127 + 31 - 1; - vs.significand = vs.sign ? -m : m; + vs.sign = (m & 0x80000000) >> 16; + vs.exponent = 127 + 31 - 1; + vs.significand = vs.sign ? -m : m; - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); } static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - vfp_single_unpack(&vsm, m); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vsm.sign = 0; - - if (vsm.exponent >= 127 + 32) { - d = vsm.sign ? 0 : 0xffffffff; - exceptions = FPSCR_IOC; - } else if (vsm.exponent >= 127 - 1) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (vsm.significand << 1) >> shift; - rem = vsm.significand << (33 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vsm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } - } - } - - pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + tm = vfp_single_type(&vsm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vsm.sign = 0; + + if (vsm.exponent >= 127 + 32) { + d = vsm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, d, sd); + + return exceptions; } static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); + return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); } static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - vfp_single_unpack(&vsm, m); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (vfp_single_type(&vsm) & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127 + 32) { - /* - * m >= 2^31-2^7: invalid - */ - d = 0x7fffffff; - if (vsm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127 - 1) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* 2^0 <= m <= 2^31-2^7 */ - d = (vsm.significand << 1) >> shift; - rem = vsm.significand << (33 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > 0x7fffffff + (vsm.sign != 0)) { - d = 0x7fffffff + (vsm.sign != 0); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vsm.sign) - d = -d; - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) - d = -1; - } - } - - pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + tm = vfp_single_type(&vsm); + if (vfp_single_type(&vsm) & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 + 32) { + /* + * m >= 2^31-2^7: invalid + */ + d = 0x7fffffff; + if (vsm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* 2^0 <= m <= 2^31-2^7 */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > (0x7fffffffu + (vsm.sign != 0))) { + d = (0x7fffffffu + (vsm.sign != 0)); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vsm.sign) + d = 0-d; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, (s32)d, sd); + + return exceptions; } static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); + return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); } static struct op fops_ext[] = { @@ -752,200 +793,237 @@ static struct op fops_ext[] = { static u32 vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) + struct vfp_single *vsm, u32 fpscr) { - struct vfp_single *vsp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_single_type(vsn); - tm = vfp_single_type(vsm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vsn->sign ^ vsm->sign) { - /* - * different signs -> invalid - */ - exceptions = FPSCR_IOC; - vsp = &vfp_single_default_qnan; - } else { - /* - * same signs -> valid - */ - vsp = vsn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vsp = vsn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - } - *vsd = *vsp; - return exceptions; + struct vfp_single *vsp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_single_type(vsn); + tm = vfp_single_type(vsm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vsn->sign ^ vsm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vsp = &vfp_single_default_qnan; + } else { + /* + * same signs -> valid + */ + vsp = vsn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vsp = vsn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + } + *vsd = *vsp; + return exceptions; } static u32 vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) + struct vfp_single *vsm, u32 fpscr) { - u32 exp_diff, m_sig; - - if (vsn->significand & 0x80000000 || - vsm->significand & 0x80000000) { - pr_info("VFP: bad FP values\n"); - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - struct vfp_single *t = vsn; - vsn = vsm; - vsm = t; - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vsn->exponent == 255) - return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); - - /* - * We have two proper numbers, where 'vsn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vsd = *vsn; - - /* - * Align both numbers. - */ - exp_diff = vsn->exponent - vsm->exponent; - m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vsn->sign ^ vsm->sign) { - m_sig = vsn->significand - m_sig; - if ((s32)m_sig < 0) { - vsd->sign = vfp_sign_negate(vsd->sign); - m_sig = -m_sig; - } else if (m_sig == 0) { - vsd->sign = (fpscr & FPSCR_RMODE_MASK) == - FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig = vsn->significand + m_sig; - } - vsd->significand = m_sig; - - return 0; + u32 exp_diff, m_sig; + + if (vsn->significand & 0x80000000 || + vsm->significand & 0x80000000) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vsn->exponent == 255) + return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); + + /* + * We have two proper numbers, where 'vsn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vsd = *vsn; + + /* + * Align both numbers. + */ + exp_diff = vsn->exponent - vsm->exponent; + m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vsn->sign ^ vsm->sign) { + m_sig = vsn->significand - m_sig; + if ((s32)m_sig < 0) { + vsd->sign = vfp_sign_negate(vsd->sign); + m_sig = 0-m_sig; + } else if (m_sig == 0) { + vsd->sign = (fpscr & FPSCR_RMODE_MASK) == + FPSCR_ROUND_MINUSINF ? 0x8000 : 0; + } + } else { + m_sig = vsn->significand + m_sig; + } + vsd->significand = m_sig; + + return 0; } static u32 vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) { - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - struct vfp_single *t = vsn; - vsn = vsm; - vsm = t; - pr_debug("VFP: swapping M <-> N\n"); - } - - vsd->sign = vsn->sign ^ vsm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vsn->exponent == 255) { - if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - if ((vsm->exponent | vsm->significand) == 0) { - *vsd = vfp_single_default_qnan; - return FPSCR_IOC; - } - vsd->exponent = vsn->exponent; - vsd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vsm->exponent | vsm->significand) == 0) { - vsd->exponent = 0; - vsd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason as - * the addition case - though this time we have +1 from each - * input operand. - */ - vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; - vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); - - vfp_single_dump("VSD", vsd); - return 0; + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vsd->sign = vsn->sign ^ vsm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vsn->exponent == 255) { + if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + if ((vsm->exponent | vsm->significand) == 0) { + *vsd = vfp_single_default_qnan; + return FPSCR_IOC; + } + vsd->exponent = vsn->exponent; + vsd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vsm->exponent | vsm->significand) == 0) { + vsd->exponent = 0; + vsd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason as + * the addition case - though this time we have +1 from each + * input operand. + */ + vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; + vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); + + vfp_single_dump("VSD", vsd); + return 0; } #define NEG_MULTIPLY (1 << 0) #define NEG_SUBTRACT (1 << 1) static u32 -vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) +vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func) { - struct vfp_single vsd, vsp, vsn, vsm; - u32 exceptions; - s32 v; + + { + struct vfp_single vsd, vsp, vsn, vsm; + u32 exceptions; + s32 v; + + + + v = vfp_get_float(state, sn); + pr_debug("VFP: s%u = %08x\n", sn, v); + vfp_single_unpack(&vsn, v); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); + + if (negate & NEG_MULTIPLY) + vsp.sign = vfp_sign_negate(vsp.sign); + + v = vfp_get_float(state, sd); + pr_debug("VFP: s%u = %08x\n", sd, v); + vfp_single_unpack(&vsn, v); + if (negate & NEG_SUBTRACT) + vsn.sign = vfp_sign_negate(vsn.sign); + + exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); + } + + struct vfp_double vsd, vsp, vsn, vsm; + u32 exceptions; + s32 v; + s64 vd; + s64 md; + + v = vfp_get_float(state, sn); + vd = vfp_single_to_doubleintern(state, v, fpscr); + vfp_double_unpack(&vsn, vd); + + md = vfp_single_to_doubleintern(state, m, fpscr); + vfp_double_unpack(&vsm, md); + + exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr); + if (negate & NEG_MULTIPLY) + vsp.sign = vfp_sign_negate(vsp.sign); - v = vfp_get_float(state, sn); - pr_debug("VFP: s%u = %08x\n", sn, v); - vfp_single_unpack(&vsn, v); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); + v = vfp_get_float(state, sd); + vd = vfp_single_to_doubleintern(state, v, fpscr); + vfp_double_unpack(&vsn, vd); - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); + if (negate & NEG_SUBTRACT) + vsn.sign = vfp_sign_negate(vsn.sign); - exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); - if (negate & NEG_MULTIPLY) - vsp.sign = vfp_sign_negate(vsp.sign); + exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr); - v = vfp_get_float(state, sd); - pr_debug("VFP: s%u = %08x\n", sd, v); - vfp_single_unpack(&vsn, v); - if (negate & NEG_SUBTRACT) - vsn.sign = vfp_sign_negate(vsn.sign); + s64 debug = vfp_double_pack(&vsd); - exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); + return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); } /* @@ -957,8 +1035,8 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp */ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); } /* @@ -966,8 +1044,8 @@ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) */ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); } /* @@ -975,8 +1053,8 @@ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr */ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); } /* @@ -984,8 +1062,8 @@ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) */ static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); } /* @@ -993,22 +1071,22 @@ static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr */ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); - exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); } /* @@ -1016,23 +1094,23 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) */ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); - pr_debug("VFP: s%u = %08x\n", sn, n); + pr_debug("VFP: s%u = %08x\n", sn, n); - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); - exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - vsd.sign = vfp_sign_negate(vsd.sign); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + vsd.sign = vfp_sign_negate(vsd.sign); + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); } /* @@ -1040,26 +1118,26 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr */ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); - pr_debug("VFP: s%u = %08x\n", sn, n); + pr_debug("VFP: s%u = %08x\n", sn, n); - /* - * Unpack and normalise denormals. - */ - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); + /* + * Unpack and normalise denormals. + */ + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); - exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); + exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); } /* @@ -1067,11 +1145,11 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) */ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - /* - * Subtraction is addition with one sign inverted. - */ - return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + /* + * Subtraction is addition with one sign inverted. + */ + return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); } /* @@ -1079,107 +1157,107 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) */ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - int tm, tn; - - pr_debug("VFP: s%u = %08x\n", sn, n); - - vfp_single_unpack(&vsn, n); - vfp_single_unpack(&vsm, m); - - vsd.sign = vsn.sign ^ vsm.sign; - - tn = vfp_single_type(&vsn); - tm = vfp_single_type(&vsm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vsn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vsm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY|VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exception - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsn); - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; - vsm.significand <<= 1; - if (vsm.significand <= (2 * vsn.significand)) { - vsn.significand >>= 1; - vsd.exponent++; - } - { - u64 significand = (u64)vsn.significand << 32; - do_div(significand, vsm.significand); - vsd.significand = significand; - } - if ((vsd.significand & 0x3f) == 0) - vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); - - vsn_nan: - exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); - pack: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; - - vsm_nan: - exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); - goto pack; - - zero: - vsd.exponent = 0; - vsd.significand = 0; - goto pack; - - divzero: - exceptions = FPSCR_DZC; - infinity: - vsd.exponent = 255; - vsd.significand = 0; - goto pack; - - invalid: - vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); - return FPSCR_IOC; + struct vfp_single vsd, vsn, vsm; + u32 exceptions = 0; + s32 n = vfp_get_float(state, sn); + int tm, tn; + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + vfp_single_unpack(&vsm, m); + + vsd.sign = vsn.sign ^ vsm.sign; + + tn = vfp_single_type(&vsn); + tm = vfp_single_type(&vsm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vsn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vsm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exception + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsn); + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; + vsm.significand <<= 1; + if (vsm.significand <= (2 * vsn.significand)) { + vsn.significand >>= 1; + vsd.exponent++; + } + { + u64 significand = (u64)vsn.significand << 32; + do_div(significand, vsm.significand); + vsd.significand = (u32)significand; + } + if ((vsd.significand & 0x3f) == 0) + vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); + +vsn_nan: + exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); +pack: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; + +vsm_nan: + exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); + goto pack; + +zero: + vsd.exponent = 0; + vsd.significand = 0; + goto pack; + +divzero: + exceptions = FPSCR_DZC; +infinity: + vsd.exponent = 255; + vsd.significand = 0; + goto pack; + +invalid: + vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); + return FPSCR_IOC; } static struct op fops[] = { @@ -1199,80 +1277,80 @@ static struct op fops[] = { u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int sn = vfp_get_sn(inst); - unsigned int sm = vfp_get_sm(inst); - unsigned int vecitr, veclen, vecstride; - struct op *fop; - pr_debug("In %s\n", __FUNCTION__); - - vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtsd takes a dN register number as destination, not sN. - * Technically, if bit 0 of dd is set, this is an invalid - * instruction. However, we ignore this for efficiency. - * It also only operates on scalars. - */ - if (fop->flags & OP_DD) - dest = vfp_get_dd(inst); - else - dest = vfp_get_sd(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, - (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); - exit(-1); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - s32 m = vfp_get_float(state, sm); - u32 except; - char type; - - type = fop->flags & OP_DD ? 'd' : 's'; - if (op == FOP_EXT) - pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", - vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, - sm, m); - else - pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", - vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, - FOP_TO_IDX(op), sm, m); - - except = fop->fn(state, dest, sn, m, fpscr); - pr_debug("VFP: itr%d: exceptions=%08x\n", - vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); - sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); - if (FREG_BANK(sm) != 0) - sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); - } - return exceptions; - - invalid: - return (u32)-1; + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int dest; + unsigned int sn = vfp_get_sn(inst); + unsigned int sm = vfp_get_sm(inst); + unsigned int vecitr, veclen, vecstride; + struct op *fop; + pr_debug("In %s\n", __FUNCTION__); + + vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); + + fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; + + /* + * fcvtsd takes a dN register number as destination, not sN. + * Technically, if bit 0 of dd is set, this is an invalid + * instruction. However, we ignore this for efficiency. + * It also only operates on scalars. + */ + if (fop->flags & OP_DD) + dest = vfp_get_dd(inst); + else + dest = vfp_get_sd(inst); + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) + veclen = 0; + else + veclen = fpscr & FPSCR_LENGTH_MASK; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + if (!fop->fn) { + printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); + exit(-1); + goto invalid; + } + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + s32 m = vfp_get_float(state, sm); + u32 except; + char type; + + type = fop->flags & OP_DD ? 'd' : 's'; + if (op == FOP_EXT) + pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, + sm, m); + else + pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, + FOP_TO_IDX(op), sm, m); + + except = fop->fn(state, dest, sn, m, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); + sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); + if (FREG_BANK(sm) != 0) + sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); + } + return exceptions; + +invalid: + return (u32)-1; } diff --git a/src/core/core.cpp b/src/core/core.cpp index 01d4f0afa..25c78d33c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -5,12 +5,14 @@ #include "common/common_types.h" #include "core/core.h" -#include "core/hw/hw.h" + +#include "core/settings.h" #include "core/arm/disassembler/arm_disasm.h" #include "core/arm/interpreter/arm_interpreter.h" - +#include "core/arm/dyncom/arm_dyncom.h" #include "core/hle/hle.h" #include "core/hle/kernel/thread.h" +#include "core/hw/hw.h" namespace Core { @@ -48,9 +50,18 @@ int Init() { NOTICE_LOG(MASTER_LOG, "initialized OK"); g_disasm = new ARM_Disasm(); - g_app_core = new ARM_Interpreter(); g_sys_core = new ARM_Interpreter(); + switch (Settings::values.cpu_core) { + case CPU_FastInterpreter: + g_app_core = new ARM_DynCom(); + break; + case CPU_Interpreter: + default: + g_app_core = new ARM_Interpreter(); + break; + } + g_last_ticks = Core::g_app_core->GetTicks(); return 0; diff --git a/src/core/core.h b/src/core/core.h index 87da252b8..850bb0ab4 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -11,6 +11,11 @@ namespace Core { +enum CPUCore { + CPU_Interpreter, + CPU_FastInterpreter +}; + extern ARM_Interface* g_app_core; ///< ARM11 application core extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core @@ -21,13 +26,13 @@ void Start(); /** * Run the core CPU loop - * This function loops for 100 instructions in the CPU before trying to update hardware. This is a - * little bit faster than SingleStep, and should be pretty much equivalent. The number of - * instructions chosen is fairly arbitrary, however a large number will more drastically affect the - * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU - * for more than 1 instruction to reduce overhead and make it a little bit faster... + * This function runs the core for the specified number of CPU instructions before trying to update + * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not + * required to do a full dispatch with each instruction. NOTE: the number of instructions requested + * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is + * requested (e.g. on a thread switch). */ -void RunLoop(int tight_loop=100); +void RunLoop(int tight_loop=1000); /// Step the CPU one instruction void SingleStep(); diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index 560db6dea..38145eed8 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h @@ -7,11 +7,13 @@ #include <memory> #include "common/common_types.h" +#include "common/string_util.h" #include "common/bit_field.h" #include "core/file_sys/file.h" #include "core/file_sys/directory.h" +#include "core/mem_map.h" #include "core/hle/kernel/kernel.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -19,6 +21,15 @@ namespace FileSys { +// Path string type +enum LowPathType : u32 { + Invalid = 0, + Empty = 1, + Binary = 2, + Char = 3, + Wchar = 4 +}; + union Mode { u32 hex; BitField<0, 1, u32> read_flag; @@ -26,6 +37,94 @@ union Mode { BitField<2, 1, u32> create_flag; }; +class Path { +public: + + Path(): + type(Invalid) + { + } + + Path(LowPathType type, u32 size, u32 pointer): + type(type) + { + switch (type) { + case Binary: + { + u8* data = Memory::GetPointer(pointer); + binary = std::vector<u8>(data, data + size); + break; + } + case Char: + { + const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer)); + string = std::string(data, size - 1); // Data is always null-terminated. + break; + } + case Wchar: + { + const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer)); + u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. + break; + } + } + } + + LowPathType GetType() const { + return type; + } + + const std::string AsString() const { + switch (GetType()) { + case Char: + return string; + case Wchar: + return Common::UTF16ToUTF8(u16str); + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!"); + return {}; + } + } + + const std::u16string AsU16Str() const { + switch (GetType()) { + case Char: + return Common::UTF8ToUTF16(string); + case Wchar: + return u16str; + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!"); + return {}; + } + } + + const std::vector<u8> AsBinary() const { + switch (GetType()) { + case Binary: + return binary; + case Char: + return std::vector<u8>(string.begin(), string.end()); + case Wchar: + return std::vector<u8>(u16str.begin(), u16str.end()); + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!"); + return {}; + } + } + +private: + LowPathType type; + std::vector<u8> binary; + std::string string; + std::u16string u16str; +}; + class Archive : NonCopyable { public: /// Supported archive types @@ -57,6 +156,13 @@ public: virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + virtual bool CreateDirectory(const std::string& path) const = 0; + + /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 9bab3471f..cc759faa8 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -34,6 +34,16 @@ std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mod } /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ +bool Archive_RomFS::CreateDirectory(const std::string& path) const { + ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS."); + return false; +}; + +/** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr @@ -50,7 +60,7 @@ std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) * @return Number of bytes read */ size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { - DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length); + DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length); memcpy(buffer, &raw_data[(u32)offset], length); return length; } diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index fcdefa95f..ae2344e82 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -37,6 +37,13 @@ public: std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + bool CreateDirectory(const std::string& path) const override; + + /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 0b647f7d0..66931e93e 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -58,6 +58,15 @@ std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode } /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ +bool Archive_SDMC::CreateDirectory(const std::string& path) const { + return FileUtil::CreateDir(GetMountPoint() + path); +} + +/** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index f68648e6f..0e059b635 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -41,6 +41,13 @@ public: std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + bool CreateDirectory(const std::string& path) const override; + + /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp index 36951564d..fd558def9 100644 --- a/src/core/file_sys/directory_sdmc.cpp +++ b/src/core/file_sys/directory_sdmc.cpp @@ -42,7 +42,7 @@ u32 Directory_SDMC::Read(const u32 count, Entry* entries) { const std::string& filename = file.virtualName; Entry& entry = entries[entries_read]; - WARN_LOG(FILESYS, "File %s: size=%d dir=%d", filename.c_str(), file.size, file.isDirectory); + WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); // TODO(Link Mauve): use a proper conversion to UTF-16. for (int j = 0; j < FILENAME_LENGTH; ++j) { diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 174d4cd6e..2b21657da 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -17,11 +17,11 @@ namespace Kernel { class AddressArbiter : public Object { public: - std::string GetTypeName() const { return "Arbiter"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Arbiter"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } - Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; } + Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; } std::string name; ///< Name of address arbiter object (optional) @@ -30,7 +30,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 86aba7489..764082d71 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp @@ -42,11 +42,11 @@ enum class DirectoryCommand : u32 { class Archive : public Object { public: - std::string GetTypeName() const { return "Archive"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Archive"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; } - Kernel::HandleType GetHandleType() const { return HandleType::Archive; } + Kernel::HandleType GetHandleType() const override { return HandleType::Archive; } std::string name; ///< Name of archive (optional) FileSys::Archive* backend; ///< Archive backend interface @@ -56,7 +56,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); @@ -119,7 +119,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; @@ -128,11 +128,11 @@ public: class File : public Object { public: - std::string GetTypeName() const { return "File"; } - std::string GetName() const { return path; } + std::string GetTypeName() const override { return "File"; } + std::string GetName() const override { return path; } static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } - Kernel::HandleType GetHandleType() const { return HandleType::File; } + Kernel::HandleType GetHandleType() const override { return HandleType::File; } std::string path; ///< Path of the file std::unique_ptr<FileSys::File> backend; ///< File backend interface @@ -142,7 +142,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -153,7 +153,7 @@ public: u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; u32 length = cmd_buff[3]; u32 address = cmd_buff[5]; - DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%x length=%d address=0x%x", + DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x", GetTypeName().c_str(), GetName().c_str(), offset, length, address); cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); break; @@ -166,7 +166,7 @@ public: u32 length = cmd_buff[3]; u32 flush = cmd_buff[4]; u32 address = cmd_buff[6]; - DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%x length=%d address=0x%x, flush=0x%x", + DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); break; @@ -184,7 +184,7 @@ public: case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - DEBUG_LOG(KERNEL, "SetSize %s %s size=%d", GetTypeName().c_str(), GetName().c_str(), size); + DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); backend->SetSize(size); break; } @@ -211,7 +211,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; @@ -220,11 +220,11 @@ public: class Directory : public Object { public: - std::string GetTypeName() const { return "Directory"; } - std::string GetName() const { return path; } + std::string GetTypeName() const override { return "Directory"; } + std::string GetName() const override { return path; } static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } - Kernel::HandleType GetHandleType() const { return HandleType::Directory; } + Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } std::string path; ///< Path of the directory std::unique_ptr<FileSys::Directory> backend; ///< File backend interface @@ -234,7 +234,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = Service::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { @@ -274,7 +274,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; @@ -381,6 +381,21 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const } /** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Opened Directory object + */ +Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->CreateDirectory(path)) + return 0; + return -1; +} + +/** * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 593861f8e..0230996b6 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h @@ -43,7 +43,15 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name); * @param mode Mode under which to open the File * @return Opened File object */ -Handle OpenFileFromArchive(Handle handle, const std::string& name, const FileSys::Mode mode); +Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); + +/** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether creation of directory succeeded + */ +Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); /** * Open a Directory from an Archive @@ -51,7 +59,7 @@ Handle OpenFileFromArchive(Handle handle, const std::string& name, const FileSys * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ -Handle OpenDirectoryFromArchive(Handle handle, const std::string& name); +Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 64f6a9649..45ed79be8 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -16,11 +16,11 @@ namespace Kernel { class Event : public Object { public: - std::string GetTypeName() const { return "Event"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Event"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; } ResetType intitial_reset_type; ///< ResetType specified at Event initialization ResetType reset_type; ///< Current ResetType @@ -35,7 +35,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { *wait = locked; if (locked) { Handle thread = GetCurrentThreadHandle(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 5d7d65dd9..fcfd061ac 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -15,11 +15,11 @@ namespace Kernel { class Mutex : public Object { public: - std::string GetTypeName() const { return "Mutex"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Mutex"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; } bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state @@ -32,7 +32,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { // TODO(bunnei): ImplementMe locked = true; return 0; @@ -43,7 +43,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe *wait = locked; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 2a6a483a1..f538c6550 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -11,17 +11,17 @@ namespace Kernel { class SharedMemory : public Object { public: - std::string GetTypeName() const { return "SharedMemory"; } + std::string GetTypeName() const override { return "SharedMemory"; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } /** * Wait for kernel object to synchronize * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; @@ -72,7 +72,7 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", - handle); + handle, address); return -1; } SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 33c0b2a47..e15590c49 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -21,11 +21,11 @@ namespace Kernel { class Thread : public Kernel::Object { public: - std::string GetName() const { return name; } - std::string GetTypeName() const { return "Thread"; } + std::string GetName() const override { return name; } + std::string GetTypeName() const override { return "Thread"; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; } inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } @@ -38,7 +38,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { if (status != THREADSTATUS_DORMANT) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp new file mode 100644 index 000000000..b39603bdf --- /dev/null +++ b/src/core/hle/service/ac_u.cpp @@ -0,0 +1,44 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ac_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AC_U + +namespace AC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "CreateDefaultConfig"}, + {0x00040006, nullptr, "ConnectAsync"}, + {0x00050002, nullptr, "GetConnectResult"}, + {0x00080004, nullptr, "CloseAsync"}, + {0x00090002, nullptr, "GetCloseResult"}, + {0x000A0000, nullptr, "GetLastErrorCode"}, + {0x000D0000, nullptr, "GetWifiStatus"}, + {0x000E0042, nullptr, "GetCurrentAPInfo"}, + {0x00100042, nullptr, "GetCurrentNZoneInfo"}, + {0x00110042, nullptr, "GetNZoneApNumService"}, + {0x00240042, nullptr, "AddDenyApType "}, + {0x00270002, nullptr, "GetInfraPriority "}, + {0x002D0082, nullptr, "SetRequestEulaVersion"}, + {0x00300004, nullptr, "RegisterDisconnectEvent"}, + {0x003C0042, nullptr, "GetAPSSIDList"}, + {0x003E0042, nullptr, "IsConnected "}, + {0x00400042, nullptr, "SetClientVersion"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h new file mode 100644 index 000000000..3c5958d27 --- /dev/null +++ b/src/core/hle/service/ac_u.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AC_U + +// socket service "ac:u" + +namespace AC_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "ac:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt_u.cpp index 3753f1107..4f41ec5f4 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -8,13 +8,15 @@ #include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" -#include "core/hle/service/apt.h" +#include "apt_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace APT_U namespace APT_U { +static Handle lock_handle = 0; + /// Signals used by APT functions enum class SignalType : u32 { None = 0x0, @@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) { Kernel::SetEventLocked(cmd_buff[3], true); Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event + _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); + Kernel::ReleaseMutex(lock_handle); + cmd_buff[1] = 0; // No error + DEBUG_LOG(KERNEL, "called"); } void GetLockHandle(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field + + if (0 == lock_handle) { + // TODO(bunnei): Verify if this is created here or at application boot? + lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); + Kernel::ReleaseMutex(lock_handle); + } cmd_buff[1] = 0; // No error - cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); + + // Not sure what these parameters are used for, but retail apps check that they are 0 after + // GetLockHandle has been called. + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = 0; + + cmd_buff[5] = lock_handle; DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); } @@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) { WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); } +/** + * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state, + * from the source process which set the parameters. Once finished, NS will clear a flag in the NS + * state so that this command will return an error if this command is used again if parameters were + * not set again. This is called when the second Initialize event is triggered. It returns a signal + * type indicating why it was triggered. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ void ReceiveParameter(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 app_id = cmd_buff[1]; @@ -66,7 +104,7 @@ void ReceiveParameter(Service::Interface* self) { cmd_buff[1] = 0; // No error cmd_buff[2] = 0; cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; + cmd_buff[4] = 0x10; // Parameter buffer size (16) cmd_buff[5] = 0; cmd_buff[6] = 0; cmd_buff[7] = 0; @@ -74,35 +112,66 @@ void ReceiveParameter(Service::Interface* self) { } /** -* APT_U::GlanceParameter service function -* Inputs: -* 1 : AppID -* 2 : Parameter buffer size, max size is 0x1000 -* Outputs: -* 1 : Result of function, 0 on success, otherwise error code -* 2 : Unknown, for now assume AppID of the process which sent these parameters -* 3 : Unknown, for now assume Signal type -* 4 : Actual parameter buffer size, this is <= to the the input size -* 5 : Value -* 6 : Handle from the source process which set the parameters, likely used for shared memory -* 7 : Size -* 8 : Output parameter buffer ptr -*/ + * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter + * (except for the word value prior to the output handle), except this will not clear the flag + * (except when responseword[3]==8 || responseword[3]==9) in NS state. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ void GlanceParameter(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 app_id = cmd_buff[1]; u32 buffer_size = cmd_buff[2]; + cmd_buff[1] = 0; // No error cmd_buff[2] = 0; cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0; + cmd_buff[4] = 0x10; // Parameter buffer size (16) cmd_buff[5] = 0; cmd_buff[6] = 0; cmd_buff[7] = 0; - cmd_buff[8] = 0; + WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); } +/** + * APT_U::AppletUtility service function + * Inputs: + * 1 : Unknown, but clearly used for something + * 2 : Buffer 1 size (purpose is unknown) + * 3 : Buffer 2 size (purpose is unknown) + * 5 : Buffer 1 address (purpose is unknown) + * 65 : Buffer 2 address (purpose is unknown) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void AppletUtility(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // These are from 3dbrew - I'm not really sure what they're used for. + u32 unk = cmd_buff[1]; + u32 buffer1_size = cmd_buff[2]; + u32 buffer2_size = cmd_buff[3]; + u32 buffer1_addr = cmd_buff[5]; + u32 buffer2_addr = cmd_buff[65]; + + cmd_buff[1] = 0; // No error + + WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " + "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, + buffer1_addr, buffer2_addr); +} + const Interface::FunctionInfo FunctionTable[] = { {0x00010040, GetLockHandle, "GetLockHandle"}, {0x00020080, Initialize, "Initialize"}, @@ -178,7 +247,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00480100, nullptr, "GetProgramInfo"}, {0x00490180, nullptr, "Reboot"}, {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, nullptr, "AppletUtility"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, {0x004C0000, nullptr, "SetFatalErrDispMode"}, {0x004D0080, nullptr, "GetAppletProgramInfo"}, {0x004E0000, nullptr, "HardwareResetAsync"}, @@ -191,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + + lock_handle = 0; } Interface::~Interface() { diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt_u.h index 4c7dd07e7..5af39e085 100644 --- a/src/core/hle/service/apt.h +++ b/src/core/hle/service/apt_u.h @@ -29,7 +29,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "APT:U"; } }; diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp new file mode 100644 index 000000000..822b0e2b8 --- /dev/null +++ b/src/core/hle/service/cfg_u.cpp @@ -0,0 +1,36 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/cfg_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_U + +namespace CFG_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010082, nullptr, "GetConfigInfoBlk2"}, + {0x00020000, nullptr, "SecureInfoGetRegion"}, + {0x00030000, nullptr, "GenHashConsoleUnique"}, + {0x00040000, nullptr, "GetRegionCanadaUSA"}, + {0x00050000, nullptr, "GetSystemModel"}, + {0x00060000, nullptr, "GetModelNintendo2DS"}, + {0x00070040, nullptr, "unknown"}, + {0x00080080, nullptr, "unknown"}, + {0x00090080, nullptr, "GetCountryCodeString"}, + {0x000A0040, nullptr, "GetCountryCodeID"}, +}; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h new file mode 100644 index 000000000..7525bd7c6 --- /dev/null +++ b/src/core/hle/service/cfg_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_U + +namespace CFG_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "cfg:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp new file mode 100644 index 000000000..9e84ac938 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.cpp @@ -0,0 +1,52 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/dsp_dsp.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace DSP_DSP + +namespace DSP_DSP { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, nullptr, "RecvData"}, + {0x00020040, nullptr, "RecvDataIsReady"}, + {0x00030080, nullptr, "SendData"}, + {0x00040040, nullptr, "SendDataIsEmpty"}, + {0x00070040, nullptr, "WriteReg0x10"}, + {0x00080000, nullptr, "GetSemaphore"}, + {0x00090040, nullptr, "ClearSemaphore"}, + {0x000B0000, nullptr, "CheckSemaphoreRequest"}, + {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"}, + {0x000D0082, nullptr, "WriteProcessPipe"}, + {0x001000C0, nullptr, "ReadPipeIfPossible"}, + {0x001100C2, nullptr, "LoadComponent"}, + {0x00120000, nullptr, "UnloadComponent"}, + {0x00130082, nullptr, "FlushDataCache"}, + {0x00140082, nullptr, "InvalidateDCache "}, + {0x00150082, nullptr, "RegisterInterruptEvents"}, + {0x00160000, nullptr, "GetSemaphoreEventHandle"}, + {0x00170040, nullptr, "SetSemaphoreMask"}, + {0x00180040, nullptr, "GetPhysicalAddress"}, + {0x00190040, nullptr, "GetVirtualAddress" }, + {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, + {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, + {0x001C0082, nullptr, "SetIirFilterEQ"}, + {0x001F0000, nullptr, "GetHeadphoneStatus"}, + {0x00210000, nullptr, "GetIsDspOccupied"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h new file mode 100644 index 000000000..c439ed266 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace DSP_DSP + +namespace DSP_DSP { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "dsp:DSP"; + } +}; + +} // namespace diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp new file mode 100644 index 000000000..917b2f8ca --- /dev/null +++ b/src/core/hle/service/err_f.cpp @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/err_f.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace ERR_F + +namespace ERR_F { + + const Interface::FunctionInfo FunctionTable[] = { + {0x00010800, nullptr, "ThrowFatalError"} + }; + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Interface class + + Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + } + + Interface::~Interface() { + } + +} // namespace diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h new file mode 100644 index 000000000..5da663267 --- /dev/null +++ b/src/core/hle/service/err_f.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace ERR_F + +namespace ERR_F { + + class Interface : public Service::Interface { + public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "err:f"; + } + }; + +} // namespace diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp new file mode 100644 index 000000000..58023e536 --- /dev/null +++ b/src/core/hle/service/frd_u.cpp @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/frd_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FRD_U + +namespace FRD_U { + + const Interface::FunctionInfo FunctionTable[] = { + {0x00050000, nullptr, "GetFriendKey"}, + {0x00080000, nullptr, "GetMyPresence"}, + {0x00100040, nullptr, "GetPassword"}, + {0x00190042, nullptr, "GetFriendFavoriteGame"}, + {0x001A00C4, nullptr, "GetFriendInfo"}, + {0x001B0080, nullptr, "IsOnFriendList"}, + {0x001C0042, nullptr, "DecodeLocalFriendCode"}, + {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, + {0x00320042, nullptr, "SetClientSdkVersion"} + }; + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Interface class + + Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + } + + Interface::~Interface() { + } + +} // namespace diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h new file mode 100644 index 000000000..9df8a815a --- /dev/null +++ b/src/core/hle/service/frd_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FRD_U + +namespace FRD_U { + + class Interface : public Service::Interface { + public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "frd:u"; + } + }; + +} // namespace diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs_user.cpp index 662c4f247..9dc83291d 100644 --- a/src/core/hle/service/fs.cpp +++ b/src/core/hle/service/fs_user.cpp @@ -4,7 +4,9 @@ #include "common/common.h" -#include "core/hle/service/fs.h" +#include "fs_user.h" +#include "common/string_util.h" +#include "core/settings.h" #include "core/hle/kernel/archive.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -12,20 +14,6 @@ namespace FS_User { -// Command to access archive file -enum class LowPathType : u32 { - Invalid = 0, - Empty = 1, - Binary = 2, - Char = 3, - Wchar = 4 -}; - -std::string GetStringFromCmdBuff(const u32 pointer, const u32 size) { - auto data = reinterpret_cast<const char*>(Memory::GetPointer(pointer)); - return std::string(data, size - 1); -} - // We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it // puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make // sure we don't mislead the application into thinking something worked. @@ -43,32 +31,36 @@ void Initialize(Service::Interface* self) { void OpenFile(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); - u32 transaction = cmd_buff[1]; // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. Handle archive_handle = static_cast<Handle>(cmd_buff[3]); - LowPathType type = static_cast<LowPathType>(cmd_buff[4]); - u32 size = cmd_buff[5]; + auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 filename_size = cmd_buff[5]; FileSys::Mode mode; mode.hex = cmd_buff[6]; - u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. - u32 pointer = cmd_buff[9]; - - if (type != LowPathType::Char) { - ERROR_LOG(KERNEL, "file LowPath type other than char is currently unsupported"); - cmd_buff[1] = -1; + u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. + u32 filename_ptr = cmd_buff[9]; + + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + std::string file_string; + switch (file_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + file_string = file_path.AsString(); + break; + default: + WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); return; } - std::string file_name = GetStringFromCmdBuff(pointer, size); - - DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", type, size, mode, attributes, file_name.c_str()); + DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", + filename_type, filename_size, mode, attributes, file_string.c_str()); - Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode); + Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); if (handle) { cmd_buff[1] = 0; cmd_buff[3] = handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str()); + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. cmd_buff[1] = -1; } @@ -79,31 +71,25 @@ void OpenFile(Service::Interface* self) { void OpenFileDirectly(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); - u32 transaction = cmd_buff[1]; - auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); - LowPathType archive_type = static_cast<LowPathType>(cmd_buff[3]); - u32 archive_size = cmd_buff[4]; - LowPathType file_type = static_cast<LowPathType>(cmd_buff[5]); - u32 size = cmd_buff[6]; + auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); + auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); + u32 archivename_size = cmd_buff[4]; + auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); + u32 filename_size = cmd_buff[6]; FileSys::Mode mode; mode.hex = cmd_buff[7]; - u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. - u32 archive_pointer = cmd_buff[10]; - u32 pointer = cmd_buff[12]; + u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. + u32 archivename_ptr = cmd_buff[10]; + u32 filename_ptr = cmd_buff[12]; - if (archive_type != LowPathType::Empty) { + DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d", + archivename_type, archivename_size, filename_type, filename_size, mode, attributes); + + if (archivename_type != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); cmd_buff[1] = -1; return; } - std::string archive_name = GetStringFromCmdBuff(archive_pointer, archive_size); - std::string file_name = GetStringFromCmdBuff(pointer, size); - - DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d archive_data=%s" - "file_type=%d file_size=%d file_mode=%d file_attrs=%d file_data=%s", - archive_type, archive_size, archive_name.c_str(), - file_type, size, mode, attributes, file_name.c_str()); - // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. Handle archive_handle = Kernel::OpenArchive(archive_id); if (archive_handle) { @@ -111,23 +97,30 @@ void OpenFileDirectly(Service::Interface* self) { // cmd_buff[2] isn't used according to 3dmoo's implementation. cmd_buff[3] = archive_handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str()); + ERROR_LOG(KERNEL, "failed to get a handle for archive"); // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. cmd_buff[1] = -1; return; } - if (file_type != LowPathType::Char) { - WARN_LOG(KERNEL, "file LowPath type other than char is currently unsupported; returning archive handle instead"); + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + std::string file_string; + switch (file_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + file_string = file_path.AsString(); + break; + default: + WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); return; } - Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode); + Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); if (handle) { cmd_buff[1] = 0; cmd_buff[3] = handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str()); + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. cmd_buff[1] = -1; } @@ -135,32 +128,76 @@ void OpenFileDirectly(Service::Interface* self) { DEBUG_LOG(KERNEL, "called"); } +/* + * FS_User::CreateDirectory service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Directory path string type + * 5 : Directory path string size + * 8 : Directory path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void CreateDirectory(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[3]); + auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 dirname_size = cmd_buff[5]; + u32 dirname_ptr = cmd_buff[8]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + std::string dir_string; + switch (dir_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + dir_string = dir_path.AsString(); + break; + default: + cmd_buff[1] = -1; + return; + } + + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); + + cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string); + + DEBUG_LOG(KERNEL, "called"); +} + void OpenDirectory(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. Handle archive_handle = static_cast<Handle>(cmd_buff[2]); - LowPathType type = static_cast<LowPathType>(cmd_buff[3]); - u32 size = cmd_buff[4]; - u32 pointer = cmd_buff[6]; - - if (type != LowPathType::Char) { - ERROR_LOG(KERNEL, "directory LowPath type other than char is currently unsupported"); + auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); + u32 dirname_size = cmd_buff[4]; + u32 dirname_ptr = cmd_buff[6]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + std::string dir_string; + switch (dir_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + dir_string = dir_path.AsString(); + break; + default: cmd_buff[1] = -1; return; } - std::string dir_name = GetStringFromCmdBuff(pointer, size); + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); - DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, dir_name.c_str()); - - Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_name); + Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string); if (handle) { cmd_buff[1] = 0; cmd_buff[3] = handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_name.c_str()); + ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. cmd_buff[1] = -1; } @@ -171,28 +208,26 @@ void OpenDirectory(Service::Interface* self) { void OpenArchive(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); - auto arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); - LowPathType type = static_cast<LowPathType>(cmd_buff[2]); - u32 size = cmd_buff[3]; - u32 pointer = cmd_buff[5]; + auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); + auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); + u32 archivename_size = cmd_buff[3]; + u32 archivename_ptr = cmd_buff[5]; + + DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size); - if (type != LowPathType::Empty) { + if (archivename_type != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); cmd_buff[1] = -1; return; } - std::string archive_name = GetStringFromCmdBuff(pointer, size); - - DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, archive_name.c_str()); - - Handle handle = Kernel::OpenArchive(arch_id); + Handle handle = Kernel::OpenArchive(archive_id); if (handle) { cmd_buff[1] = 0; // cmd_buff[2] isn't used according to 3dmoo's implementation. cmd_buff[3] = handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str()); + ERROR_LOG(KERNEL, "failed to get a handle for archive"); // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. cmd_buff[1] = -1; } @@ -200,6 +235,21 @@ void OpenArchive(Service::Interface* self) { DEBUG_LOG(KERNEL, "called"); } +/* +* FS_User::IsSdmcDetected service function +* Outputs: +* 1 : Result of function, 0 on success, otherwise error code +* 2 : Whether the Sdmc could be detected +*/ +void IsSdmcDetected(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + cmd_buff[1] = 0; + cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; + + DEBUG_LOG(KERNEL, "called"); +} + const Interface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, @@ -211,7 +261,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08060142, nullptr, "DeleteDirectory"}, {0x08070142, nullptr, "DeleteDirectoryRecursively"}, {0x08080202, nullptr, "CreateFile"}, - {0x08090182, nullptr, "CreateDirectory"}, + {0x08090182, CreateDirectory, "CreateDirectory"}, {0x080A0244, nullptr, "RenameDirectory"}, {0x080B0102, OpenDirectory, "OpenDirectory"}, {0x080C00C2, OpenArchive, "OpenArchive"}, @@ -225,7 +275,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08140000, nullptr, "GetSdmcArchiveResource"}, {0x08150000, nullptr, "GetNandArchiveResource"}, {0x08160000, nullptr, "GetSdmcFatfsErro"}, - {0x08170000, nullptr, "IsSdmcDetected"}, + {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, {0x08180000, nullptr, "IsSdmcWritable"}, {0x08190042, nullptr, "GetSdmcCid"}, {0x081A0042, nullptr, "GetNandCid"}, diff --git a/src/core/hle/service/fs.h b/src/core/hle/service/fs_user.h index 36f3697d3..005382540 100644 --- a/src/core/hle/service/fs.h +++ b/src/core/hle/service/fs_user.h @@ -23,7 +23,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "fs:USER"; } }; diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp_gpu.cpp index 614d9584d..6119e6300 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -9,7 +9,7 @@ #include "core/mem_map.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" -#include "core/hle/service/gsp.h" +#include "gsp_gpu.h" #include "core/hw/gpu.h" #include "video_core/gpu_debugger.h" diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp_gpu.h index a09d59dbb..177ce8da6 100644 --- a/src/core/hle/service/gsp.h +++ b/src/core/hle/service/gsp_gpu.h @@ -167,7 +167,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "gsp::Gpu"; } diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid_user.cpp index b6ec1b8ff..0eb32ba4a 100644 --- a/src/core/hle/service/hid.cpp +++ b/src/core/hle/service/hid_user.cpp @@ -7,7 +7,7 @@ #include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" -#include "core/hle/service/hid.h" +#include "hid_user.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace HID_User @@ -78,6 +78,10 @@ void PadButtonRelease(PadState pad_state) { 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; diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/hid_user.h index a077e25cd..9f6c4d5ed 100644 --- a/src/core/hle/service/hid.h +++ b/src/core/hle/service/hid_user.h @@ -111,7 +111,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "hid:USER"; } diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp new file mode 100644 index 000000000..58051f133 --- /dev/null +++ b/src/core/hle/service/mic_u.cpp @@ -0,0 +1,43 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/mic_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace MIC_U + +namespace MIC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010042, nullptr, "MapSharedMem"}, + {0x00020000, nullptr, "UnmapSharedMem"}, + {0x00030140, nullptr, "Initialize"}, + {0x00040040, nullptr, "AdjustSampling"}, + {0x00050000, nullptr, "StopSampling"}, + {0x00060000, nullptr, "IsSampling"}, + {0x00070000, nullptr, "GetEventHandle"}, + {0x00080040, nullptr, "SetControl"}, + {0x00090000, nullptr, "GetControl"}, + {0x000A0040, nullptr, "SetBias"}, + {0x000B0000, nullptr, "GetBias"}, + {0x000C0042, nullptr, "size"}, + {0x000D0040, nullptr, "SetClamp"}, + {0x000E0000, nullptr, "GetClamp"}, + {0x000F0040, nullptr, "unknown_input1"}, + {0x00100040, nullptr, "unknown_input2"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h new file mode 100644 index 000000000..72ba048ef --- /dev/null +++ b/src/core/hle/service/mic_u.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace MIC_U + +// mic service + +namespace MIC_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "mic:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm_u.cpp index f6af0a153..37c0661bf 100644 --- a/src/core/hle/service/ndm.cpp +++ b/src/core/hle/service/ndm_u.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/ndm.h" +#include "ndm_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace NDM_U diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm_u.h index d5ec28f5b..2ca9fcf22 100644 --- a/src/core/hle/service/ndm.h +++ b/src/core/hle/service/ndm_u.h @@ -24,7 +24,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "ndm:u"; } diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp new file mode 100644 index 000000000..14df86d85 --- /dev/null +++ b/src/core/hle/service/nwm_uds.cpp @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/nwm_uds.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NWM_UDS + +namespace NWM_UDS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00030000, nullptr, "Shutdown"}, + {0x000F0404, nullptr, "RecvBeaconBroadcastData"}, + {0x00100042, nullptr, "SetBeaconAdditionalData"}, + {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, + {0x001B0302, nullptr, "Initialize"}, + {0x001D0044, nullptr, "BeginHostingNetwork"}, + {0x001E0084, nullptr, "ConnectToNetwork"}, + {0x001F0006, nullptr, "DecryptBeaconData"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h new file mode 100644 index 000000000..a956ca812 --- /dev/null +++ b/src/core/hle/service/nwm_uds.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NWM_UDS + +// local-WLAN service + +namespace NWM_UDS { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "nwm:UDS"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp new file mode 100644 index 000000000..f6a14d509 --- /dev/null +++ b/src/core/hle/service/ptm_u.cpp @@ -0,0 +1,42 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ptm_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PTM_U + +namespace PTM_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, nullptr, "GetAdapterState"}, + {0x00060000, nullptr, "GetShellState "}, + {0x00070000, nullptr, "GetBatteryLevel"}, + {0x00080000, nullptr, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory "}, + {0x000C0000, nullptr, "GetTotalStepCount "}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h new file mode 100644 index 000000000..82749fa39 --- /dev/null +++ b/src/core/hle/service/ptm_u.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PTM_U + +// ptm service + +namespace PTM_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "ptm:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 9eb1726aa..bb0f80e98 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -6,12 +6,22 @@ #include "common/string_util.h" #include "core/hle/service/service.h" -#include "core/hle/service/apt.h" -#include "core/hle/service/fs.h" -#include "core/hle/service/gsp.h" -#include "core/hle/service/hid.h" -#include "core/hle/service/ndm.h" +#include "core/hle/service/ac_u.h" +#include "core/hle/service/apt_u.h" +#include "core/hle/service/cfg_u.h" +#include "core/hle/service/dsp_dsp.h" +#include "core/hle/service/err_f.h" +#include "core/hle/service/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/mic_u.h" +#include "core/hle/service/ndm_u.h" +#include "core/hle/service/nwm_uds.h" +#include "core/hle/service/ptm_u.h" +#include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" +#include "core/hle/service/ssl_c.h" namespace Service { @@ -66,11 +76,21 @@ void Init() { g_manager = new Manager; g_manager->AddService(new SRV::Interface); + g_manager->AddService(new AC_U::Interface); g_manager->AddService(new APT_U::Interface); + g_manager->AddService(new CFG_U::Interface); + g_manager->AddService(new DSP_DSP::Interface); + g_manager->AddService(new ERR_F::Interface); + g_manager->AddService(new FRD_U::Interface); g_manager->AddService(new FS_User::Interface); g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new HID_User::Interface); + g_manager->AddService(new MIC_U::Interface); g_manager->AddService(new NDM_U::Interface); + g_manager->AddService(new NWM_UDS::Interface); + g_manager->AddService(new PTM_U::Interface); + g_manager->AddService(new SOC_U::Interface); + g_manager->AddService(new SSL_C::Interface); NOTICE_LOG(HLE, "initialized OK"); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index c0e803bda..2f5a866c9 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -39,11 +39,11 @@ class Interface : public Kernel::Object { friend class Manager; public: - std::string GetName() const { return GetPortName(); } - std::string GetTypeName() const { return GetPortName(); } + std::string GetName() const override { return GetPortName(); } + std::string GetTypeName() const override { return GetPortName(); } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; } typedef void (*Function)(Interface*); @@ -80,7 +80,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -113,7 +113,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "unimplemented function"); return 0; diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp new file mode 100644 index 000000000..2f8910468 --- /dev/null +++ b/src/core/hle/service/soc_u.cpp @@ -0,0 +1,58 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/soc_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SOC_U + +namespace SOC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010044, nullptr, "InitializeSockets"}, + {0x000200C2, nullptr, "socket"}, + {0x00030082, nullptr, "listen"}, + {0x00040082, nullptr, "accept"}, + {0x00050084, nullptr, "bind"}, + {0x00060084, nullptr, "connect"}, + {0x00070104, nullptr, "recvfrom_other"}, + {0x00080102, nullptr, "recvfrom"}, + {0x00090106, nullptr, "sendto_other"}, + {0x000A0106, nullptr, "sendto"}, + {0x000B0042, nullptr, "close"}, + {0x000C0082, nullptr, "shutdown"}, + {0x000D0082, nullptr, "gethostbyname"}, + {0x000E00C2, nullptr, "gethostbyaddr"}, + {0x000F0106, nullptr, "unknown_resolve_ip"}, + {0x00110102, nullptr, "getsockopt"}, + {0x00120104, nullptr, "setsockopt"}, + {0x001300C2, nullptr, "fcntl"}, + {0x00140084, nullptr, "poll"}, + {0x00150042, nullptr, "sockatmark"}, + {0x00160000, nullptr, "gethostid"}, + {0x00170082, nullptr, "getsockname"}, + {0x00180082, nullptr, "getpeername"}, + {0x00190000, nullptr, "ShutdownSockets"}, + {0x001A00C0, nullptr, "GetNetworkOpt"}, + {0x001B0040, nullptr, "ICMPSocket"}, + {0x001C0104, nullptr, "ICMPPing"}, + {0x001D0040, nullptr, "ICMPCancel"}, + {0x001E0040, nullptr, "ICMPClose"}, + {0x001F0040, nullptr, "GetResolverInfo"}, + {0x00210002, nullptr, "CloseSockets"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h new file mode 100644 index 000000000..e27a2b1fe --- /dev/null +++ b/src/core/hle/service/soc_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SOC_U + +namespace SOC_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "soc:U"; + } +}; + +} // namespace diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index eb2c73f93..6c02a43d9 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -57,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00030100, nullptr, "RegisterService"}, {0x000400C0, nullptr, "UnregisterService"}, {0x00050100, GetServiceHandle, "GetServiceHandle"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, nullptr, "PublishToSubscriber"} }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 9451472de..6d5fe5048 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -22,7 +22,7 @@ public: * Gets the string name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "srv:"; } diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp new file mode 100644 index 000000000..4aa660ecc --- /dev/null +++ b/src/core/hle/service/ssl_c.cpp @@ -0,0 +1,31 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ssl_c.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SSL_C + +namespace SSL_C { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000200C2, nullptr, "CreateContext"}, + {0x00050082, nullptr, "AddTrustedRootCA"}, + {0x00150082, nullptr, "Read"}, + {0x00170082, nullptr, "Write"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h new file mode 100644 index 000000000..7b4e7fd8a --- /dev/null +++ b/src/core/hle/service/ssl_c.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SSL_C + +namespace SSL_C { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "ssl:C"; + } +}; + +} // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 490e05cde..1eda36c53 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -115,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); - DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(), + DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); @@ -138,7 +138,7 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa bool unlock_all = true; bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated - DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", + DEBUG_LOG(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 @@ -324,7 +324,7 @@ Result ClearEvent(Handle evt) { /// Sleep the current thread void SleepThread(s64 nanoseconds) { - DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); + DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); } /// This returns the total CPU ticks elapsed since the CPU was powered-on diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 33a0e0fe7..3ad801c63 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -4,11 +4,12 @@ #include "common/common_types.h" +#include "core/settings.h" #include "core/core.h" #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/service/gsp.h" +#include "core/hle/service/gsp_gpu.h" #include "core/hw/gpu.h" @@ -24,6 +25,9 @@ u32 g_cur_line = 0; ///< Current vertical screen line u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame +static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second +static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame + template <typename T> inline void Read(T &var, const u32 raw_addr) { u32 addr = raw_addr - 0x1EF00000; @@ -31,7 +35,7 @@ inline void Read(T &var, const u32 raw_addr) { // Reads other than u32 are untested, so I'd rather have them abort than silently fail if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { - ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); return; } @@ -45,7 +49,7 @@ inline void Write(u32 addr, const T data) { // Writes other than u32 are untested, so I'd rather have them abort than silently fail if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { - ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); return; } @@ -214,6 +218,9 @@ void Update() { /// Initialize hardware void Init() { + kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate; + kFrameTicks = kFrameCycles / 3; + g_cur_line = 0; g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks(); diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 92097d182..3fa7b9ccf 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -11,9 +11,6 @@ namespace GPU { -static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second -static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame - // Returns index corresponding to the Regs member labeled by field_name // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index efd94f147..33f75c50a 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -50,7 +50,7 @@ inline void Read(T &var, const u32 addr) { break; default: - ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); } } @@ -68,7 +68,7 @@ inline void Write(u32 addr, const T data) { break; default: - ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); } } diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp index 158241fd6..e29a773f1 100644 --- a/src/core/hw/ndma.cpp +++ b/src/core/hw/ndma.cpp @@ -10,12 +10,12 @@ namespace NDMA { template <typename T> inline void Read(T &var, const u32 addr) { - ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); } template <typename T> inline void Write(u32 addr, const T data) { - ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); } // Explicitly instantiate template functions because we aren't defining this in the header: diff --git a/src/core/settings.h b/src/core/settings.h index 77b2f02fc..7e7a66b89 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -7,6 +7,7 @@ namespace Settings { struct Values { + // Controls int pad_a_key; int pad_b_key; int pad_x_key; @@ -25,6 +26,11 @@ struct Values { int pad_sleft_key; int pad_sright_key; + // Core + int cpu_core; + int gpu_refresh_rate; + + // Data Storage bool use_virtual_sd; bool enable_log; |