From 3895c083cbd5af2f0155a05682ee106255ad08eb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 31 Oct 2014 04:12:07 +0300 Subject: [PATCH] ARMv7: BX, MOV_IMM, IT (ITSTATE register) --- rpcs3/Emu/ARMv7/ARMv7Decoder.h | 6 +- rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp | 221 ++++++++++++++++++++++----- rpcs3/Emu/ARMv7/ARMv7Opcodes.h | 16 +- rpcs3/Emu/ARMv7/ARMv7Thread.cpp | 3 +- rpcs3/Emu/ARMv7/ARMv7Thread.h | 42 +++++ 5 files changed, 239 insertions(+), 49 deletions(-) diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h index 9b8b5e0d34..81b58e9939 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.h @@ -18,11 +18,11 @@ public: const u32 code0 = vm::psv::read16(address & ~1); const u32 code1 = vm::psv::read16(address + 2 & ~1); const u32 data = code0 << 16 | code1; - const u32 arg = address & 1 ? data : code1 << 16 | code0; + const u32 arg = address & 1 ? code1 << 16 | code0 : data; for (auto& opcode : ARMv7_opcode_table) { - if ((opcode.type >= A1) == ((address & 1) == 0) && (data & opcode.mask) == opcode.code) + if ((opcode.type < A1) == ((address & 1) == 0) && (arg & opcode.mask) == opcode.code) { (m_op.*opcode.func)(opcode.length == 2 ? code0 : arg, opcode.type); return opcode.length; @@ -30,6 +30,6 @@ public: } m_op.UNK(data); - return 2; + return address & 1 ? 4 : 2; } }; diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index 9ecf2b4735..f5cf8d64a6 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -150,15 +150,20 @@ void ARMv7Interpreter::ASR_REG(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::B(const u32 data, const ARMv7_encoding type) { - u32 cond = 0xf; + u32 cond = CPU.ITSTATE.advance(); u32 jump = 0; // jump = instr_size + imm32 switch (type) { case T1: { + cond = (data >> 8) & 0xf; + if (cond == 0xf) + { + throw "SVC"; + } + jump = 2 + sign<9, u32>((data & 0xff) << 1); - cond = (data >> 8) & 0xf; if (cond == 0xf) throw "SVC"; break; } case T2: @@ -168,11 +173,16 @@ void ARMv7Interpreter::B(const u32 data, const ARMv7_encoding type) } case T3: { + cond = (data >> 6) & 0xf; + if (cond >= 0xe) + { + throw "Related encodings"; + } + u32 s = (data >> 26) & 0x1; u32 j1 = (data >> 13) & 0x1; u32 j2 = (data >> 11) & 0x1; jump = 4 + sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (data & 0x3f0000) >> 4 | (data & 0x7ff) << 1); - cond = (data >> 6) & 0xf; if (cond >= 0xe) throw "Related encodings"; break; } case T4: @@ -185,8 +195,8 @@ void ARMv7Interpreter::B(const u32 data, const ARMv7_encoding type) } case A1: { - jump = 1 + 4 + sign<26, u32>((data & 0xffffff) << 2); cond = (data >> 28) & 0xf; + jump = 1 + 4 + sign<26, u32>((data & 0xffffff) << 2); break; } } @@ -257,7 +267,9 @@ void ARMv7Interpreter::BKPT(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::BL(const u32 data, const ARMv7_encoding type) { - u32 jump = 0; + u32 cond = CPU.ITSTATE.advance(); + u32 newLR = CPU.PC; + u32 imm32 = 0; switch (type) { @@ -266,30 +278,39 @@ void ARMv7Interpreter::BL(const u32 data, const ARMv7_encoding type) u32 s = (data >> 26) & 0x1; u32 i1 = (data >> 13) & 0x1 ^ s ^ 1; u32 i2 = (data >> 11) & 0x1 ^ s ^ 1; - jump = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); + imm32 = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); + newLR = (CPU.PC + 4) | 1; break; } case A1: { - jump = 4 + sign<26, u32>((data & 0xffffff) << 2); + cond = data >> 28; + imm32 = 4 + sign<26, u32>((data & 0xffffff) << 2); + newLR = (CPU.PC + 4) - 4; break; } default: throw __FUNCTION__; } - CPU.LR = (CPU.PC & 1) ? CPU.PC - 4 : CPU.PC; - CPU.SetBranch(CPU.PC + jump); + if (ConditionPassed(cond)) + { + CPU.LR = newLR; + CPU.SetBranch(CPU.PC + imm32); + } } void ARMv7Interpreter::BLX(const u32 data, const ARMv7_encoding type) { - u32 target; + u32 cond = CPU.ITSTATE.advance(); + u32 newLR = CPU.PC; + u32 target = 0; switch (type) { case T1: { - target = CPU.GPR[(data >> 3) & 0xf]; + target = CPU.read_gpr((data >> 3) & 0xf); + newLR = ((CPU.PC + 2) - 2) | 1; // ??? break; } case T2: @@ -297,34 +318,75 @@ void ARMv7Interpreter::BLX(const u32 data, const ARMv7_encoding type) u32 s = (data >> 26) & 0x1; u32 i1 = (data >> 13) & 0x1 ^ s ^ 1; u32 i2 = (data >> 11) & 0x1 ^ s ^ 1; - target = CPU.PC + 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1) & ~1; + target = (CPU.PC + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); + newLR = (CPU.PC + 4) | 1; break; } case A1: { - target = CPU.GPR[data & 0xf]; - if (!ConditionPassed(data >> 28)) return; + cond = data >> 28; + target = CPU.read_gpr(data & 0xf); + newLR = (CPU.PC + 4) - 4; break; } case A2: { - target = CPU.PC + 5 + sign<25, u32>((data & 0xffffff) << 2 | (data & 0x1000000) >> 23); + target = (CPU.PC + 4 | 1) + sign<25, u32>((data & 0xffffff) << 2 | (data & 0x1000000) >> 23); + newLR = (CPU.PC + 4) - 4; break; } default: throw __FUNCTION__; } - CPU.LR = (CPU.PC & 1) ? CPU.PC - (type == T1 ? 2 : 4) : CPU.PC - 4; // ??? - CPU.SetBranch(target); + if (ConditionPassed(cond)) + { + CPU.LR = newLR; + if (target & 1) + { + CPU.ISET = Thumb; + CPU.SetBranch(target & ~1); + } + else + { + CPU.ISET = ARM; + CPU.SetBranch(target); + } + } } void ARMv7Interpreter::BX(const u32 data, const ARMv7_encoding type) { + u32 cond = CPU.ITSTATE.advance(); + u32 target = 0; + switch (type) { - case A1: throw __FUNCTION__; + case T1: + { + target = CPU.read_gpr((data >> 3) & 0xf); + break; + } + case A1: + { + cond = data >> 28; + target = CPU.read_gpr(data & 0xf); + } default: throw __FUNCTION__; } + + if (ConditionPassed(cond)) + { + if (target & 1) + { + CPU.ISET = Thumb; + CPU.SetBranch(target & ~1); + } + else + { + CPU.ISET = ARM; + CPU.SetBranch(target); + } + } } @@ -336,7 +398,7 @@ void ARMv7Interpreter::CB_Z(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if ((CPU.GPR[data & 0x7] == 0) ^ (data & 0x800)) + if ((CPU.read_gpr(data & 0x7) == 0) ^ (data & 0x800)) { CPU.SetBranch(CPU.PC + 2 + ((data & 0xf8) >> 2) + ((data & 0x200) >> 3)); } @@ -441,7 +503,16 @@ void ARMv7Interpreter::IT(const u32 data, const ARMv7_encoding type) { switch (type) { - case A1: throw __FUNCTION__; + case T1: + { + if ((data & 0xf) == 0) + { + throw "Related encodings"; + } + + CPU.ITSTATE.IT = data & 0xff; + return; + } default: throw __FUNCTION__; } } @@ -711,16 +782,48 @@ void ARMv7Interpreter::MLS(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::MOV_IMM(const u32 data, const ARMv7_encoding type) { - u32 d; - u32 imm; + bool set_flags = CPU.ITSTATE; + bool carry = CPU.APSR.C; + + u32 cond = CPU.ITSTATE.advance(); + u32 d = 0; + u32 imm32 = 0; switch (type) { - case T1: d = (data >> 8) & 0x7; imm = sign<8, u32>(data & 0xff); break; + case T1: + { + d = (data >> 8) & 0x7; + imm32 = sign<8, u32>(data & 0xff); + break; + } + //case T2: + //{ + // set_flags = data & 0x100000; + // d = (data >> 8) & 0xf; + // imm32 = ThumbExpandImm_C((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff), carry); + // break; + //} + case T3: + { + set_flags = false; + d = (data >> 8) & 0xf; + imm32 = (data & 0xf0000) >> 4 | (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + break; + } default: throw __FUNCTION__; } - CPU.write_gpr(d, imm); + if (ConditionPassed(cond)) + { + CPU.write_gpr(d, imm32); + if (set_flags) + { + CPU.APSR.N = imm32 >> 31; + CPU.APSR.Z = imm32 == 0; + CPU.APSR.C = carry; + } + } } void ARMv7Interpreter::MOV_REG(const u32 data, const ARMv7_encoding type) @@ -810,13 +913,29 @@ void ARMv7Interpreter::MVN_RSR(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::NOP(const u32 data, const ARMv7_encoding type) { + u32 cond = CPU.ITSTATE.advance(); + switch (type) { - case T1: break; - case T2: break; - case A1: break; + case T1: + { + break; + } + case T2: + { + break; + } + case A1: + { + cond = data >> 28; + break; + } default: throw __FUNCTION__; } + + if (ConditionPassed(cond)) + { + } } @@ -879,6 +998,7 @@ void ARMv7Interpreter::PKH(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::POP(const u32 data, const ARMv7_encoding type) { + u32 cond = CPU.ITSTATE.advance(); u16 reg_list = 0; switch (type) @@ -900,31 +1020,39 @@ void ARMv7Interpreter::POP(const u32 data, const ARMv7_encoding type) } case A1: { - reg_list = data & 0xffff; if (BitCount(reg_list) < 2) throw "LDM / LDMIA / LDMFD"; - if (!ConditionPassed(data >> 28)) return; + cond = data >> 28; + reg_list = data & 0xffff; + if (BitCount(reg_list) < 2) + { + throw "LDM / LDMIA / LDMFD"; + } break; } case A2: { + cond = data >> 28; reg_list = 1 << ((data >> 12) & 0xf); - if (!ConditionPassed(data >> 28)) return; break; } default: throw __FUNCTION__; } - for (u16 mask = 1, i = 0; mask; mask <<= 1, i++) + if (ConditionPassed(cond)) { - if (reg_list & mask) + for (u16 mask = 1, i = 0; mask; mask <<= 1, i++) { - CPU.write_gpr(i, vm::psv::read32(CPU.SP)); - CPU.SP += 4; + if (reg_list & mask) + { + CPU.write_gpr(i, vm::psv::read32(CPU.SP)); + CPU.SP += 4; + } } } } void ARMv7Interpreter::PUSH(const u32 data, const ARMv7_encoding type) { + u32 cond = CPU.ITSTATE.advance(); u16 reg_list = 0; switch (type) @@ -946,25 +1074,32 @@ void ARMv7Interpreter::PUSH(const u32 data, const ARMv7_encoding type) } case A1: { - reg_list = data & 0xffff; if (BitCount(reg_list) < 2) throw "STMDB / STMFD"; - if (!ConditionPassed(data >> 28)) return; + cond = data >> 28; + reg_list = data & 0xffff; + if (BitCount(reg_list) < 2) + { + throw "STMDB / STMFD"; + } break; } case A2: { + cond = data >> 28; reg_list = 1 << ((data >> 12) & 0xf); - if (!ConditionPassed(data >> 28)) return; break; } default: throw __FUNCTION__; } - for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--) + if (ConditionPassed(cond)) { - if (reg_list & mask) + for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--) { - CPU.SP -= 4; - vm::psv::write32(CPU.SP, CPU.read_gpr(i)); + if (reg_list & mask) + { + CPU.SP -= 4; + vm::psv::write32(CPU.SP, CPU.read_gpr(i)); + } } } } @@ -1657,9 +1792,11 @@ void ARMv7Interpreter::SUB_RSR(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::SUB_SPI(const u32 data, const ARMv7_encoding type) { + u32 cond = CPU.ITSTATE.advance(); + switch (type) { - case T1: CPU.SP -= (data & 0x7f) << 2; return; + case T1: if (ConditionPassed(cond)) CPU.SP -= (data & 0x7f) << 2; return; default: throw __FUNCTION__; } } diff --git a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h index e73f44899f..d391b7fcd1 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h +++ b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h @@ -338,7 +338,7 @@ struct ARMv7_opcode_t static const ARMv7_opcode_t ARMv7_opcode_table[] = { - ARMv7_OP2(0xffff, 0x0000, T1, NULL_OP), + ARMv7_OP2(0xffff, 0x0000, T1, NULL_OP), // ??? ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM), ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM), @@ -555,7 +555,17 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8000, T2, NOP), ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf000, A1, NOP), - // + ARMv7_OP4(0xfbe0, 0x8000, 0xf060, 0x0000, T1, ORN_IMM), + ARMv7_OP4(0xffe0, 0x8000, 0xea60, 0x0000, T1, ORN_REG), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM), + ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR), + + // TODO (PKH...) ARMv7_OP2(0xfe00, 0xbc00, T1, POP), ARMv7_OP4(0xffff, 0x0000, 0xe8bd, 0x0000, T2, POP), @@ -569,7 +579,7 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0x0fff, 0x0000, 0x092d, 0x0000, A1, PUSH), ARMv7_OP4(0x0fff, 0x0fff, 0x052d, 0x0004, A2, PUSH), - // + // TODO (Q*...) ARMv7_OP2(0xf800, 0x6000, T1, STR_IMM), ARMv7_OP2(0xf800, 0x9000, T2, STR_IMM), diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 162f08a918..ea8976b38e 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -18,7 +18,8 @@ void ARMv7Thread::InitRegs() memset(GPR, 0, sizeof(GPR[0]) * 15); APSR.APSR = 0; IPSR.IPSR = 0; - PC |= 1; + ISET = Thumb; + ITSTATE.IT = 0; SP = m_stack_addr + m_stack_size; } diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index e95e9b49ec..0ef26562ff 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -1,6 +1,14 @@ #pragma once #include "Emu/CPU/CPUThread.h" +enum ARMv7InstructionSet +{ + ARM, + Thumb, + Jazelle, + ThumbEE, +}; + class ARMv7Thread : public CPUThread { public: @@ -38,6 +46,7 @@ public: }; u32 APSR; + } APSR; union @@ -49,8 +58,41 @@ public: }; u32 IPSR; + } IPSR; + ARMv7InstructionSet ISET; + + union + { + struct + { + u8 cond : 3; + u8 state : 5; + }; + + u8 IT; + + u32 advance() + { + const u32 res = (state & 0xf) ? (cond << 1 | state >> 4) : 0xe /* true */; + + state <<= 1; + if ((state & 0xf) == 0) // if no d + { + IT = 0; // clear ITSTATE + } + + return res; + } + + operator bool() const + { + return (state & 0xf) != 0; + } + + } ITSTATE; + void write_gpr(u32 n, u32 value) { assert(n < 16);