1090 lines
24 KiB
C++
1090 lines
24 KiB
C++
#include "types.h"
|
|
|
|
#if FEAT_AREC != DYNAREC_NONE
|
|
#include "hw/mem/addrspace.h"
|
|
#include "hw/arm7/arm7.h"
|
|
#include "hw/aica/aica_if.h"
|
|
#include "hw/arm7/arm7_rec.h"
|
|
#include "emulator.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
static const u32 N_FLAG = 1 << 31;
|
|
static const u32 Z_FLAG = 1 << 30;
|
|
static const u32 C_FLAG = 1 << 29;
|
|
static const u32 V_FLAG = 1 << 28;
|
|
static const u32 NZCV_MASK = N_FLAG | Z_FLAG | C_FLAG | V_FLAG;
|
|
|
|
|
|
namespace aica::arm::recompiler {
|
|
|
|
extern void (*EntryPoints[])();
|
|
|
|
class AicaArmTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override
|
|
{
|
|
if (!addrspace::reserve())
|
|
die("addrspace::reserve failed");
|
|
emu.init();
|
|
emu.dc_reset(true);
|
|
Arm7Enabled = true;
|
|
}
|
|
|
|
void PrepareOp(u32 op)
|
|
{
|
|
PrepareOps(1, &op);
|
|
}
|
|
|
|
void PrepareOps(int count, u32 *ops)
|
|
{
|
|
arm_Reg[R15_ARM_NEXT].I = 0x1000;
|
|
for (int i = 0; i < count; i++)
|
|
*(u32*)&aica_ram[0x1000 + i * 4] = ops[i];
|
|
*(u32*)&aica_ram[0x1000 + count * 4] = 0xea000000 | ((u32)(-count * 4 - 8) << 2); // b pc+8-12
|
|
flush();
|
|
compile();
|
|
}
|
|
|
|
void RunOp()
|
|
{
|
|
arm_Reg[R15_ARM_NEXT].I = 0x1000;
|
|
arm_Reg[CYCL_CNT].I = 1;
|
|
arm_mainloop(arm_Reg, EntryPoints);
|
|
}
|
|
void ResetNZCV()
|
|
{
|
|
arm_Reg[RN_PSR_FLAGS].I &= ~NZCV_MASK;
|
|
}
|
|
};
|
|
#define ASSERT_NZCV_EQ(expected) ASSERT_EQ(arm_Reg[RN_PSR_FLAGS].I & NZCV_MASK, (expected));
|
|
|
|
TEST_F(AicaArmTest, ArithmeticOpsTest)
|
|
{
|
|
PrepareOp(0xe0810002); // add r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xbaad0000;
|
|
arm_Reg[2].I = 0x0000cafe;
|
|
arm_Reg[RN_PSR_FLAGS].I |= NZCV_MASK;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
ASSERT_NZCV_EQ(NZCV_MASK);
|
|
|
|
PrepareOp(0xe0810000); // add r0, r1, r0
|
|
arm_Reg[0].I = 11;
|
|
arm_Reg[1].I = 22;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 33);
|
|
|
|
PrepareOp(0xe0410002); // sub r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xbaadcafe;
|
|
arm_Reg[2].I = 0x0000cafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaad0000);
|
|
ASSERT_NZCV_EQ(NZCV_MASK);
|
|
|
|
PrepareOp(0xe0410000); // sub r0, r1, r0
|
|
arm_Reg[0].I = 11;
|
|
arm_Reg[1].I = 22;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 11);
|
|
|
|
PrepareOp(0xe0910002); // adds r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x80000000;
|
|
arm_Reg[2].I = 0x80000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG | V_FLAG); // Z,C,V
|
|
|
|
PrepareOp(0xe0510002); // subs r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xbaadcafe;
|
|
arm_Reg[2].I = 0x0000cafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaad0000);
|
|
ASSERT_NZCV_EQ(N_FLAG | C_FLAG); // N,C
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xbaadcafe;
|
|
arm_Reg[2].I = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG); // Z,C
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x80000000;
|
|
arm_Reg[2].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x7fffffff);
|
|
ASSERT_NZCV_EQ(C_FLAG | V_FLAG); // C,V
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xffffffff;
|
|
arm_Reg[2].I = 0xffffffff;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG); // Z,C
|
|
|
|
PrepareOp(0xe0b10002); // adcs r0, r1, r2
|
|
arm_Reg[RN_PSR_FLAGS].I &= ~NZCV_MASK;
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 3);
|
|
ASSERT_NZCV_EQ(0); //
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // set C
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 4);
|
|
ASSERT_NZCV_EQ(0); //
|
|
|
|
// from armwrestler
|
|
PrepareOp(0xe0d22002); // sbcs r2,r2,r2
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // set C
|
|
arm_Reg[2].I = 0xFFFFFFFF;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[2].I, 0);
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG);
|
|
|
|
// from armwrestler
|
|
PrepareOp(0xe2d22000); // sbcs r2,r2,#0
|
|
ResetNZCV();
|
|
arm_Reg[2].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[2].I, -1);
|
|
ASSERT_NZCV_EQ(N_FLAG);
|
|
|
|
PrepareOp(0xe0d10002); // sbcs r0, r1, r2
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, -2);
|
|
ASSERT_NZCV_EQ(N_FLAG); // N
|
|
|
|
PrepareOp(0xe0710002); // rsbs r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C, confirmed by interpreter and online arm sim
|
|
|
|
PrepareOp(0xe0f10002); // rscs r0, r1, r2
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG); // Z,C
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // C set
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
|
|
PrepareOp(0xe1500001); // cmp r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 2;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
|
|
PrepareOp(0xe1700001); // cmn r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 2;
|
|
arm_Reg[1].I = -1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
}
|
|
|
|
TEST_F(AicaArmTest, LogicOpsTest)
|
|
{
|
|
PrepareOp(0xe1a00001); // mov r0, r1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
|
|
PrepareOp(0xe3c100ff); // bic r0, r1, 0xff
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xffff;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xff00);
|
|
|
|
PrepareOp(0xe0010002); // and r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xff0f;
|
|
arm_Reg[2].I = 0xf0f0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xf000);
|
|
|
|
PrepareOp(0xe0010000); // and r0, r1, r0
|
|
arm_Reg[0].I = 0xf0f0f0f0;
|
|
arm_Reg[1].I = 0xffffffff;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xf0f0f0f0);
|
|
|
|
PrepareOp(0xe1a00251); // asr r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xfffffff8;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xfffffffe);
|
|
|
|
PrepareOp(0xe1a00241); // asr r0, r1, 4
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x0ffffff0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x00ffffff);
|
|
|
|
PrepareOp(0xe0210002); // eor r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0xffff0000;
|
|
arm_Reg[2].I = 0xf0f0f0f0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x0f0ff0f0);
|
|
|
|
PrepareOp(0xe0210000); // eor r0, r1, r0
|
|
arm_Reg[0].I = 0xf0f0f0f0;
|
|
arm_Reg[1].I = 0xffffffff;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x0f0f0f0f);
|
|
|
|
PrepareOp(0xe1810000); // orr r0, r1, r0
|
|
arm_Reg[0].I = 0xf0f0f0f0;
|
|
arm_Reg[1].I = 0x0f0f0f0f;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xffffffff);
|
|
|
|
PrepareOp(0xe1a00211); // lsl r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 8;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x100);
|
|
|
|
PrepareOp(0xe1a00231); // lsr r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x100;
|
|
arm_Reg[2].I = 4;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x10);
|
|
|
|
PrepareOp(0xe1a00271); // ror r0, r1, r2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x12345678;
|
|
arm_Reg[2].I = 16;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x56781234);
|
|
|
|
PrepareOp(0xe1300001); // teq r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG | V_FLAG; // set C,V
|
|
arm_Reg[0].I = 1;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG | V_FLAG); // Z,C,V
|
|
|
|
PrepareOp(0xe1100001); // tst r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 1;
|
|
arm_Reg[1].I = 2;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(0x40000000); // Z
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG | V_FLAG; // set C,V
|
|
arm_Reg[0].I = 3;
|
|
arm_Reg[1].I = 2;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(C_FLAG | V_FLAG); // C,V
|
|
}
|
|
|
|
TEST_F(AicaArmTest, Operand2ImmTest)
|
|
{
|
|
PrepareOp(0xe2810003); // add r0, r1, #3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 4);
|
|
|
|
PrepareOp(0xe2a10003); // adc r0, r1, #3
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 5);
|
|
|
|
PrepareOp(0xe2410003); // sub r0, r1, #3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 7;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 4);
|
|
|
|
PrepareOp(0xe2610003); // rsb r0, r1, #3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 2);
|
|
|
|
PrepareOp(0xe2c10003); // sbc r0, r1, #3
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 10;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 6);
|
|
|
|
PrepareOp(0xe2e10010); // rsc r0, r1, #16
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 6;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 9);
|
|
|
|
PrepareOp(0xe3500010); // cmp r0, #16
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 16;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG);
|
|
|
|
PrepareOp(0xe3700001); // cmn r0, #1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0xffffffff;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG);
|
|
|
|
PrepareOp(0xe2010001); // and r0, r1, #1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 3;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0xe3810001); // orr r0, r1, #1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 3);
|
|
|
|
PrepareOp(0xe2210001); // eor r0, r1, #1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 3;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 2);
|
|
|
|
PrepareOp(0xe3c10001); // bic r0, r1, #1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 3;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 2);
|
|
|
|
PrepareOp(0xe3100001); // tst r0, #1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 2;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG);
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(0);
|
|
|
|
PrepareOp(0xe3300001); // teq r0, #1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG);
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 2;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(0);
|
|
|
|
PrepareOp(0xe2522001); // subs r2, #1
|
|
ResetNZCV();
|
|
arm_Reg[2].I = 1;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(Z_FLAG | C_FLAG);
|
|
ResetNZCV();
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(C_FLAG);
|
|
ResetNZCV();
|
|
arm_Reg[2].I = 0;
|
|
RunOp();
|
|
ASSERT_NZCV_EQ(N_FLAG);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, Operand2ShiftImmTest)
|
|
{
|
|
PrepareOp(0xe0810202); // add r0, r1, r2, LSL #4
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x21);
|
|
|
|
PrepareOp(0xe0810142); // add r0, r1, r2, ASR #2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = -8;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, -1);
|
|
|
|
PrepareOp(0xe08100a2); // add r0, r1, r2, LSR #1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x40000001);
|
|
|
|
PrepareOp(0xe0810862); // add r0, r1, r2, ROR #16
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x56771234;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x12345678);
|
|
|
|
PrepareOp(0xe0810062); // add r0, r1, r2, RRX
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x22222221;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x11111111);
|
|
ASSERT_NZCV_EQ(0); //
|
|
|
|
PrepareOp(0xe1910062); // orrs r0, r1, r2, RRX
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // set C
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x22222221;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x91111111);
|
|
ASSERT_NZCV_EQ(N_FLAG | C_FLAG); // N,C
|
|
|
|
// When an Operand2 constant is used with the instructions MOVS, MVNS, ANDS, ORRS, ORNS, EORS, BICS, TEQ or TST, the carry flag is updated to bit[31] of the constant,
|
|
// if the constant is greater than 255 and can be produced by shifting an 8-bit value.
|
|
PrepareOp(0xe3b00102); // movs r0, #0x80000000
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x80000000);
|
|
ASSERT_NZCV_EQ(N_FLAG | C_FLAG); // N,C
|
|
|
|
PrepareOp(0xe3f00000); // mvns r0, #0
|
|
arm_Reg[RN_PSR_FLAGS].I &= ~NZCV_MASK;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xffffffff);
|
|
ASSERT_NZCV_EQ(N_FLAG); // N
|
|
}
|
|
|
|
TEST_F(AicaArmTest, Operand2RegShiftTest)
|
|
{
|
|
PrepareOp(0xe1810312); // orr r0, r1, r2, LSL r3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x10;
|
|
arm_Reg[3].I = 8;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x1001);
|
|
|
|
PrepareOp(0xe1810352); // orr r0, r1, r2, ASR r3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80000000;
|
|
arm_Reg[3].I = 30;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xffffffff);
|
|
|
|
PrepareOp(0xe1810332); // orr r0, r1, r2, LSR r3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80000000;
|
|
arm_Reg[3].I = 30;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 3);
|
|
|
|
PrepareOp(0xe1810372); // orr r0, r1, r2, ROR r3
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x43208765;
|
|
arm_Reg[3].I = 16;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x87654321);
|
|
|
|
PrepareOp(0xe1b0431f); // movs r4, r15, lsl r3
|
|
ResetNZCV();
|
|
arm_Reg[3].I = 0;
|
|
arm_Reg[4].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[4].I, 0x1000 + 12);
|
|
ASSERT_NZCV_EQ(0);
|
|
|
|
PrepareOp(0xe1b0400f); // movs r4, r15, lsl #0
|
|
ResetNZCV();
|
|
arm_Reg[3].I = 0;
|
|
arm_Reg[4].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[4].I, 0x1000 + 8);
|
|
ASSERT_NZCV_EQ(0);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, CarryTest)
|
|
{
|
|
PrepareOp(0xe1910022); // orrs r0, r1, r2, LSR #32
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
|
|
PrepareOp(0xe1910822); // orrs r0, r1, r2, LSR #16
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80008000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x8001);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
|
|
PrepareOp(0xe1910042); // orrs r0, r1, r2, ASR #32
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x80000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xffffffff);
|
|
ASSERT_NZCV_EQ(N_FLAG | C_FLAG); // N,C
|
|
|
|
PrepareOp(0xe1910842); // orrs r0, r1, r2, ASR #16
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x00008000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
arm_Reg[RN_PSR_FLAGS].I &= ~NZCV_MASK;
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x00004000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_NZCV_EQ(0); //
|
|
|
|
PrepareOp(0xe1910802); // orrs r0, r1, r2, LSL #16
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
arm_Reg[2].I = 0x00010001;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x10001);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
}
|
|
|
|
TEST_F(AicaArmTest, MemoryTest)
|
|
{
|
|
PrepareOp(0xe5910004); // ldr r0, [r1, #4]
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x10000;
|
|
*(u32*)&aica_ram[0x10004] = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
|
|
PrepareOp(0xe5010008); // str r0, [r1, #-8]
|
|
arm_Reg[0].I = 0xbaadcafe;
|
|
arm_Reg[1].I = 0x10008;
|
|
*(u32*)&aica_ram[0x10000] = 0;
|
|
RunOp();
|
|
ASSERT_EQ(*(u32*)&aica_ram[0x10000], 0xbaadcafe);
|
|
|
|
PrepareOp(0xe5b10004); // ldr r0, [r1, #4]!
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x10000;
|
|
*(u32*)&aica_ram[0x10004] = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
ASSERT_EQ(arm_Reg[1].I, 0x10004);
|
|
|
|
PrepareOp(0xe4110004); // ldr r0, [r1], #-4
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x10004;
|
|
*(u32*)&aica_ram[0x10004] = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
ASSERT_EQ(arm_Reg[1].I, 0x10000);
|
|
|
|
PrepareOp(0xe4900004); // ldr r0, [r0], #4
|
|
arm_Reg[0].I = 0x10004;
|
|
*(u32*)&aica_ram[0x10004] = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
|
|
PrepareOp(0xe5b00004); // ldr r0, [r0, #4]!
|
|
arm_Reg[0].I = 0x10000;
|
|
*(u32*)&aica_ram[0x10000] = 0xbaadcafe;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0xbaadcafe);
|
|
|
|
PrepareOp(0xe51f0004); // ldr r0, [r15, #-4]
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
|
|
PrepareOp(0xe79000a4); // ldr r0, [r0, r4, LSR #1]
|
|
arm_Reg[0].I = 0x1003;
|
|
arm_Reg[4].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
|
|
PrepareOp(0xe7900084); // ldr r0, [r0, r4, LSL #1]
|
|
arm_Reg[0].I = 0x1002;
|
|
arm_Reg[4].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
|
|
PrepareOp(0xe7900024); // ldr r0, [r0, r4, LSR #32]
|
|
arm_Reg[0].I = 0x1004;
|
|
arm_Reg[4].I = 0x12345678;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[4].I, 0x12345678);
|
|
|
|
PrepareOp(0xe7900044); // ldr r0, [r0, r4, ASR #32]
|
|
arm_Reg[0].I = 0x1005;
|
|
arm_Reg[4].I = 0x80000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[4].I, 0x80000000);
|
|
|
|
PrepareOp(0xe7920002); // ldr r0,[r2,r2]
|
|
arm_Reg[0].I = 5;
|
|
arm_Reg[2].I = 0x1004 / 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1004 / 2);
|
|
|
|
PrepareOp(0xe7920063); // ldr r0,[r2,r3, rrx]
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // set C
|
|
arm_Reg[0].I = 5;
|
|
arm_Reg[2].I = 0x1006;
|
|
arm_Reg[3].I = -4;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1006);
|
|
ASSERT_EQ(arm_Reg[3].I, -4);
|
|
|
|
// unaligned read
|
|
PrepareOp(0xe7900002); // ldr r0,[r0,r2]
|
|
arm_Reg[0].I = 0x1004;
|
|
arm_Reg[2].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, (*(u32*)&aica_ram[0x1004]) >> 16 | (*(u32*)&aica_ram[0x1004]) << 16);
|
|
ASSERT_EQ(arm_Reg[2].I, 2);
|
|
|
|
PrepareOp(0xe69000a4); // ldr r0,[r0],r4, lsr #1
|
|
arm_Reg[0].I = 0x1004;
|
|
arm_Reg[4].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[4].I, 2);
|
|
|
|
PrepareOp(0xe6920104); // ldr r0,[r2],r4, lsl #2
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[2].I = 0x1004;
|
|
arm_Reg[4].I = 2;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1004 + 8);
|
|
ASSERT_EQ(arm_Reg[4].I, 2);
|
|
|
|
PrepareOp(0xe6920000); // ldr r0,[r2],r0
|
|
arm_Reg[0].I = 123;
|
|
arm_Reg[2].I = 0x1004;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1004 + 123);
|
|
|
|
PrepareOp(0xe6920043); // ldr r0,[r2],r3, asr #32
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[2].I = 0x1004;
|
|
arm_Reg[3].I = 0xc0000000;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1004 - 1);
|
|
ASSERT_EQ(arm_Reg[3].I, 0xc0000000);
|
|
|
|
PrepareOp(0xe6920063); // ldr r0,[r2],r3, rrx
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG; // set C
|
|
arm_Reg[0].I = 5;
|
|
arm_Reg[2].I = 0x1004;
|
|
arm_Reg[3].I = 0xfffffffc;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, *(u32*)&aica_ram[0x1004]);
|
|
ASSERT_EQ(arm_Reg[2].I, 0x1002);
|
|
ASSERT_NZCV_EQ(C_FLAG); // C
|
|
ASSERT_EQ(arm_Reg[3].I, 0xfffffffc);
|
|
|
|
// unaligned read
|
|
PrepareOp(0xe6900002); // ldr r0,[r0],r2
|
|
arm_Reg[0].I = 0x1006;
|
|
arm_Reg[2].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, (*(u32*)&aica_ram[0x1004]) >> 16 | (*(u32*)&aica_ram[0x1004]) << 16);
|
|
ASSERT_EQ(arm_Reg[2].I, 1);
|
|
|
|
// conditional with write-back, false condition
|
|
PrepareOp(0x04910004); // ldreq r0, [r1], #4
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 0x1004;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ASSERT_EQ(arm_Reg[1].I, 0x1004);
|
|
|
|
}
|
|
|
|
TEST_F(AicaArmTest, PcRelativeTest)
|
|
{
|
|
PrepareOp(0xe38f0010); // orr r0, r15, #16
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x1008 + 16);
|
|
|
|
PrepareOp(0xe180011f); // orr r0, r15, LSL r1
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0x100C << 1);
|
|
|
|
PrepareOp(0xe28f5c7d); // add r5, r15, #32000
|
|
arm_Reg[5].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[5].I, 32000 + 0x1008);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, ConditionalTest)
|
|
{
|
|
PrepareOp(0x01a00001); // moveq r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0x11a00001); // movne r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0x21a00001); // movcs r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0x31a00001); // movcc r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0x41a00001); // movmi r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0x51a00001); // movpl r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0x61a00001); // movvs r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0x71a00001); // movvc r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0x81a00001); // movhi r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0x91a00001); // movls r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= C_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I = Z_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0xa1a00001); // movge r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0xb1a00001); // movlt r0, r1
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
|
|
PrepareOp(0xc1a00001); // movgt r0, r1
|
|
// Z==0 && N==V
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
arm_Reg[0].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
|
|
PrepareOp(0xd1a00001); // movle r0, r1
|
|
// Z==1 || N!=V
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[1].I = 1;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ResetNZCV();
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[RN_PSR_FLAGS].I |= V_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
arm_Reg[0].I = 0;
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[0].I, 0);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, JumpTest)
|
|
{
|
|
PrepareOp(0xea00003e); // b +248
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1100);
|
|
|
|
PrepareOp(0xeb00003e); // bl +248
|
|
arm_Reg[14].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1100);
|
|
ASSERT_EQ(arm_Reg[14].I, 0x1004);
|
|
|
|
PrepareOp(0xe1a0f000); // mov pc, r0
|
|
arm_Reg[0].I = 0x100;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x100);
|
|
|
|
PrepareOp(0xc1a0f000); // movgt pc, r0
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= N_FLAG;
|
|
arm_Reg[0].I = 0x100;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1004);
|
|
ResetNZCV();
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x100);
|
|
|
|
PrepareOp(0xe590f000); // ldr r15, [r0]
|
|
arm_Reg[0].I = 0x10000;
|
|
*(u32*)&aica_ram[0x10000] = 0xbaadcafc;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0xbaadcafc);
|
|
|
|
PrepareOp(0x1b00003e); // blne +248
|
|
ResetNZCV();
|
|
arm_Reg[14].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1100);
|
|
ASSERT_EQ(arm_Reg[14].I, 0x1004);
|
|
ResetNZCV();
|
|
arm_Reg[RN_PSR_FLAGS].I |= Z_FLAG;
|
|
arm_Reg[14].I = 0;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1004);
|
|
ASSERT_EQ(arm_Reg[14].I, 0);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, LdmStmTest)
|
|
{
|
|
PrepareOp(0xe8bd8000); // ldm sp!, {pc}
|
|
arm_Reg[13].I = 0x1100;
|
|
*(u32*)&aica_ram[0x1100] = 0x1234;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[R15_ARM_NEXT].I, 0x1234);
|
|
|
|
PrepareOp(0xe92d8000); // stmdb sp!, {pc}
|
|
arm_Reg[13].I = 0x1104;
|
|
RunOp();
|
|
ASSERT_EQ(arm_Reg[13].I, 0x1100);
|
|
ASSERT_EQ(*(u32*)&aica_ram[0x1100], 0x1000 + 12);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, RegAllocTest)
|
|
{
|
|
u32 ops[] = {
|
|
0xe3a00000, // mov r0, #0
|
|
0xe3a01001, // mov r1, #1
|
|
0xe3a02002, // mov r2, #2
|
|
0xe3a03003, // mov r3, #3
|
|
0xe3a04004, // mov r4, #4
|
|
0xe3a05005, // mov r5, #5
|
|
0xe3a06006, // mov r6, #6
|
|
0xe0800001, // add r0, r0, r1
|
|
0xe0811002, // add r1, r1, r2
|
|
0xe0822003, // add r2, r2, r3
|
|
0xe0833004, // add r3, r3, r4
|
|
0xe0844005, // add r4, r4, r5
|
|
0xe0855006, // add r5, r5, r6
|
|
0xe0866000, // add r6, r6, r0
|
|
};
|
|
PrepareOps(std::size(ops), ops);
|
|
for (int i = 0; i < 15; i++)
|
|
arm_Reg[i].I = 0;
|
|
|
|
RunOp();
|
|
|
|
ASSERT_EQ(arm_Reg[0].I, 1);
|
|
ASSERT_EQ(arm_Reg[1].I, 3);
|
|
ASSERT_EQ(arm_Reg[2].I, 5);
|
|
ASSERT_EQ(arm_Reg[3].I, 7);
|
|
ASSERT_EQ(arm_Reg[4].I, 9);
|
|
ASSERT_EQ(arm_Reg[5].I, 11);
|
|
ASSERT_EQ(arm_Reg[6].I, 7);
|
|
}
|
|
|
|
TEST_F(AicaArmTest, ConditionRegAllocTest)
|
|
{
|
|
u32 ops1[] = {
|
|
0x03a0004d, // moveq r0, #77
|
|
0xe1a01000 // mov r1, r0
|
|
};
|
|
PrepareOps(std::size(ops1), ops1);
|
|
arm_Reg[0].I = 22;
|
|
arm_Reg[1].I = 22;
|
|
ResetNZCV();
|
|
|
|
RunOp();
|
|
|
|
ASSERT_EQ(arm_Reg[0].I, 22);
|
|
ASSERT_EQ(arm_Reg[1].I, 22);
|
|
|
|
u32 ops2[] = {
|
|
0x01a01000, // moveq r1, r0
|
|
0xe1a02000 // mov r2, r0
|
|
};
|
|
PrepareOps(std::size(ops2), ops2);
|
|
arm_Reg[0].I = 22;
|
|
arm_Reg[1].I = 0;
|
|
arm_Reg[2].I = 0;
|
|
ResetNZCV();
|
|
|
|
RunOp();
|
|
|
|
ASSERT_EQ(arm_Reg[0].I, 22);
|
|
ASSERT_EQ(arm_Reg[1].I, 0);
|
|
ASSERT_EQ(arm_Reg[2].I, 22);
|
|
}
|
|
}
|
|
#endif
|