1 // Copyright 2015, VIXL authors 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #include "aarch32/test-utils-aarch32.h" 28 29 #define __ masm-> 30 31 namespace vixl { 32 namespace aarch32 { 33 34 #define VIXL_OFFSET(type, member) offsetof(type, member) 35 36 void RegisterDump::Dump(MacroAssembler* masm) { 37 UseScratchRegisterScope scratch(masm); 38 scratch.ExcludeAll(); 39 40 // Preserve some temporary registers. 41 Register dump_base = r0; 42 Register tmp = r1; 43 44 // Check that the the dump registers can be used 45 VIXL_STATIC_ASSERT(sizeof(dump_.r_[0]) == kRegSizeInBytes); 46 VIXL_STATIC_ASSERT(sizeof(dump_.d_[0]) == kDRegSizeInBytes); 47 48 // Offsets into the dump_ structure. 49 const int r_offset = static_cast<int>(VIXL_OFFSET(dump_t, r_)); 50 const int d_offset = static_cast<int>(VIXL_OFFSET(dump_t, d_)); 51 const int flags_offset = static_cast<int>(VIXL_OFFSET(dump_t, flags_)); 52 53 __ Push(dump_base); 54 __ Push(tmp); 55 56 // Load the address of the dump_ structure. 57 __ Mov(dump_base, Operand::From(&dump_)); 58 59 // Dump all core registers. Note that the stack pointer and temporary 60 // registers will be stored again later after they are restored. 61 for (unsigned i = 0; i < kNumberOfRegisters; i++) { 62 Register rt(i); 63 // In T32 mode, "str pc, [base, #offset]" is not allowed so we cannot store 64 // the program counter this way. We could however compute the relative 65 // offset from the start of the buffer and store it but it's not very 66 // useful. So for now, testing the value of the PC is not supported. 67 if (!rt.IsPC()) { 68 __ Str(rt, MemOperand(dump_base, r_offset + (i * kRegSizeInBytes))); 69 } 70 } 71 72 for (unsigned i = 0; i < kMaxNumberOfDRegisters; i++) { 73 DRegister rt(i); 74 __ Vstr(Untyped64, 75 rt, 76 MemOperand(dump_base, d_offset + (i * kDRegSizeInBytes))); 77 } 78 79 // Dump the flags. 80 __ Mrs(tmp, APSR); 81 __ Str(tmp, MemOperand(dump_base, flags_offset)); 82 83 // We need a new pointer to dump_ in order to dump the temporary registers and 84 // the stack pointer. 85 Register dump2_base = r2; 86 // TODO: Assert that dump_base, dump2_base and tmp are not aliases. 87 __ Mov(dump2_base, dump_base); 88 89 __ Pop(tmp); 90 __ Pop(dump_base); 91 92 // Dump tmp, dump_base and the stack pointer. 93 __ Str(tmp, 94 MemOperand(dump2_base, r_offset + (tmp.GetCode() * kRegSizeInBytes))); 95 __ Str(dump_base, 96 MemOperand(dump2_base, 97 r_offset + (dump_base.GetCode() * kRegSizeInBytes))); 98 __ Str(sp, MemOperand(dump2_base, r_offset + (kSPRegNum * kRegSizeInBytes))); 99 100 completed_ = true; 101 } 102 103 104 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result) { 105 if (result != expected) { 106 printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 107 expected, 108 result); 109 } 110 111 return expected == result; 112 } 113 114 115 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) { 116 if (reg.IsPC()) { 117 printf("Testing the value of the program counter is not supported."); 118 return false; 119 } else { 120 return Equal32(expected, core, core->reg(reg.GetCode())); 121 } 122 } 123 124 125 bool Equal32(uint32_t expected, 126 const RegisterDump* core, 127 const SRegister& sreg) { 128 return Equal32(expected, core, core->GetSRegisterBits(sreg.GetCode())); 129 } 130 131 132 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result) { 133 if (result != expected) { 134 printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 135 expected, 136 result); 137 } 138 139 return expected == result; 140 } 141 142 143 bool Equal64(uint64_t expected, 144 const RegisterDump* core, 145 const DRegister& dreg) { 146 return Equal64(expected, core, core->GetDRegisterBits(dreg.GetCode())); 147 } 148 149 150 bool Equal128(vec128_t expected, const RegisterDump*, vec128_t result) { 151 if ((result.h != expected.h) || (result.l != expected.l)) { 152 printf("Expected 0x%016" PRIx64 "%016" PRIx64 153 "\t " 154 "Found 0x%016" PRIx64 "%016" PRIx64 "\n", 155 expected.h, 156 expected.l, 157 result.h, 158 result.l); 159 } 160 161 return ((expected.h == result.h) && (expected.l == result.l)); 162 } 163 164 165 bool Equal128(uint64_t expected_h, 166 uint64_t expected_l, 167 const RegisterDump* core, 168 const QRegister& qreg) { 169 vec128_t expected = {expected_l, expected_h}; 170 vec128_t result = core->GetQRegisterBits(qreg.GetCode()); 171 return Equal128(expected, core, result); 172 } 173 174 175 static char FlagN(uint32_t flags) { return (flags & NFlag) ? 'N' : 'n'; } 176 177 178 static char FlagZ(uint32_t flags) { return (flags & ZFlag) ? 'Z' : 'z'; } 179 180 181 static char FlagC(uint32_t flags) { return (flags & CFlag) ? 'C' : 'c'; } 182 183 184 static char FlagV(uint32_t flags) { return (flags & VFlag) ? 'V' : 'v'; } 185 186 187 bool EqualNzcv(uint32_t expected, uint32_t result) { 188 VIXL_ASSERT((expected & ~NZCVFlag) == 0); 189 VIXL_ASSERT((result & ~NZCVFlag) == 0); 190 if (result != expected) { 191 printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n", 192 FlagN(expected), 193 FlagZ(expected), 194 FlagC(expected), 195 FlagV(expected), 196 FlagN(result), 197 FlagZ(result), 198 FlagC(result), 199 FlagV(result)); 200 return false; 201 } 202 203 return true; 204 } 205 206 207 bool EqualFP32(float expected, 208 const RegisterDump* core, 209 const SRegister& sreg) { 210 // Retrieve the corresponding S register 211 uint32_t result = core->GetSRegisterBits(sreg.GetCode()); 212 213 if (FloatToRawbits(expected) == result) { 214 return true; 215 } else { 216 if (IsNaN(expected) || (expected == 0.0)) { 217 printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 218 FloatToRawbits(expected), 219 result); 220 } else { 221 printf("Expected %.9f (0x%08" PRIx32 222 ")\t " 223 "Found %.9f (0x%08" PRIx32 ")\n", 224 expected, 225 FloatToRawbits(expected), 226 RawbitsToFloat(result), 227 result); 228 } 229 return false; 230 } 231 } 232 233 234 bool EqualFP64(double expected, 235 const RegisterDump* core, 236 const DRegister& dreg) { 237 // Retrieve the corresponding D register 238 uint64_t result = core->GetDRegisterBits(dreg.GetCode()); 239 240 if (DoubleToRawbits(expected) == result) { 241 return true; 242 } 243 244 if (IsNaN(expected) || (expected == 0.0)) { 245 printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 246 DoubleToRawbits(expected), 247 DoubleToRawbits(result)); 248 } else { 249 printf("Expected %.17f (0x%016" PRIx64 250 ")\t " 251 "Found %.17f (0x%016" PRIx64 ")\n", 252 expected, 253 DoubleToRawbits(expected), 254 RawbitsToDouble(result), 255 result); 256 } 257 return false; 258 } 259 260 261 } // namespace aarch32 262 } // namespace vixl 263