diff options
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 96 | ||||
| -rw-r--r-- | src/core/arm/interpreter/armsupp.cpp | 35 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 2 |
3 files changed, 131 insertions, 2 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 0ee103c56..a66560af2 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -1100,6 +1100,14 @@ typedef struct _smla_inst { | |||
| 1100 | unsigned int Rn; | 1100 | unsigned int Rn; |
| 1101 | } smla_inst; | 1101 | } smla_inst; |
| 1102 | 1102 | ||
| 1103 | typedef struct ssat_inst { | ||
| 1104 | unsigned int Rn; | ||
| 1105 | unsigned int Rd; | ||
| 1106 | unsigned int imm5; | ||
| 1107 | unsigned int sat_imm; | ||
| 1108 | unsigned int shift_type; | ||
| 1109 | } ssat_inst; | ||
| 1110 | |||
| 1103 | typedef struct umaal_inst { | 1111 | typedef struct umaal_inst { |
| 1104 | unsigned int Rn; | 1112 | unsigned int Rn; |
| 1105 | unsigned int Rm; | 1113 | unsigned int Rm; |
| @@ -2525,7 +2533,24 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) | |||
| 2525 | } | 2533 | } |
| 2526 | ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMUSD"); } | 2534 | ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMUSD"); } |
| 2527 | ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SRS"); } | 2535 | ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SRS"); } |
| 2528 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSAT"); } | 2536 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) |
| 2537 | { | ||
| 2538 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); | ||
| 2539 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 2540 | |||
| 2541 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2542 | inst_base->idx = index; | ||
| 2543 | inst_base->br = NON_BRANCH; | ||
| 2544 | inst_base->load_r15 = 0; | ||
| 2545 | |||
| 2546 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 2547 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2548 | inst_cream->imm5 = BITS(inst, 7, 11); | ||
| 2549 | inst_cream->sat_imm = BITS(inst, 16, 20); | ||
| 2550 | inst_cream->shift_type = BIT(inst, 6); | ||
| 2551 | |||
| 2552 | return inst_base; | ||
| 2553 | } | ||
| 2529 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSAT16"); } | 2554 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSAT16"); } |
| 2530 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSUB8"); } | 2555 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSUB8"); } |
| 2531 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) | 2556 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) |
| @@ -3128,7 +3153,10 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index) | |||
| 3128 | { | 3153 | { |
| 3129 | return INTERPRETER_TRANSLATE(usada8)(inst, index); | 3154 | return INTERPRETER_TRANSLATE(usada8)(inst, index); |
| 3130 | } | 3155 | } |
| 3131 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USAT"); } | 3156 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) |
| 3157 | { | ||
| 3158 | return INTERPRETER_TRANSLATE(ssat)(inst, index); | ||
| 3159 | } | ||
| 3132 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USAT16"); } | 3160 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USAT16"); } |
| 3133 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB16"); } | 3161 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB16"); } |
| 3134 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB8"); } | 3162 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB8"); } |
| @@ -5514,6 +5542,38 @@ unsigned InterpreterMainLoop(ARMul_State* state) { | |||
| 5514 | SMUSD_INST: | 5542 | SMUSD_INST: |
| 5515 | SRS_INST: | 5543 | SRS_INST: |
| 5516 | SSAT_INST: | 5544 | SSAT_INST: |
| 5545 | { | ||
| 5546 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 5547 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 5548 | |||
| 5549 | u8 shift_type = inst_cream->shift_type; | ||
| 5550 | u8 shift_amount = inst_cream->imm5; | ||
| 5551 | u32 rn_val = RN; | ||
| 5552 | |||
| 5553 | // 32-bit ASR is encoded as an amount of 0. | ||
| 5554 | if (shift_type == 1 && shift_amount == 0) | ||
| 5555 | shift_amount = 31; | ||
| 5556 | |||
| 5557 | if (shift_type == 0) | ||
| 5558 | rn_val <<= shift_amount; | ||
| 5559 | else if (shift_type == 1) | ||
| 5560 | rn_val = ((s32)rn_val >> shift_amount); | ||
| 5561 | |||
| 5562 | bool saturated = false; | ||
| 5563 | rn_val = ARMul_SignedSatQ(rn_val, inst_cream->sat_imm, &saturated); | ||
| 5564 | |||
| 5565 | if (saturated) | ||
| 5566 | cpu->Cpsr |= (1 << 27); | ||
| 5567 | |||
| 5568 | RD = rn_val; | ||
| 5569 | } | ||
| 5570 | |||
| 5571 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5572 | INC_PC(sizeof(ssat_inst)); | ||
| 5573 | FETCH_INST; | ||
| 5574 | GOTO_NEXT_INST; | ||
| 5575 | } | ||
| 5576 | |||
| 5517 | SSAT16_INST: | 5577 | SSAT16_INST: |
| 5518 | SSUB8_INST: | 5578 | SSUB8_INST: |
| 5519 | STC_INST: | 5579 | STC_INST: |
| @@ -6262,6 +6322,38 @@ unsigned InterpreterMainLoop(ARMul_State* state) { | |||
| 6262 | } | 6322 | } |
| 6263 | 6323 | ||
| 6264 | USAT_INST: | 6324 | USAT_INST: |
| 6325 | { | ||
| 6326 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 6327 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 6328 | |||
| 6329 | u8 shift_type = inst_cream->shift_type; | ||
| 6330 | u8 shift_amount = inst_cream->imm5; | ||
| 6331 | u32 rn_val = RN; | ||
| 6332 | |||
| 6333 | // 32-bit ASR is encoded as an amount of 0. | ||
| 6334 | if (shift_type == 1 && shift_amount == 0) | ||
| 6335 | shift_amount = 31; | ||
| 6336 | |||
| 6337 | if (shift_type == 0) | ||
| 6338 | rn_val <<= shift_amount; | ||
| 6339 | else if (shift_type == 1) | ||
| 6340 | rn_val = ((s32)rn_val >> shift_amount); | ||
| 6341 | |||
| 6342 | bool saturated = false; | ||
| 6343 | rn_val = ARMul_UnsignedSatQ(rn_val, inst_cream->sat_imm, &saturated); | ||
| 6344 | |||
| 6345 | if (saturated) | ||
| 6346 | cpu->Cpsr |= (1 << 27); | ||
| 6347 | |||
| 6348 | RD = rn_val; | ||
| 6349 | } | ||
| 6350 | |||
| 6351 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6352 | INC_PC(sizeof(ssat_inst)); | ||
| 6353 | FETCH_INST; | ||
| 6354 | GOTO_NEXT_INST; | ||
| 6355 | } | ||
| 6356 | |||
| 6265 | USAT16_INST: | 6357 | USAT16_INST: |
| 6266 | USUB16_INST: | 6358 | USUB16_INST: |
| 6267 | USUB8_INST: | 6359 | USUB8_INST: |
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 8b3661c8f..426b67831 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp | |||
| @@ -578,6 +578,41 @@ u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) | |||
| 578 | return left - right; | 578 | return left - right; |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | // Signed saturation. | ||
| 582 | u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 583 | { | ||
| 584 | const u32 max = (1 << shift) - 1; | ||
| 585 | const s32 top = (value >> shift); | ||
| 586 | |||
| 587 | if (top > 0) { | ||
| 588 | *saturation_occurred = true; | ||
| 589 | return max; | ||
| 590 | } | ||
| 591 | else if (top < -1) { | ||
| 592 | *saturation_occurred = true; | ||
| 593 | return ~max; | ||
| 594 | } | ||
| 595 | |||
| 596 | *saturation_occurred = false; | ||
| 597 | return (u32)value; | ||
| 598 | } | ||
| 599 | |||
| 600 | // Unsigned saturation | ||
| 601 | u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 602 | { | ||
| 603 | const u32 max = (1 << shift) - 1; | ||
| 604 | |||
| 605 | if (value < 0) { | ||
| 606 | *saturation_occurred = true; | ||
| 607 | return 0; | ||
| 608 | } else if ((u32)value > max) { | ||
| 609 | *saturation_occurred = true; | ||
| 610 | return max; | ||
| 611 | } | ||
| 612 | |||
| 613 | *saturation_occurred = false; | ||
| 614 | return (u32)value; | ||
| 615 | } | ||
| 581 | 616 | ||
| 582 | /* This function does the work of generating the addresses used in an | 617 | /* This function does the work of generating the addresses used in an |
| 583 | LDC instruction. The code here is always post-indexed, it's up to the | 618 | LDC instruction. The code here is always post-indexed, it's up to the |
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 0f2bcbdb1..8611d7392 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h | |||
| @@ -800,6 +800,8 @@ extern u16 ARMul_UnsignedSaturatedAdd16(u16, u16); | |||
| 800 | extern u8 ARMul_UnsignedSaturatedSub8(u8, u8); | 800 | extern u8 ARMul_UnsignedSaturatedSub8(u8, u8); |
| 801 | extern u16 ARMul_UnsignedSaturatedSub16(u16, u16); | 801 | extern u16 ARMul_UnsignedSaturatedSub16(u16, u16); |
| 802 | extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | 802 | extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8); |
| 803 | extern u32 ARMul_SignedSatQ(s32, u8, bool*); | ||
| 804 | extern u32 ARMul_UnsignedSatQ(s32, u8, bool*); | ||
| 803 | 805 | ||
| 804 | #define DIFF_LOG 0 | 806 | #define DIFF_LOG 0 |
| 805 | #define SAVE_LOG 0 | 807 | #define SAVE_LOG 0 |