Commit 6b623658 authored by jacob.bramley's avatar jacob.bramley Committed by Commit bot

[arm] Basic simulation of msr and mrs.

Only CPSR_f is supported, and then only for the flags that we actually
simulate (NZCV). This isn't currently used, but will be useful for some
tests.

BUG=

Review URL: https://codereview.chromium.org/1776933003

Cr-Commit-Position: refs/heads/master@{#34662}
parent fe921661
......@@ -1966,7 +1966,8 @@ void Assembler::mrs(Register dst, SRegister s, Condition cond) {
void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
Condition cond) {
DCHECK(fields >= B16 && fields < B20); // at least one field set
DCHECK((fields & 0x000f0000) != 0); // At least one field must be set.
DCHECK(((fields & 0xfff0ffff) == CPSR) || ((fields & 0xfff0ffff) == SPSR));
Instr instr;
if (!src.rm_.is_valid()) {
// Immediate.
......
......@@ -604,6 +604,26 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
Print("s");
}
return 4;
} else if (format[1] == 'p') {
if (format[8] == '_') { // 'spec_reg_fields
DCHECK(STRING_STARTS_WITH(format, "spec_reg_fields"));
Print("_");
int mask = instr->Bits(19, 16);
if (mask == 0) Print("(none)");
if ((mask & 0x8) != 0) Print("f");
if ((mask & 0x4) != 0) Print("s");
if ((mask & 0x2) != 0) Print("x");
if ((mask & 0x1) != 0) Print("c");
return 15;
} else { // 'spec_reg
DCHECK(STRING_STARTS_WITH(format, "spec_reg"));
if (instr->Bit(22) == 0) {
Print("CPSR");
} else {
Print("SPSR");
}
return 8;
}
}
// 's: S field of data processing instructions
if (instr->HasS()) {
......@@ -822,7 +842,13 @@ void Decoder::DecodeType01(Instruction* instr) {
return;
}
} else if ((type == 0) && instr->IsMiscType0()) {
if (instr->Bits(22, 21) == 1) {
if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
(instr->Bits(15, 4) == 0xf00)) {
Format(instr, "msr'cond 'spec_reg'spec_reg_fields, 'rm");
} else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
(instr->Bits(11, 0) == 0)) {
Format(instr, "mrs'cond 'rd, 'spec_reg");
} else if (instr->Bits(22, 21) == 1) {
switch (instr->BitField(7, 4)) {
case BX:
Format(instr, "bx'cond 'rm");
......
......@@ -1041,6 +1041,32 @@ ReturnType Simulator::GetFromVFPRegister(int reg_index) {
return value;
}
void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
uint32_t value) {
// Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
n_flag_ = ((value & (1 << 31)) != 0);
z_flag_ = ((value & (1 << 30)) != 0);
c_flag_ = ((value & (1 << 29)) != 0);
v_flag_ = ((value & (1 << 28)) != 0);
} else {
UNIMPLEMENTED();
}
}
uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
uint32_t result = 0;
// Only CPSR_f is implemented.
if (reg == CPSR) {
if (n_flag_) result |= (1 << 31);
if (z_flag_) result |= (1 << 30);
if (c_flag_) result |= (1 << 29);
if (v_flag_) result |= (1 << 28);
} else {
UNIMPLEMENTED();
}
return result;
}
// Runtime FP routines take:
// - two double arguments
......@@ -2312,7 +2338,22 @@ void Simulator::DecodeType01(Instruction* instr) {
return;
}
} else if ((type == 0) && instr->IsMiscType0()) {
if (instr->Bits(22, 21) == 1) {
if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
(instr->Bits(15, 4) == 0xf00)) {
// MSR
int rm = instr->RmValue();
DCHECK_NE(pc, rm); // UNPREDICTABLE
SRegisterFieldMask sreg_and_mask =
instr->BitField(22, 22) | instr->BitField(19, 16);
SetSpecialRegister(sreg_and_mask, get_register(rm));
} else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
(instr->Bits(11, 0) == 0)) {
// MRS
int rd = instr->RdValue();
DCHECK_NE(pc, rd); // UNPREDICTABLE
SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
set_register(rd, GetFromSpecialRegister(sreg));
} else if (instr->Bits(22, 21) == 1) {
int rm = instr->RmValue();
switch (instr->BitField(7, 4)) {
case BX:
......
......@@ -363,6 +363,9 @@ class Simulator {
template<class InputType, int register_size>
void SetVFPRegister(int reg_index, const InputType& value);
void SetSpecialRegister(SRegisterFieldMask reg_and_mask, uint32_t value);
uint32_t GetFromSpecialRegister(SRegister reg);
void CallInternal(byte* entry);
// Architecture state.
......
......@@ -46,7 +46,7 @@ typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
typedef Object* (*F3)(void* p0, int p1, int p2, int p3, int p4);
typedef Object* (*F4)(void* p0, void* p1, int p2, int p3, int p4);
typedef Object* (*F5)(uint32_t p0, void* p1, void* p2, int p3, int p4);
#define __ assm.
......@@ -1939,6 +1939,78 @@ TEST(code_relative_offset) {
CHECK_EQ(42, res);
}
TEST(msr_mrs) {
// Test msr and mrs.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, NULL, 0);
// Create a helper function:
// void TestMsrMrs(uint32_t nzcv,
// uint32_t * result_conditionals,
// uint32_t * result_mrs);
__ msr(CPSR_f, Operand(r0));
// Test that the condition flags have taken effect.
__ mov(r3, Operand(0));
__ orr(r3, r3, Operand(1 << 31), LeaveCC, mi); // N
__ orr(r3, r3, Operand(1 << 30), LeaveCC, eq); // Z
__ orr(r3, r3, Operand(1 << 29), LeaveCC, cs); // C
__ orr(r3, r3, Operand(1 << 28), LeaveCC, vs); // V
__ str(r3, MemOperand(r1));
// Also check mrs, ignoring everything other than the flags.
__ mrs(r3, CPSR);
__ and_(r3, r3, Operand(kSpecialCondition));
__ str(r3, MemOperand(r2));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef DEBUG
OFStream os(stdout);
code->Print(os);
#endif
F5 f = FUNCTION_CAST<F5>(code->entry());
Object* dummy = nullptr;
USE(dummy);
#define CHECK_MSR_MRS(n, z, c, v) \
do { \
uint32_t nzcv = (n << 31) | (z << 30) | (c << 29) | (v << 28); \
uint32_t result_conditionals = -1; \
uint32_t result_mrs = -1; \
dummy = CALL_GENERATED_CODE(isolate, f, nzcv, &result_conditionals, \
&result_mrs, 0, 0); \
CHECK_EQ(nzcv, result_conditionals); \
CHECK_EQ(nzcv, result_mrs); \
} while (0);
// N Z C V
CHECK_MSR_MRS(0, 0, 0, 0);
CHECK_MSR_MRS(0, 0, 0, 1);
CHECK_MSR_MRS(0, 0, 1, 0);
CHECK_MSR_MRS(0, 0, 1, 1);
CHECK_MSR_MRS(0, 1, 0, 0);
CHECK_MSR_MRS(0, 1, 0, 1);
CHECK_MSR_MRS(0, 1, 1, 0);
CHECK_MSR_MRS(0, 1, 1, 1);
CHECK_MSR_MRS(1, 0, 0, 0);
CHECK_MSR_MRS(1, 0, 0, 1);
CHECK_MSR_MRS(1, 0, 1, 0);
CHECK_MSR_MRS(1, 0, 1, 1);
CHECK_MSR_MRS(1, 1, 0, 0);
CHECK_MSR_MRS(1, 1, 0, 1);
CHECK_MSR_MRS(1, 1, 1, 0);
CHECK_MSR_MRS(1, 1, 1, 1);
#undef CHECK_MSR_MRS
}
TEST(ARMv8_float32_vrintX) {
// Test the vrintX floating point instructions.
......
......@@ -453,6 +453,54 @@ TEST(Type3) {
}
TEST(msr_mrs_disasm) {
SET_UP();
SRegisterFieldMask CPSR_all = CPSR_f | CPSR_s | CPSR_x | CPSR_c;
SRegisterFieldMask SPSR_all = SPSR_f | SPSR_s | SPSR_x | SPSR_c;
COMPARE(msr(CPSR_f, Operand(r0)), "e128f000 msr CPSR_f, r0");
COMPARE(msr(CPSR_s, Operand(r1)), "e124f001 msr CPSR_s, r1");
COMPARE(msr(CPSR_x, Operand(r2)), "e122f002 msr CPSR_x, r2");
COMPARE(msr(CPSR_c, Operand(r3)), "e121f003 msr CPSR_c, r3");
COMPARE(msr(CPSR_all, Operand(ip)), "e12ff00c msr CPSR_fsxc, ip");
COMPARE(msr(SPSR_f, Operand(r0)), "e168f000 msr SPSR_f, r0");
COMPARE(msr(SPSR_s, Operand(r1)), "e164f001 msr SPSR_s, r1");
COMPARE(msr(SPSR_x, Operand(r2)), "e162f002 msr SPSR_x, r2");
COMPARE(msr(SPSR_c, Operand(r3)), "e161f003 msr SPSR_c, r3");
COMPARE(msr(SPSR_all, Operand(ip)), "e16ff00c msr SPSR_fsxc, ip");
COMPARE(msr(CPSR_f, Operand(r0), eq), "0128f000 msreq CPSR_f, r0");
COMPARE(msr(CPSR_s, Operand(r1), ne), "1124f001 msrne CPSR_s, r1");
COMPARE(msr(CPSR_x, Operand(r2), cs), "2122f002 msrcs CPSR_x, r2");
COMPARE(msr(CPSR_c, Operand(r3), cc), "3121f003 msrcc CPSR_c, r3");
COMPARE(msr(CPSR_all, Operand(ip), mi), "412ff00c msrmi CPSR_fsxc, ip");
COMPARE(msr(SPSR_f, Operand(r0), pl), "5168f000 msrpl SPSR_f, r0");
COMPARE(msr(SPSR_s, Operand(r1), vs), "6164f001 msrvs SPSR_s, r1");
COMPARE(msr(SPSR_x, Operand(r2), vc), "7162f002 msrvc SPSR_x, r2");
COMPARE(msr(SPSR_c, Operand(r3), hi), "8161f003 msrhi SPSR_c, r3");
COMPARE(msr(SPSR_all, Operand(ip), ls), "916ff00c msrls SPSR_fsxc, ip");
// Other combinations of mask bits.
COMPARE(msr(CPSR_s | CPSR_x, Operand(r4)),
"e126f004 msr CPSR_sx, r4");
COMPARE(msr(SPSR_s | SPSR_x | SPSR_c, Operand(r5)),
"e167f005 msr SPSR_sxc, r5");
COMPARE(msr(SPSR_s | SPSR_c, Operand(r6)),
"e165f006 msr SPSR_sc, r6");
COMPARE(msr(SPSR_f | SPSR_c, Operand(r7)),
"e169f007 msr SPSR_fc, r7");
// MSR with no mask is UNPREDICTABLE, and checked by the assembler, but check
// that the disassembler does something sensible.
COMPARE(dd(0xe120f008), "e120f008 msr CPSR_(none), r8");
COMPARE(mrs(r0, CPSR), "e10f0000 mrs r0, CPSR");
COMPARE(mrs(r1, SPSR), "e14f1000 mrs r1, SPSR");
COMPARE(mrs(r2, CPSR, ge), "a10f2000 mrsge r2, CPSR");
COMPARE(mrs(r3, SPSR, lt), "b14f3000 mrslt r3, SPSR");
VERIFY_RUN();
}
TEST(Vfp) {
SET_UP();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment