OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include "native_client/src/trusted/validator_arm/inst_classes.h" | 7 #include "native_client/src/trusted/validator_arm/inst_classes.h" |
8 | 8 // TODO(mrm) remove when debug is gone |
bsy
2011/09/21 22:32:17
mrm
jasonwkim
2011/09/26 21:35:52
all mrm fixed
| |
9 #include <stdio.h> | |
9 /* | 10 /* |
10 * Implementations of instruction classes, for those not completely defined in | 11 * Implementations of instruction classes, for those not completely defined in |
11 * the header. | 12 * the header. |
12 */ | 13 */ |
13 | 14 |
14 namespace nacl_arm_dec { | 15 namespace nacl_arm_dec { |
15 | 16 |
16 /* | 17 /* |
17 * A utility function: given a modified-immediate-form instruction, extracts | 18 * A utility function: given a modified-immediate-form instruction, extracts |
18 * the immediate value. This is used to analyze BIC and TST. | 19 * the immediate value. This is used to analyze BIC and TST. |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 RegisterList Branch::defs(const Instruction i) const { | 413 RegisterList Branch::defs(const Instruction i) const { |
413 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); | 414 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); |
414 } | 415 } |
415 | 416 |
416 int32_t Branch::branch_target_offset(const Instruction i) const { | 417 int32_t Branch::branch_target_offset(const Instruction i) const { |
417 // Sign extend and shift left 2: | 418 // Sign extend and shift left 2: |
418 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; | 419 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; |
419 return offset + 8; // because r15 reads as 8 bytes ahead | 420 return offset + 8; // because r15 reads as 8 bytes ahead |
420 } | 421 } |
421 | 422 |
423 /* Thumb Functions */ | |
Karl
2011/09/19 19:56:05
Thumb2?
jasonwkim
2011/09/26 21:35:52
Thumb is more correct in this case
| |
424 SafetyLevel Def3::safety(Instruction i) const { | |
425 /* If it tries to write to PC, unsafe */ | |
426 if (defs(i)[kRegisterPc]) { | |
427 return FORBIDDEN_OPERANDS; | |
428 } | |
429 return MAY_BE_SAFE; | |
430 } | |
431 | |
432 RegisterList Def3::defs(Instruction i) const { | |
433 return i.reg(3, 0); | |
434 } | |
435 | |
436 SafetyLevel Def8_10::safety(Instruction i) const { | |
437 // TODO(mrm) should be encoding impossible, check | |
438 if (defs(i)[kRegisterPc]) { | |
439 return FORBIDDEN_OPERANDS; | |
440 } | |
441 return MAY_BE_SAFE; | |
442 } | |
443 | |
444 RegisterList Def8_10::defs(Instruction i) const { | |
445 return i.reg(10, 8); | |
446 } | |
447 | |
448 SafetyLevel MemOpThumb::safety(Instruction i) const { | |
449 // Don't let addressing writeback alter PC. | |
450 // TODO(mrm): Check if this is possible, we may be able to remove this. | |
451 if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS; | |
452 | |
453 return MAY_BE_SAFE; | |
454 } | |
455 | |
456 Register MemOpThumb::base_address_register(Instruction i) const { | |
457 return i.reg(5, 3); | |
458 } | |
459 | |
460 RegisterList MemOpThumbLoad::defs(Instruction i) const { | |
461 return i.reg(2, 0); | |
462 } | |
463 | |
464 // TODO(mrm) double check, this is suspect | |
465 // Specifically, double check if I need to +4 things? | |
466 int32_t CmpBrZ::branch_target_offset(Instruction i) const { | |
467 return int32_t ((i.bits(9, 9) << 6) & (i.bits(7, 3) << 1)); | |
468 } | |
469 | |
470 RegisterList PopMult::defs(Instruction i) const { | |
471 return RegisterList(i.bits(7, 0)) + kRegisterStack; | |
472 } | |
473 | |
474 SafetyLevel BranchTCond::safety(Instruction i) const { | |
475 if ((condition(i) & 14) != 14) | |
476 return MAY_BE_SAFE; | |
477 return FORBIDDEN_OPERANDS; | |
478 } | |
479 | |
480 // TODO(mrm) Check if I need to +4 | |
481 int32_t BranchT1::branch_target_offset(Instruction i) const { | |
482 // Sign extend and left shift by one | |
483 return ((int32_t)(i.bits(7, 0) << 24)) >> 23; | |
484 } | |
485 | |
486 // TODO(mrm) write test | |
487 Instruction::Condition BranchT1::condition(Instruction i) const { | |
488 return (Instruction::Condition)i.bits(11, 8); | |
489 } | |
490 | |
491 // TODO(mrm) Check if I need to +4 | |
492 int32_t BranchT2::branch_target_offset(Instruction i) const { | |
493 // Sign extend and left shift by one. | |
494 return ((int32_t)(i.bits(10, 0) << 21)) >> 20; | |
495 } | |
496 | |
497 // TODO(mrm) Check if I need to +4 | |
498 int32_t BranchT3::branch_target_offset(Instruction i) const { | |
499 // Construct the value | |
500 uint32_t val = ((((((((i.bit(10) << 1) | i.bit(27)) << 1) | i.bit(29)) << 6) | |
501 | i.bits(5, 0)) << 11) | i.bits(26, 16)) << 1; | |
502 // Sign extend it. | |
503 return ((int32_t)(val << 9)) >> 9; | |
504 } | |
505 | |
506 Instruction::Condition BranchT3::condition(Instruction i) const { | |
507 return (Instruction::Condition)i.bits(9, 6); | |
508 } | |
509 | |
510 int32_t get_stretched_immediate(Instruction i) { | |
511 uint32_t s = i.bit(10); | |
512 uint32_t i1 = (~(i.bit(27) ^ s)) & 1; | |
513 uint32_t i2 = (~(i.bit(29) ^ s)) & 1; | |
514 // Construct the value | |
515 uint32_t val = ((((((((i.bit(10) << 1) | i1) << 1) | i2) << 10) | |
516 | i.bits(9, 0)) << 11) | i.bits(26, 16)) << 1; | |
517 // Sign extend it, adjust for pc shift | |
518 return (((int32_t)(val << 9)) >> 9); | |
519 } | |
520 | |
521 int32_t BranchT4::branch_target_offset(Instruction i) const { | |
522 return get_stretched_immediate(i) + 4; | |
523 } | |
524 | |
525 // TODO(mrm) LDMT1/STMT1 could be cleaned up | |
526 RegisterList LDMT1::defs(Instruction i) const { | |
527 return RegisterList(i.bits(7, 0)); | |
528 } | |
529 | |
530 RegisterList STMT1::defs(Instruction i) const { | |
531 return RegisterList(i.bits(7, 0)) + i.reg(10, 8); | |
532 } | |
533 | |
534 RegisterList STMT1::immediate_addressing_defs(Instruction i) const { | |
535 return i.reg(10, 8); | |
536 } | |
537 | |
538 Register STMT1::base_address_register(Instruction i) const { | |
539 return i.reg(10, 8); | |
540 } | |
541 | |
542 RegisterList LDRLitT1::defs(Instruction i) const { | |
543 return i.reg(10, 8); | |
544 } | |
545 | |
546 RegisterList ADRT1::defs(Instruction i) const { | |
547 return i.reg(10, 8); | |
548 } | |
549 | |
550 RegisterList MemOpSPThumbLoad::defs(Instruction i) const { | |
551 return i.reg(10, 8); | |
552 } | |
553 | |
554 RegisterList DPMImm::defs(Instruction i) const { | |
555 return i.reg(27, 24); | |
556 } | |
557 | |
558 uint32_t get_thumb_modified_immediate(Instruction i) { | |
559 uint32_t raw = i.bits(23, 16); | |
560 uint8_t shift_mode = (((i.bits(10, 10) << 3) | i.bits(30, 28)) << 1) | |
561 | i.bits(23, 23); | |
562 switch (shift_mode >> 1) { | |
563 case 0: return raw; | |
564 case 1: return (raw << 16) | raw; | |
565 case 2: return ((raw << 16) | raw) << 8; | |
566 case 3: return (((((raw << 8) | raw) << 8) | raw) << 8) | raw; | |
567 default: return (raw | (1 << 7)) << (31 - 7 - (shift_mode - 8)); | |
568 }; | |
569 } | |
570 | |
571 bool BicModImmT::clears_bits(Instruction i, uint32_t mask) const { | |
572 return (get_thumb_modified_immediate(i) & mask) == mask; | |
573 } | |
574 | |
575 bool OrrModImmT::sets_bits(Instruction i, uint32_t mask) const { | |
576 return get_thumb_modified_immediate(i) == mask; | |
577 } | |
578 | |
579 RegisterList MovT::defs(Instruction i) const { | |
580 return Register((i.bits(7, 7) << 3) | i.bits(2, 0)); | |
581 } | |
582 | |
583 Register BXT::branch_target_register(Instruction i) const { | |
584 return i.reg(6, 3); | |
585 } | |
586 | |
587 int32_t BLT::branch_target_offset(Instruction i) const { | |
588 return get_stretched_immediate(i); | |
589 } | |
590 | |
591 ITCond IT::it_sequence(Instruction i) const { | |
592 uint8_t firstmask = i.bit(4); | |
593 ITCond base = it_set(0, THEN, 0); | |
594 uint8_t maskdex = 0; | |
595 while (i.bit(maskdex) == 0) | |
596 maskdex++; | |
597 // TODO(mrm) Add a guard to the parse table to make sure the mask is never 0 | |
598 maskdex++; | |
599 for (uint8_t conddex = 1; maskdex < 4; maskdex++, conddex++) { | |
600 base = it_set(conddex, i.bit(maskdex) == firstmask ? THEN : ELSE, base); | |
601 } | |
602 return base; | |
603 } | |
604 | |
605 Instruction::Condition IT::condition(Instruction i) const { | |
606 return (Instruction::Condition)i.bits(7, 4); | |
607 } | |
608 | |
609 RegisterList STMTD::defs(Instruction i) const { | |
610 return i.reg(3, 0); | |
611 } | |
612 | |
613 Register STMTD::base_address_register(Instruction i) const { | |
614 return i.reg(3, 0); | |
615 } | |
616 | |
617 RegisterList STMTD::immediate_addressing_defs(Instruction i) const { | |
618 return base_address_register(i); | |
619 } | |
620 | |
621 RegisterList LDMTD::defs(Instruction i) const { | |
622 return i.reg(3, 0) + RegisterList(i.bits(12, 0)); | |
623 } | |
624 | |
625 Register StrS::base_address_register(Instruction i) const { | |
626 return i.reg(3, 0); | |
627 } | |
628 | |
629 // Note that while this doesn't always write something to i.reg(3, 0), it is | |
630 // safe to pretend that it does. | |
631 RegisterList StrS::defs(Instruction i) const { | |
632 return i.reg(3, 0); | |
633 } | |
634 | |
635 Register LDRImmT3::base_address_register(Instruction i) const { | |
636 return i.reg(3, 0); | |
637 } | |
638 | |
639 RegisterList LDRImmT4::defs(Instruction i) const { | |
640 if (i.bit(8 + 16)) { | |
641 return base_address_register(i); // Writeback | |
642 } else { | |
643 return kRegisterNone; | |
644 } | |
645 } | |
646 | |
647 RegisterList LDRImmT4::immediate_addressing_defs(Instruction i) const { | |
648 return defs(i); | |
649 } | |
650 | |
651 RegisterList Def31_18::defs(Instruction i) const { | |
652 return i.reg(31, 18); | |
653 } | |
654 | |
655 RegisterList StrEx::defs(Instruction i) const { | |
656 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16); | |
657 } | |
658 | |
659 RegisterList StrEx::immediate_addressing_defs(Instruction i) const { | |
660 if (i.bit(5)) | |
661 return base_address_register(i); | |
662 return kRegisterNone; | |
663 } | |
664 | |
665 Register StrEx::base_address_register(Instruction i) const { | |
666 return i.reg(3, 0); | |
667 } | |
668 | |
669 RegisterList LdrEx::defs(Instruction i) const { | |
670 return immediate_addressing_defs(i) + i.reg(15 + 16, 12 + 16); | |
671 } | |
672 | |
673 RegisterList StrD::defs(Instruction i) const { | |
674 return immediate_addressing_defs(i); | |
675 } | |
676 | |
677 RegisterList LdrD::defs(Instruction i) const { | |
678 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16) | |
679 + i.reg(15 + 16, 12 + 16); | |
680 } | |
681 | |
682 RegisterList Def27_24::defs(Instruction i) const { | |
683 return i.reg(27, 24); | |
684 } | |
685 | |
686 bool ThumbBreakpoint::is_literal_pool_head(Instruction i) const { | |
687 UNREFERENCED_PARAMETER(i); | |
688 return true; //TODO We ideally want to think about conditions, but due to the | |
689 //rule that IT cannot straddle a boundary, and this has to start | |
690 //a bundle, we're fine. | |
691 } | |
692 | |
422 } // namespace | 693 } // namespace |
OLD | NEW |