diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_dec.cpp | 25 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_dec.h | 16 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 93 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_thumb.cpp | 28 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_thumb.h | 28 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/armstate.h | 25 |
6 files changed, 91 insertions, 124 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 3ab9f2c17..ee4288314 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | #include "core/arm/dyncom/arm_dyncom_dec.h" | 5 | #include "core/arm/dyncom/arm_dyncom_dec.h" |
| 6 | #include "core/arm/skyeye_common/armsupp.h" | 6 | #include "core/arm/skyeye_common/armsupp.h" |
| 7 | 7 | ||
| 8 | const ISEITEM arm_instruction[] = { | 8 | const InstructionSetEncodingItem arm_instruction[] = { |
| 9 | { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, | 9 | { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, |
| 10 | { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, | 10 | { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, |
| 11 | { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, | 11 | { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, |
| @@ -207,7 +207,7 @@ const ISEITEM arm_instruction[] = { | |||
| 207 | { "bbl", 1, 0, { 25, 27, 0x00000005 }}, | 207 | { "bbl", 1, 0, { 25, 27, 0x00000005 }}, |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| 210 | const ISEITEM arm_exclusion_code[] = { | 210 | const InstructionSetEncodingItem arm_exclusion_code[] = { |
| 211 | { "vmla", 0, ARMVFP2, { 0 }}, | 211 | { "vmla", 0, ARMVFP2, { 0 }}, |
| 212 | { "vmls", 0, ARMVFP2, { 0 }}, | 212 | { "vmls", 0, ARMVFP2, { 0 }}, |
| 213 | { "vnmla", 0, ARMVFP2, { 0 }}, | 213 | { "vnmla", 0, ARMVFP2, { 0 }}, |
| @@ -414,14 +414,13 @@ const ISEITEM arm_exclusion_code[] = { | |||
| 414 | { "invalid", 0, INVALID, { 0 }} | 414 | { "invalid", 0, INVALID, { 0 }} |
| 415 | }; | 415 | }; |
| 416 | 416 | ||
| 417 | int decode_arm_instr(u32 instr, s32* idx) { | 417 | ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) { |
| 418 | int n = 0; | 418 | int n = 0; |
| 419 | int base = 0; | 419 | int base = 0; |
| 420 | int ret = DECODE_FAILURE; | 420 | int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); |
| 421 | int i = 0; | 421 | ARMDecodeStatus ret = ARMDecodeStatus::FAILURE; |
| 422 | int instr_slots = sizeof(arm_instruction) / sizeof(ISEITEM); | ||
| 423 | 422 | ||
| 424 | for (i = 0; i < instr_slots; i++) { | 423 | for (int i = 0; i < instr_slots; i++) { |
| 425 | n = arm_instruction[i].attribute_value; | 424 | n = arm_instruction[i].attribute_value; |
| 426 | base = 0; | 425 | base = 0; |
| 427 | 426 | ||
| @@ -438,11 +437,11 @@ int decode_arm_instr(u32 instr, s32* idx) { | |||
| 438 | n--; | 437 | n--; |
| 439 | } | 438 | } |
| 440 | 439 | ||
| 441 | // All conditions is satisfied. | 440 | // All conditions are satisfied. |
| 442 | if (n == 0) | 441 | if (n == 0) |
| 443 | ret = DECODE_SUCCESS; | 442 | ret = ARMDecodeStatus::SUCCESS; |
| 444 | 443 | ||
| 445 | if (ret == DECODE_SUCCESS) { | 444 | if (ret == ARMDecodeStatus::SUCCESS) { |
| 446 | n = arm_exclusion_code[i].attribute_value; | 445 | n = arm_exclusion_code[i].attribute_value; |
| 447 | if (n != 0) { | 446 | if (n != 0) { |
| 448 | base = 0; | 447 | base = 0; |
| @@ -454,13 +453,13 @@ int decode_arm_instr(u32 instr, s32* idx) { | |||
| 454 | n--; | 453 | n--; |
| 455 | } | 454 | } |
| 456 | 455 | ||
| 457 | // All conditions is satisfied. | 456 | // All conditions are satisfied. |
| 458 | if (n == 0) | 457 | if (n == 0) |
| 459 | ret = DECODE_FAILURE; | 458 | ret = ARMDecodeStatus::FAILURE; |
| 460 | } | 459 | } |
| 461 | } | 460 | } |
| 462 | 461 | ||
| 463 | if (ret == DECODE_SUCCESS) { | 462 | if (ret == ARMDecodeStatus::SUCCESS) { |
| 464 | *idx = i; | 463 | *idx = i; |
| 465 | return ret; | 464 | return ret; |
| 466 | } | 465 | } |
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h index 5f6279627..d7170e0fc 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ b/src/core/arm/dyncom/arm_dyncom_dec.h | |||
| @@ -6,22 +6,20 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | int decode_arm_instr(u32 instr, s32* idx); | 9 | enum class ARMDecodeStatus { |
| 10 | 10 | SUCCESS, | |
| 11 | enum DECODE_STATUS { | 11 | FAILURE |
| 12 | DECODE_SUCCESS, | ||
| 13 | DECODE_FAILURE | ||
| 14 | }; | 12 | }; |
| 15 | 13 | ||
| 16 | struct instruction_set_encoding_item { | 14 | ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx); |
| 15 | |||
| 16 | struct InstructionSetEncodingItem { | ||
| 17 | const char *name; | 17 | const char *name; |
| 18 | int attribute_value; | 18 | int attribute_value; |
| 19 | int version; | 19 | int version; |
| 20 | u32 content[21]; | 20 | u32 content[21]; |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 24 | |||
| 25 | // ARM versions | 23 | // ARM versions |
| 26 | enum { | 24 | enum { |
| 27 | INVALID = 0, | 25 | INVALID = 0, |
| @@ -38,4 +36,4 @@ enum { | |||
| 38 | ARMV6K, | 36 | ARMV6K, |
| 39 | }; | 37 | }; |
| 40 | 38 | ||
| 41 | extern const ISEITEM arm_instruction[]; | 39 | extern const InstructionSetEncodingItem arm_instruction[]; |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index cf09acb4e..d022546ed 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -47,27 +47,6 @@ enum { | |||
| 47 | 47 | ||
| 48 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); | 48 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); |
| 49 | 49 | ||
| 50 | // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag. | ||
| 51 | // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to | ||
| 52 | // support LDR/STREXD. | ||
| 53 | static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; | ||
| 54 | |||
| 55 | // Exclusive memory access | ||
| 56 | static int exclusive_detect(ARMul_State* state, u32 addr) { | ||
| 57 | if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK)) | ||
| 58 | return 0; | ||
| 59 | else | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | static void add_exclusive_addr(ARMul_State* state, u32 addr){ | ||
| 64 | state->exclusive_tag = addr & RESERVATION_GRANULE_MASK; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void remove_exclusive(ARMul_State* state, u32 addr){ | ||
| 68 | state->exclusive_tag = 0xFFFFFFFF; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int CondPassed(ARMul_State* cpu, unsigned int cond) { | 50 | static int CondPassed(ARMul_State* cpu, unsigned int cond) { |
| 72 | const u32 NFLAG = cpu->NFlag; | 51 | const u32 NFLAG = cpu->NFlag; |
| 73 | const u32 ZFLAG = cpu->ZFlag; | 52 | const u32 ZFLAG = cpu->ZFlag; |
| @@ -3489,21 +3468,15 @@ enum { | |||
| 3489 | FETCH_FAILURE | 3468 | FETCH_FAILURE |
| 3490 | }; | 3469 | }; |
| 3491 | 3470 | ||
| 3492 | static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) { | 3471 | static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) { |
| 3493 | // Check if in Thumb mode | 3472 | // Check if in Thumb mode |
| 3494 | tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size); | 3473 | ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size); |
| 3495 | if(ret == t_branch){ | 3474 | if (ret == ThumbDecodeStatus::BRANCH) { |
| 3496 | // TODO: FIXME, endian should be judged | ||
| 3497 | u32 tinstr; | ||
| 3498 | if((addr & 0x3) != 0) | ||
| 3499 | tinstr = inst >> 16; | ||
| 3500 | else | ||
| 3501 | tinstr = inst & 0xFFFF; | ||
| 3502 | |||
| 3503 | int inst_index; | 3475 | int inst_index; |
| 3504 | int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); | 3476 | int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); |
| 3477 | u32 tinstr = GetThumbInstruction(inst, addr); | ||
| 3505 | 3478 | ||
| 3506 | switch((tinstr & 0xF800) >> 11){ | 3479 | switch ((tinstr & 0xF800) >> 11) { |
| 3507 | case 26: | 3480 | case 26: |
| 3508 | case 27: | 3481 | case 27: |
| 3509 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ | 3482 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ |
| @@ -3536,7 +3509,7 @@ static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_s | |||
| 3536 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | 3509 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); |
| 3537 | break; | 3510 | break; |
| 3538 | default: | 3511 | default: |
| 3539 | ret = t_undefined; | 3512 | ret = ThumbDecodeStatus::UNDEFINED; |
| 3540 | break; | 3513 | break; |
| 3541 | } | 3514 | } |
| 3542 | } | 3515 | } |
| @@ -3548,10 +3521,6 @@ enum { | |||
| 3548 | FETCH_EXCEPTION | 3521 | FETCH_EXCEPTION |
| 3549 | }; | 3522 | }; |
| 3550 | 3523 | ||
| 3551 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 3552 | |||
| 3553 | extern const ISEITEM arm_instruction[]; | ||
| 3554 | |||
| 3555 | static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { | 3524 | static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { |
| 3556 | Common::Profiling::ScopeTimer timer_decode(profile_decode); | 3525 | Common::Profiling::ScopeTimer timer_decode(profile_decode); |
| 3557 | 3526 | ||
| @@ -3573,20 +3542,19 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { | |||
| 3573 | inst = Memory::Read32(phys_addr & 0xFFFFFFFC); | 3542 | inst = Memory::Read32(phys_addr & 0xFFFFFFFC); |
| 3574 | 3543 | ||
| 3575 | size++; | 3544 | size++; |
| 3576 | // If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction | 3545 | // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction |
| 3577 | if (cpu->TFlag) { | 3546 | if (cpu->TFlag) { |
| 3578 | uint32_t arm_inst; | 3547 | uint32_t arm_inst; |
| 3579 | tdstate state = decode_thumb_instr(inst, phys_addr, &arm_inst, &inst_size, &inst_base); | 3548 | ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base); |
| 3580 | 3549 | ||
| 3581 | // We have translated the branch instruction of thumb in thumb decoder | 3550 | // We have translated the Thumb branch instruction in the Thumb decoder |
| 3582 | if(state == t_branch){ | 3551 | if (state == ThumbDecodeStatus::BRANCH) { |
| 3583 | goto translated; | 3552 | goto translated; |
| 3584 | } | 3553 | } |
| 3585 | inst = arm_inst; | 3554 | inst = arm_inst; |
| 3586 | } | 3555 | } |
| 3587 | 3556 | ||
| 3588 | ret = decode_arm_instr(inst, &idx); | 3557 | if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { |
| 3589 | if (ret == DECODE_FAILURE) { | ||
| 3590 | std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); | 3558 | std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); |
| 3591 | LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst); | 3559 | LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst); |
| 3592 | LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); | 3560 | LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); |
| @@ -4174,9 +4142,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4174 | 4142 | ||
| 4175 | CLREX_INST: | 4143 | CLREX_INST: |
| 4176 | { | 4144 | { |
| 4177 | remove_exclusive(cpu, 0); | 4145 | cpu->UnsetExclusiveMemoryAddress(); |
| 4178 | cpu->exclusive_state = 0; | ||
| 4179 | |||
| 4180 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4146 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4181 | INC_PC(sizeof(clrex_inst)); | 4147 | INC_PC(sizeof(clrex_inst)); |
| 4182 | FETCH_INST; | 4148 | FETCH_INST; |
| @@ -4543,8 +4509,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4543 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4509 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4544 | unsigned int read_addr = RN; | 4510 | unsigned int read_addr = RN; |
| 4545 | 4511 | ||
| 4546 | add_exclusive_addr(cpu, read_addr); | 4512 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4547 | cpu->exclusive_state = 1; | ||
| 4548 | 4513 | ||
| 4549 | RD = cpu->ReadMemory32(read_addr); | 4514 | RD = cpu->ReadMemory32(read_addr); |
| 4550 | if (inst_cream->Rd == 15) { | 4515 | if (inst_cream->Rd == 15) { |
| @@ -4563,8 +4528,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4563 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4528 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4564 | unsigned int read_addr = RN; | 4529 | unsigned int read_addr = RN; |
| 4565 | 4530 | ||
| 4566 | add_exclusive_addr(cpu, read_addr); | 4531 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4567 | cpu->exclusive_state = 1; | ||
| 4568 | 4532 | ||
| 4569 | RD = Memory::Read8(read_addr); | 4533 | RD = Memory::Read8(read_addr); |
| 4570 | if (inst_cream->Rd == 15) { | 4534 | if (inst_cream->Rd == 15) { |
| @@ -4583,8 +4547,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4583 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4547 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4584 | unsigned int read_addr = RN; | 4548 | unsigned int read_addr = RN; |
| 4585 | 4549 | ||
| 4586 | add_exclusive_addr(cpu, read_addr); | 4550 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4587 | cpu->exclusive_state = 1; | ||
| 4588 | 4551 | ||
| 4589 | RD = cpu->ReadMemory16(read_addr); | 4552 | RD = cpu->ReadMemory16(read_addr); |
| 4590 | if (inst_cream->Rd == 15) { | 4553 | if (inst_cream->Rd == 15) { |
| @@ -4603,8 +4566,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4603 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4566 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4604 | unsigned int read_addr = RN; | 4567 | unsigned int read_addr = RN; |
| 4605 | 4568 | ||
| 4606 | add_exclusive_addr(cpu, read_addr); | 4569 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4607 | cpu->exclusive_state = 1; | ||
| 4608 | 4570 | ||
| 4609 | RD = cpu->ReadMemory32(read_addr); | 4571 | RD = cpu->ReadMemory32(read_addr); |
| 4610 | RD2 = cpu->ReadMemory32(read_addr + 4); | 4572 | RD2 = cpu->ReadMemory32(read_addr + 4); |
| @@ -6089,10 +6051,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6089 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6051 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6090 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6052 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6091 | 6053 | ||
| 6092 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6054 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6093 | remove_exclusive(cpu, write_addr); | 6055 | cpu->UnsetExclusiveMemoryAddress(); |
| 6094 | cpu->exclusive_state = 0; | ||
| 6095 | |||
| 6096 | cpu->WriteMemory32(write_addr, RM); | 6056 | cpu->WriteMemory32(write_addr, RM); |
| 6097 | RD = 0; | 6057 | RD = 0; |
| 6098 | } else { | 6058 | } else { |
| @@ -6111,10 +6071,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6111 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6071 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6112 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6072 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6113 | 6073 | ||
| 6114 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6074 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6115 | remove_exclusive(cpu, write_addr); | 6075 | cpu->UnsetExclusiveMemoryAddress(); |
| 6116 | cpu->exclusive_state = 0; | ||
| 6117 | |||
| 6118 | Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); | 6076 | Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); |
| 6119 | RD = 0; | 6077 | RD = 0; |
| 6120 | } else { | 6078 | } else { |
| @@ -6133,9 +6091,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6133 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6091 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6134 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6092 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6135 | 6093 | ||
| 6136 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6094 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6137 | remove_exclusive(cpu, write_addr); | 6095 | cpu->UnsetExclusiveMemoryAddress(); |
| 6138 | cpu->exclusive_state = 0; | ||
| 6139 | 6096 | ||
| 6140 | const u32 rt = cpu->Reg[inst_cream->Rm + 0]; | 6097 | const u32 rt = cpu->Reg[inst_cream->Rm + 0]; |
| 6141 | const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; | 6098 | const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; |
| @@ -6165,10 +6122,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6165 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6122 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6166 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6123 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6167 | 6124 | ||
| 6168 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6125 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6169 | remove_exclusive(cpu, write_addr); | 6126 | cpu->UnsetExclusiveMemoryAddress(); |
| 6170 | cpu->exclusive_state = 0; | ||
| 6171 | |||
| 6172 | cpu->WriteMemory16(write_addr, RM); | 6127 | cpu->WriteMemory16(write_addr, RM); |
| 6173 | RD = 0; | 6128 | RD = 0; |
| 6174 | } else { | 6129 | } else { |
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index 2860af376..29272fd5d 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp | |||
| @@ -12,15 +12,9 @@ | |||
| 12 | // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions | 12 | // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions |
| 13 | // allows easier simulation of the special dual BL instruction. | 13 | // allows easier simulation of the special dual BL instruction. |
| 14 | 14 | ||
| 15 | tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | 15 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { |
| 16 | tdstate valid = t_uninitialized; | 16 | ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED; |
| 17 | u32 tinstr = instr; | 17 | u32 tinstr = GetThumbInstruction(instr, addr); |
| 18 | |||
| 19 | // The endian should be judge here | ||
| 20 | if((addr & 0x3) != 0) | ||
| 21 | tinstr = instr >> 16; | ||
| 22 | else | ||
| 23 | tinstr &= 0xFFFF; | ||
| 24 | 18 | ||
| 25 | *ainstr = 0xDEADC0DE; // Debugging to catch non updates | 19 | *ainstr = 0xDEADC0DE; // Debugging to catch non updates |
| 26 | 20 | ||
| @@ -357,21 +351,21 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 357 | else | 351 | else |
| 358 | *ainstr |= (tinstr & 0x00FF); | 352 | *ainstr |= (tinstr & 0x00FF); |
| 359 | } else if ((tinstr & 0x0F00) != 0x0E00) | 353 | } else if ((tinstr & 0x0F00) != 0x0E00) |
| 360 | valid = t_branch; | 354 | valid = ThumbDecodeStatus::BRANCH; |
| 361 | else // UNDEFINED : cc=1110(AL) uses different format | 355 | else // UNDEFINED : cc=1110(AL) uses different format |
| 362 | valid = t_undefined; | 356 | valid = ThumbDecodeStatus::UNDEFINED; |
| 363 | 357 | ||
| 364 | break; | 358 | break; |
| 365 | 359 | ||
| 366 | case 28: // B | 360 | case 28: // B |
| 367 | valid = t_branch; | 361 | valid = ThumbDecodeStatus::BRANCH; |
| 368 | break; | 362 | break; |
| 369 | 363 | ||
| 370 | case 29: | 364 | case 29: |
| 371 | if(tinstr & 0x1) | 365 | if (tinstr & 0x1) |
| 372 | valid = t_undefined; | 366 | valid = ThumbDecodeStatus::UNDEFINED; |
| 373 | else | 367 | else |
| 374 | valid = t_branch; | 368 | valid = ThumbDecodeStatus::BRANCH; |
| 375 | break; | 369 | break; |
| 376 | 370 | ||
| 377 | case 30: // BL instruction 1 | 371 | case 30: // BL instruction 1 |
| @@ -380,7 +374,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 380 | // simulation simple (from the user perspective) we check if the following instruction is | 374 | // simulation simple (from the user perspective) we check if the following instruction is |
| 381 | // the second half of this BL, and if it is we simulate it immediately | 375 | // the second half of this BL, and if it is we simulate it immediately |
| 382 | 376 | ||
| 383 | valid = t_branch; | 377 | valid = ThumbDecodeStatus::BRANCH; |
| 384 | break; | 378 | break; |
| 385 | 379 | ||
| 386 | case 31: // BL instruction 2 | 380 | case 31: // BL instruction 2 |
| @@ -389,7 +383,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 389 | // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the | 383 | // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the |
| 390 | // simulation of it on its own, with undefined results if r14 is not suitably initialised. | 384 | // simulation of it on its own, with undefined results if r14 is not suitably initialised. |
| 391 | 385 | ||
| 392 | valid = t_branch; | 386 | valid = ThumbDecodeStatus::BRANCH; |
| 393 | break; | 387 | break; |
| 394 | } | 388 | } |
| 395 | 389 | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h index c06f09580..447974363 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.h +++ b/src/core/arm/dyncom/arm_dyncom_thumb.h | |||
| @@ -28,20 +28,22 @@ | |||
| 28 | 28 | ||
| 29 | #include "common/common_types.h" | 29 | #include "common/common_types.h" |
| 30 | 30 | ||
| 31 | enum tdstate { | 31 | enum class ThumbDecodeStatus { |
| 32 | t_undefined, // Undefined Thumb instruction | 32 | UNDEFINED, // Undefined Thumb instruction |
| 33 | t_decoded, // Instruction decoded to ARM equivalent | 33 | DECODED, // Instruction decoded to ARM equivalent |
| 34 | t_branch, // Thumb branch (already processed) | 34 | BRANCH, // Thumb branch (already processed) |
| 35 | t_uninitialized, | 35 | UNINITIALIZED, |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | 38 | // Translates a Thumb mode instruction into its ARM equivalent. |
| 39 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | ||
| 39 | 40 | ||
| 40 | static inline u32 get_thumb_instr(u32 instr, u32 pc) { | 41 | static inline u32 GetThumbInstruction(u32 instr, u32 address) { |
| 41 | u32 tinstr; | 42 | // Normally you would need to handle instruction endianness, |
| 42 | if ((pc & 0x3) != 0) | 43 | // however, it is fixed to little-endian on the MPCore, so |
| 43 | tinstr = instr >> 16; | 44 | // there's no need to check for this beforehand. |
| 44 | else | 45 | if ((address & 0x3) != 0) |
| 45 | tinstr = instr & 0xFFFF; | 46 | return instr >> 16; |
| 46 | return tinstr; | 47 | |
| 48 | return instr & 0xFFFF; | ||
| 47 | } | 49 | } |
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h index 88c1dab9d..b364e2621 100644 --- a/src/core/arm/skyeye_common/armstate.h +++ b/src/core/arm/skyeye_common/armstate.h | |||
| @@ -163,6 +163,19 @@ public: | |||
| 163 | u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; | 163 | u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; |
| 164 | void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | 164 | void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); |
| 165 | 165 | ||
| 166 | // Exclusive memory access functions | ||
| 167 | bool IsExclusiveMemoryAccess(u32 address) const { | ||
| 168 | return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK); | ||
| 169 | } | ||
| 170 | void SetExclusiveMemoryAddress(u32 address) { | ||
| 171 | exclusive_tag = address & RESERVATION_GRANULE_MASK; | ||
| 172 | exclusive_state = true; | ||
| 173 | } | ||
| 174 | void UnsetExclusiveMemoryAddress() { | ||
| 175 | exclusive_tag = 0xFFFFFFFF; | ||
| 176 | exclusive_state = false; | ||
| 177 | } | ||
| 178 | |||
| 166 | // Whether or not the given CPU is in big endian mode (E bit is set) | 179 | // Whether or not the given CPU is in big endian mode (E bit is set) |
| 167 | bool InBigEndianMode() const { | 180 | bool InBigEndianMode() const { |
| 168 | return (Cpsr & (1 << 9)) != 0; | 181 | return (Cpsr & (1 << 9)) != 0; |
| @@ -203,9 +216,6 @@ public: | |||
| 203 | 216 | ||
| 204 | u32 Mode; // The current mode | 217 | u32 Mode; // The current mode |
| 205 | u32 Bank; // The current register bank | 218 | u32 Bank; // The current register bank |
| 206 | u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode | ||
| 207 | u32 exclusive_state; | ||
| 208 | u32 exclusive_result; | ||
| 209 | 219 | ||
| 210 | u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed | 220 | u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed |
| 211 | unsigned int shifter_carry_out; | 221 | unsigned int shifter_carry_out; |
| @@ -230,4 +240,13 @@ public: | |||
| 230 | 240 | ||
| 231 | private: | 241 | private: |
| 232 | void ResetMPCoreCP15Registers(); | 242 | void ResetMPCoreCP15Registers(); |
| 243 | |||
| 244 | // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag. | ||
| 245 | // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to | ||
| 246 | // support LDR/STREXD. | ||
| 247 | static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; | ||
| 248 | |||
| 249 | u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode | ||
| 250 | u32 exclusive_result; | ||
| 251 | bool exclusive_state; | ||
| 233 | }; | 252 | }; |