Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(918)

Side by Side Diff: src/arm/simulator-arm.cc

Issue 2006183004: Implement ldrex and strex in ARM simulator (Closed) Base URL: http://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/arm/simulator-arm.h ('K') | « src/arm/simulator-arm.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdarg.h> 5 #include <stdarg.h>
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <cmath> 7 #include <cmath>
8 8
9 #if V8_TARGET_ARCH_ARM 9 #if V8_TARGET_ARCH_ARM
10 10
11 #include "src/arm/constants-arm.h" 11 #include "src/arm/constants-arm.h"
12 #include "src/arm/simulator-arm.h" 12 #include "src/arm/simulator-arm.h"
13 #include "src/assembler.h" 13 #include "src/assembler.h"
14 #include "src/base/bits.h" 14 #include "src/base/bits.h"
15 #include "src/codegen.h" 15 #include "src/codegen.h"
16 #include "src/disasm.h" 16 #include "src/disasm.h"
17 #include "src/runtime/runtime-utils.h" 17 #include "src/runtime/runtime-utils.h"
18 18
19 #if defined(USE_SIMULATOR) 19 #if defined(USE_SIMULATOR)
20 20
21 // Only build the simulator if not compiling for real ARM hardware. 21 // Only build the simulator if not compiling for real ARM hardware.
22 namespace v8 { 22 namespace v8 {
23 namespace internal { 23 namespace internal {
24 24
25 // static
26 base::LazyMutex Simulator::DataMonitor::mutex_ =
27 LAZY_STATIC_INSTANCE_INITIALIZER;
28 // static
29 Simulator::DataMonitor* Simulator::DataMonitor::head_;
30
25 // This macro provides a platform independent use of sscanf. The reason for 31 // This macro provides a platform independent use of sscanf. The reason for
26 // SScanF not being implemented in a platform independent way through 32 // SScanF not being implemented in a platform independent way through
27 // ::v8::internal::OS in the same way as SNPrintF is that the 33 // ::v8::internal::OS in the same way as SNPrintF is that the
28 // Windows C Run-Time Library does not provide vsscanf. 34 // Windows C Run-Time Library does not provide vsscanf.
29 #define SScanF sscanf // NOLINT 35 #define SScanF sscanf // NOLINT
30 36
31 // The ArmDebugger class is used by the simulator while debugging simulated ARM 37 // The ArmDebugger class is used by the simulator while debugging simulated ARM
32 // code. 38 // code.
33 class ArmDebugger { 39 class ArmDebugger {
34 public: 40 public:
(...skipping 2161 matching lines...) Expand 10 before | Expand all | Expand 10 after
2196 hi_res = static_cast<int32_t>(result >> 32); 2202 hi_res = static_cast<int32_t>(result >> 32);
2197 lo_res = static_cast<int32_t>(result & 0xffffffff); 2203 lo_res = static_cast<int32_t>(result & 0xffffffff);
2198 } 2204 }
2199 set_register(rd_lo, lo_res); 2205 set_register(rd_lo, lo_res);
2200 set_register(rd_hi, hi_res); 2206 set_register(rd_hi, hi_res);
2201 if (instr->HasS()) { 2207 if (instr->HasS()) {
2202 UNIMPLEMENTED(); 2208 UNIMPLEMENTED();
2203 } 2209 }
2204 } 2210 }
2205 } else { 2211 } else {
2206 UNIMPLEMENTED(); // Not used by V8. 2212 if (instr->Bits(24, 23) == 3) {
2213 if (instr->Bit(20) == 1) {
2214 // ldrex
2215 int rt = instr->RtValue();
2216 int rn = instr->RnValue();
2217 int32_t addr = get_register(rn);
2218 switch (instr->Bits(22, 21)) {
2219 case 0: {
2220 // Format(instr, "ldrex'cond 'rt, ['rn]");
2221 int value = data_monitor_.ReadExW(this, addr, instr);
2222 set_register(rt, value);
2223 break;
2224 }
2225 case 2: {
2226 // Format(instr, "ldrexb'cond 'rt, ['rn]");
2227 uint8_t value = data_monitor_.ReadExBU(this, addr);
2228 set_register(rt, value);
2229 break;
2230 }
2231 case 3: {
2232 // Format(instr, "ldrexh'cond 'rt, ['rn]");
2233 uint16_t value = data_monitor_.ReadExHU(this, addr, instr);
2234 set_register(rt, value);
2235 break;
2236 }
2237 default:
2238 UNREACHABLE();
2239 break;
2240 }
2241 } else {
2242 // The instruction is documented as strex rd, rt, [rn], but the
2243 // "rt" register is using the rm bits.
2244 int rd = instr->RdValue();
2245 int rt = instr->RmValue();
2246 int rn = instr->RnValue();
2247 int32_t addr = get_register(rn);
2248 switch (instr->Bits(22, 21)) {
2249 case 0: {
2250 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
2251 int value = get_register(rt);
2252 int status = data_monitor_.WriteExW(this, addr, value, instr);
2253 set_register(rd, status);
2254 break;
2255 }
2256 case 2: {
2257 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]");
2258 uint8_t value = get_register(rt);
2259 int status = data_monitor_.WriteExB(this, addr, value);
2260 set_register(rd, status);
2261 break;
2262 }
2263 case 3: {
2264 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]");
2265 uint16_t value = get_register(rt);
2266 int status = data_monitor_.WriteExH(this, addr, value, instr);
2267 set_register(rd, status);
2268 break;
2269 }
2270 default:
2271 UNREACHABLE();
2272 break;
2273 }
2274 }
2275 } else {
2276 UNIMPLEMENTED(); // Not used by V8.
2277 }
2207 } 2278 }
2208 } else { 2279 } else {
2209 // extra load/store instructions 2280 // extra load/store instructions
2210 int rd = instr->RdValue(); 2281 int rd = instr->RdValue();
2211 int rn = instr->RnValue(); 2282 int rn = instr->RnValue();
2212 int32_t rn_val = get_register(rn); 2283 int32_t rn_val = get_register(rn);
2213 int32_t addr = 0; 2284 int32_t addr = 0;
2214 if (instr->Bit(22) == 0) { 2285 if (instr->Bit(22) == 0) {
2215 int rm = instr->RmValue(); 2286 int rm = instr->RmValue();
2216 int32_t rm_val = get_register(rm); 2287 int32_t rm_val = get_register(rm);
(...skipping 2092 matching lines...) Expand 10 before | Expand all | Expand 10 after
4309 4380
4310 4381
4311 uintptr_t Simulator::PopAddress() { 4382 uintptr_t Simulator::PopAddress() {
4312 int current_sp = get_register(sp); 4383 int current_sp = get_register(sp);
4313 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); 4384 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4314 uintptr_t address = *stack_slot; 4385 uintptr_t address = *stack_slot;
4315 set_register(sp, current_sp + sizeof(uintptr_t)); 4386 set_register(sp, current_sp + sizeof(uintptr_t));
4316 return address; 4387 return address;
4317 } 4388 }
4318 4389
4390
4391 // Syncronization primitives. See ARM DDI 0406C.b, A2.9.
4392 uint8_t Simulator::DataMonitor::ReadExBU(Simulator* simulator, int32_t addr) {
4393 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4394 ReadExInternal_Locked(addr);
4395 return simulator->ReadBU(addr);
4396 }
4397
4398
4399 int Simulator::DataMonitor::WriteExB(Simulator* simulator,
4400 int32_t addr,
4401 uint8_t value) {
4402 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4403 if (WriteExInternal_Locked(addr)) {
4404 simulator->WriteB(addr, value);
jbramley 2016/05/31 16:58:47 Also, _any_ unrelated memory operation should _som
binji 2016/06/01 21:06:40 OK, makes sense.
4405 return 1;
Rodolph Perfetta (ARM) 2016/05/25 17:38:29 it is 0 on success and 1 for failure.
binji 2016/06/01 21:06:40 Oops! done.
4406 }
4407 return 0;
4408 }
4409
4410
4411 uint16_t Simulator::DataMonitor::ReadExHU(Simulator* simulator,
4412 int32_t addr,
4413 Instruction* instr) {
4414 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4415 ReadExInternal_Locked(addr);
4416 return simulator->ReadHU(addr, instr);
4417 }
4418
4419
4420 int Simulator::DataMonitor::WriteExH(Simulator* simulator,
4421 int32_t addr,
4422 uint16_t value,
4423 Instruction* instr) {
4424 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4425 if (WriteExInternal_Locked(addr)) {
4426 simulator->WriteH(addr, value, instr);
4427 return 1;
Rodolph Perfetta (ARM) 2016/05/25 17:38:29 0
binji 2016/06/01 21:06:40 Done.
4428 }
4429 return 0;
4430 }
4431
4432
4433 int Simulator::DataMonitor::ReadExW(Simulator* simulator,
4434 int32_t addr,
4435 Instruction* instr) {
4436 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4437 ReadExInternal_Locked(addr);
4438 return simulator->ReadW(addr, instr);
4439 }
4440
4441
4442 int Simulator::DataMonitor::WriteExW(Simulator* simulator,
4443 int32_t addr,
4444 int value,
4445 Instruction* instr) {
4446 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
4447 if (WriteExInternal_Locked(addr)) {
4448 simulator->WriteW(addr, value, instr);
4449 return 1;
Rodolph Perfetta (ARM) 2016/05/25 17:38:29 0
binji 2016/06/01 21:06:40 Done.
4450 }
4451 return 0;
4452 }
4453
4454
4455 Simulator::DataMonitor::DataMonitor()
4456 : access_state_(Access::Open),
4457 tagged_addr_(0),
4458 next_(nullptr),
4459 prev_(nullptr) {}
4460
4461
4462 void Simulator::DataMonitor::ReadExInternal_Locked(int32_t addr) {
4463 if (access_state_ == Access::Exclusive) {
4464 // This DataMonitor is already in the linked list; remove it so can be
4465 // added below.
4466 RemoveNode_Locked();
4467 }
4468
4469 PrependNode_Locked();
4470 access_state_ = Access::Exclusive;
4471 tagged_addr_ = addr & kAddrMask;
4472 }
4473
4474
4475 bool Simulator::DataMonitor::WriteExInternal_Locked(int32_t addr) {
4476 if (access_state_ == Access::Exclusive) {
jbramley 2016/05/31 16:58:47 This should be more strict, and check that the add
binji 2016/06/01 21:06:40 OK, I'll work on this after these simple fixes.
4477 // This DataMonitor is in the linked list, check if there is another
4478 // thread that has more recent exclusive access to this address.
4479 DataMonitor* node = FirstNodeWithTaggedAddr_Locked(addr);
4480 if (node != this) {
4481 // This thread does not have exclusive access (either it never called
4482 // ldrex or another thread took it away. Either way, this write will
4483 // fail.
4484 return false;
4485 }
4486
4487 RemoveNode_Locked();
4488 access_state_ = Access::Open;
Rodolph Perfetta (ARM) 2016/05/25 17:38:29 You should make sure any other nodes with the same
binji 2016/06/01 21:06:40 OK, I'll work on this after these simple fixes.
4489 return true;
4490 } else {
4491 // Not marked for exclusive access.
4492 return false;
4493 }
4494 }
4495
4496
4497 void Simulator::DataMonitor::RemoveNode_Locked() {
4498 if (prev_) {
4499 prev_->next_ = next_;
4500 } else {
4501 head_ = next_;
4502 }
4503 if (next_) {
4504 next_->prev_ = prev_;
4505 }
4506 prev_ = nullptr;
4507 next_ = nullptr;
4508 }
4509
4510
4511 void Simulator::DataMonitor::PrependNode_Locked() {
4512 if (head_) {
4513 head_->prev_ = this;
4514 }
Rodolph Perfetta (ARM) 2016/05/25 17:38:29 shouldn't next_ point to head_?
binji 2016/06/01 21:06:40 Done.
4515 head_ = this;
4516 }
4517
4518
4519 Simulator::DataMonitor* Simulator::DataMonitor::FirstNodeWithTaggedAddr_Locked(
4520 int32_t addr) {
4521 for (DataMonitor* node = head_; node; node = node->next_) {
4522 if ((addr & kAddrMask) == node->tagged_addr_) {
4523 return node;
4524 }
4525 }
4526 return nullptr;
4527 }
4528
4529
4319 } // namespace internal 4530 } // namespace internal
4320 } // namespace v8 4531 } // namespace v8
4321 4532
4322 #endif // USE_SIMULATOR 4533 #endif // USE_SIMULATOR
4323 4534
4324 #endif // V8_TARGET_ARCH_ARM 4535 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« src/arm/simulator-arm.h ('K') | « src/arm/simulator-arm.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698