mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-22 12:35:21 +00:00
ARMv7: BX, MOV_IMM, IT (ITSTATE register)
This commit is contained in:
parent
de156c59e4
commit
3895c083cb
5 changed files with 239 additions and 49 deletions
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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__;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue