aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/arm
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm')
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp141
-rw-r--r--src/core/arm/disassembler/arm_disasm.h18
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp10
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp54
4 files changed, 193 insertions, 30 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index aaf47b3f..964e3011 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -4,6 +4,7 @@
#include "common/string_util.h"
#include "core/arm/disassembler/arm_disasm.h"
+#include "core/arm/skyeye_common/armsupp.h"
static const char *cond_names[] = {
"eq",
@@ -37,6 +38,7 @@ static const char *opcode_names[] = {
"blx",
"bx",
"cdp",
+ "clrex",
"clz",
"cmn",
"cmp",
@@ -46,6 +48,10 @@ static const char *opcode_names[] = {
"ldr",
"ldrb",
"ldrbt",
+ "ldrex",
+ "ldrexb",
+ "ldrexd",
+ "ldrexh",
"ldrh",
"ldrsb",
"ldrsh",
@@ -58,11 +64,13 @@ static const char *opcode_names[] = {
"msr",
"mul",
"mvn",
+ "nop",
"orr",
"pld",
"rsb",
"rsc",
"sbc",
+ "sev",
"smlal",
"smull",
"stc",
@@ -70,6 +78,10 @@ static const char *opcode_names[] = {
"str",
"strb",
"strbt",
+ "strex",
+ "strexb",
+ "strexd",
+ "strexh",
"strh",
"strt",
"sub",
@@ -80,6 +92,9 @@ static const char *opcode_names[] = {
"tst",
"umlal",
"umull",
+ "wfe",
+ "wfi",
+ "yield",
"undefined",
"adc",
@@ -172,6 +187,8 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
return DisassembleBX(insn);
case OP_CDP:
return "cdp";
+ case OP_CLREX:
+ return "clrex";
case OP_CLZ:
return DisassembleCLZ(insn);
case OP_LDC:
@@ -188,6 +205,15 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
case OP_STRBT:
case OP_STRT:
return DisassembleMem(insn);
+ case OP_LDREX:
+ case OP_LDREXB:
+ case OP_LDREXD:
+ case OP_LDREXH:
+ case OP_STREX:
+ case OP_STREXB:
+ case OP_STREXD:
+ case OP_STREXH:
+ return DisassembleREX(opcode, insn);
case OP_LDRH:
case OP_LDRSB:
case OP_LDRSH:
@@ -204,6 +230,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
return DisassembleMSR(insn);
case OP_MUL:
return DisassembleMUL(opcode, insn);
+ case OP_NOP:
+ case OP_SEV:
+ case OP_WFE:
+ case OP_WFI:
+ case OP_YIELD:
+ return DisassembleNoOperands(opcode, insn);
case OP_PLD:
return DisassemblePLD(insn);
case OP_STC:
@@ -646,6 +678,12 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
}
+std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn)
+{
+ uint32_t cond = BITS(insn, 28, 31);
+ return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond));
+}
+
std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
{
uint8_t is_reg = (insn >> 25) & 0x1;
@@ -669,6 +707,36 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
}
}
+std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) {
+ uint32_t rn = BITS(insn, 16, 19);
+ uint32_t rd = BITS(insn, 12, 15);
+ uint32_t rt = BITS(insn, 0, 3);
+ uint32_t cond = BITS(insn, 28, 31);
+
+ switch (opcode) {
+ case OP_STREX:
+ case OP_STREXB:
+ case OP_STREXH:
+ return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
+ cond_to_str(cond), rd, rt, rn);
+ case OP_STREXD:
+ return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode],
+ cond_to_str(cond), rd, rt, rt + 1, rn);
+
+ // for LDREX instructions, rd corresponds to Rt from reference manual
+ case OP_LDREX:
+ case OP_LDREXB:
+ case OP_LDREXH:
+ return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode],
+ cond_to_str(cond), rd, rn);
+ case OP_LDREXD:
+ return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
+ cond_to_str(cond), rd, rd + 1, rn);
+ default:
+ return opcode_names[OP_UNDEFINED];
+ }
+}
+
std::string ARM_Disasm::DisassembleSWI(uint32_t insn)
{
uint8_t cond = (insn >> 28) & 0xf;
@@ -721,12 +789,9 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
}
uint32_t bits7_4 = (insn >> 4) & 0xf;
if (bits7_4 == 0x9) {
- if ((insn & 0x0ff00ff0) == 0x01000090) {
- // Swp instruction
- uint8_t bit22 = (insn >> 22) & 0x1;
- if (bit22)
- return OP_SWPB;
- return OP_SWP;
+ uint32_t bit24 = BIT(insn, 24);
+ if (bit24) {
+ return DecodeSyncPrimitive(insn);
}
// One of the multiply instructions
return DecodeMUL(insn);
@@ -739,6 +804,12 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
}
}
+ uint32_t op1 = BITS(insn, 20, 24);
+ if (bit25 && (op1 == 0x12 || op1 == 0x16)) {
+ // One of the MSR (immediate) and hints instructions
+ return DecodeMSRImmAndHints(insn);
+ }
+
// One of the data processing instructions
return DecodeALU(insn);
}
@@ -754,6 +825,10 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) {
// Pre-load
return OP_PLD;
}
+ if (insn == 0xf57ff01f) {
+ // Clear-Exclusive
+ return OP_CLREX;
+ }
if (is_load) {
if (is_byte) {
// Load byte
@@ -836,6 +911,35 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
return OP_MCR;
}
+Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) {
+ uint32_t op = BITS(insn, 20, 23);
+ uint32_t bit22 = BIT(insn, 22);
+ switch (op) {
+ case 0x0:
+ if (bit22)
+ return OP_SWPB;
+ return OP_SWP;
+ case 0x8:
+ return OP_STREX;
+ case 0x9:
+ return OP_LDREX;
+ case 0xA:
+ return OP_STREXD;
+ case 0xB:
+ return OP_LDREXD;
+ case 0xC:
+ return OP_STREXB;
+ case 0xD:
+ return OP_LDREXB;
+ case 0xE:
+ return OP_STREXH;
+ case 0xF:
+ return OP_LDREXH;
+ default:
+ return OP_UNDEFINED;
+ }
+}
+
Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
uint8_t bit24 = (insn >> 24) & 0x1;
if (bit24 != 0) {
@@ -870,6 +974,31 @@ Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
return OP_SMLAL;
}
+Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
+ uint32_t op = BIT(insn, 22);
+ uint32_t op1 = BITS(insn, 16, 19);
+ uint32_t op2 = BITS(insn, 0, 7);
+
+ if (op == 0 && op1 == 0) {
+ switch (op2) {
+ case 0x0:
+ return OP_NOP;
+ case 0x1:
+ return OP_YIELD;
+ case 0x2:
+ return OP_WFE;
+ case 0x3:
+ return OP_WFI;
+ case 0x4:
+ return OP_SEV;
+ default:
+ return OP_UNDEFINED;
+ }
+ }
+
+ return OP_MSR;
+}
+
Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) {
uint8_t is_load = (insn >> 20) & 0x1;
uint8_t bits_65 = (insn >> 5) & 0x3;
diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h
index f94bd466..d04fd21e 100644
--- a/src/core/arm/disassembler/arm_disasm.h
+++ b/src/core/arm/disassembler/arm_disasm.h
@@ -20,6 +20,7 @@ enum Opcode {
OP_BLX,
OP_BX,
OP_CDP,
+ OP_CLREX,
OP_CLZ,
OP_CMN,
OP_CMP,
@@ -29,6 +30,10 @@ enum Opcode {
OP_LDR,
OP_LDRB,
OP_LDRBT,
+ OP_LDREX,
+ OP_LDREXB,
+ OP_LDREXD,
+ OP_LDREXH,
OP_LDRH,
OP_LDRSB,
OP_LDRSH,
@@ -41,11 +46,13 @@ enum Opcode {
OP_MSR,
OP_MUL,
OP_MVN,
+ OP_NOP,
OP_ORR,
OP_PLD,
OP_RSB,
OP_RSC,
OP_SBC,
+ OP_SEV,
OP_SMLAL,
OP_SMULL,
OP_STC,
@@ -53,6 +60,10 @@ enum Opcode {
OP_STR,
OP_STRB,
OP_STRBT,
+ OP_STREX,
+ OP_STREXB,
+ OP_STREXD,
+ OP_STREXH,
OP_STRH,
OP_STRT,
OP_SUB,
@@ -63,6 +74,9 @@ enum Opcode {
OP_TST,
OP_UMLAL,
OP_UMULL,
+ OP_WFE,
+ OP_WFI,
+ OP_YIELD,
// Define thumb opcodes
OP_THUMB_UNDEFINED,
@@ -117,7 +131,9 @@ class ARM_Disasm {
static Opcode Decode01(uint32_t insn);
static Opcode Decode10(uint32_t insn);
static Opcode Decode11(uint32_t insn);
+ static Opcode DecodeSyncPrimitive(uint32_t insn);
static Opcode DecodeMUL(uint32_t insn);
+ static Opcode DecodeMSRImmAndHints(uint32_t insn);
static Opcode DecodeLDRH(uint32_t insn);
static Opcode DecodeALU(uint32_t insn);
@@ -135,7 +151,9 @@ class ARM_Disasm {
static std::string DisassembleMUL(Opcode opcode, uint32_t insn);
static std::string DisassembleMRS(uint32_t insn);
static std::string DisassembleMSR(uint32_t insn);
+ static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn);
static std::string DisassemblePLD(uint32_t insn);
+ static std::string DisassembleREX(Opcode opcode, uint32_t insn);
static std::string DisassembleSWI(uint32_t insn);
static std::string DisassembleSWP(Opcode opcode, uint32_t insn);
};
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 0c20c2bc..b88b7475 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -3886,7 +3886,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
#endif
arm_inst* inst_base;
unsigned int addr;
- unsigned int phys_addr;
unsigned int num_instrs = 0;
int ptr;
@@ -3905,8 +3904,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
else
cpu->Reg[15] &= 0xfffffffc;
- phys_addr = cpu->Reg[15];
-
// Find the cached instruction cream, otherwise translate it...
auto itr = cpu->instruction_cache.find(cpu->Reg[15]);
if (itr != cpu->instruction_cache.end()) {
@@ -5997,7 +5994,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
+ unsigned int reg = BITS(inst_cream->inst, 12, 15);
+ unsigned int value = cpu->Reg[reg];
+
+ if (reg == 15)
+ value += 2 * cpu->GetInstructionSize();
+
cpu->WriteMemory32(addr, value);
}
cpu->Reg[15] += cpu->GetInstructionSize();
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 9b99fc5b..49298d7b 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -1511,19 +1511,26 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL
VSTM_INST: /* encoding 1 */
{
- if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
CHECK_VFP_ENABLED;
- vstm_inst *inst_cream = (vstm_inst *)inst_base->component;
+ vstm_inst* inst_cream = (vstm_inst*)inst_base->component;
+
+ u32 address = cpu->Reg[inst_cream->n];
- addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
+ // Only possible in ARM mode, where PC accesses have an 8 byte offset.
+ if (inst_cream->n == 15)
+ address += 8;
+
+ if (inst_cream->add == 0)
+ address -= inst_cream->imm32;
for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
- cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
- addr += 4;
+ cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d+i]);
+ address += 4;
}
else
{
@@ -1531,17 +1538,17 @@ VSTM_INST: /* encoding 1 */
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
if (cpu->InBigEndianMode()) {
- cpu->WriteMemory32(addr + 0, word2);
- cpu->WriteMemory32(addr + 4, word1);
+ cpu->WriteMemory32(address + 0, word2);
+ cpu->WriteMemory32(address + 4, word1);
} else {
- cpu->WriteMemory32(addr + 0, word1);
- cpu->WriteMemory32(addr + 4, word2);
+ cpu->WriteMemory32(address + 0, word1);
+ cpu->WriteMemory32(address + 4, word2);
}
- addr += 8;
+ address += 8;
}
}
- if (inst_cream->wback){
+ if (inst_cream->wback) {
cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 :
cpu->Reg[inst_cream->n] - inst_cream->imm32);
}
@@ -1731,24 +1738,31 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL
VLDM_INST:
{
- if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
CHECK_VFP_ENABLED;
- vldm_inst *inst_cream = (vldm_inst *)inst_base->component;
+ vldm_inst* inst_cream = (vldm_inst*)inst_base->component;
+
+ u32 address = cpu->Reg[inst_cream->n];
+
+ // Only possible in ARM mode, where PC accesses have an 8 byte offset.
+ if (inst_cream->n == 15)
+ address += 8;
- addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
+ if (inst_cream->add == 0)
+ address -= inst_cream->imm32;
for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
- cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
- addr += 4;
+ cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(address);
+ address += 4;
}
else
{
- const u32 word1 = cpu->ReadMemory32(addr + 0);
- const u32 word2 = cpu->ReadMemory32(addr + 4);
+ const u32 word1 = cpu->ReadMemory32(address + 0);
+ const u32 word2 = cpu->ReadMemory32(address + 4);
if (cpu->InBigEndianMode()) {
cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
@@ -1758,10 +1772,10 @@ VLDM_INST:
cpu->ExtReg[(inst_cream->d+i)*2+1] = word2;
}
- addr += 8;
+ address += 8;
}
}
- if (inst_cream->wback){
+ if (inst_cream->wback) {
cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 :
cpu->Reg[inst_cream->n] - inst_cream->imm32);
}