branch.isa revision 2089
12497SN/Ae// -*- mode:c++ -*- 212780Snikos.nikoleris@arm.com 38711SN/A//////////////////////////////////////////////////////////////////// 48711SN/A// 58711SN/A// Control transfer instructions 68711SN/A// 78711SN/A 88711SN/Aoutput header {{ 98711SN/A 108711SN/A /** 118711SN/A * Base class for instructions whose disassembly is not purely a 128711SN/A * function of the machine instruction (i.e., it depends on the 138711SN/A * PC). This class overrides the disassemble() method to check 142497SN/A * the PC and symbol table values before re-using a cached 152497SN/A * disassembly string. This is necessary for branches and jumps, 162497SN/A * where the disassembly string includes the target address (which 172497SN/A * may depend on the PC and/or symbol table). 182497SN/A */ 192497SN/A class PCDependentDisassembly : public MipsStaticInst 202497SN/A { 212497SN/A protected: 222497SN/A /// Cached program counter from last disassembly 232497SN/A mutable Addr cachedPC; 242497SN/A 252497SN/A /// Cached symbol table pointer from last disassembly 262497SN/A mutable const SymbolTable *cachedSymtab; 272497SN/A 282497SN/A /// Constructor 292497SN/A PCDependentDisassembly(const char *mnem, MachInst _machInst, 302497SN/A OpClass __opClass) 312497SN/A : MipsStaticInst(mnem, _machInst, __opClass), 322497SN/A cachedPC(0), cachedSymtab(0) 332497SN/A { 342497SN/A } 352497SN/A 362497SN/A const std::string & 372497SN/A disassemble(Addr pc, const SymbolTable *symtab) const; 382497SN/A }; 392665SN/A 402665SN/A /** 418715SN/A * Base class for branches (PC-relative control transfers), 428922SN/A * conditional or unconditional. 4312351Snikos.nikoleris@arm.com */ 442497SN/A class Branch : public PCDependentDisassembly 452497SN/A { 462497SN/A protected: 472982SN/A /// target address (signed) Displacement . 4810405Sandreas.hansson@arm.com int32_t targetOffset; 492497SN/A 502497SN/A /// Constructor. 5111793Sbrandon.potter@amd.com Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 5211793Sbrandon.potter@amd.com : PCDependentDisassembly(mnem, _machInst, __opClass), 5312334Sgabeblack@google.com targetOffset(OFFSET << 2) 542548SN/A { 5510405Sandreas.hansson@arm.com } 5610405Sandreas.hansson@arm.com 579524SN/A Addr branchTarget(Addr branchPC) const; 582497SN/A 5910405Sandreas.hansson@arm.com std::string 6010719SMarco.Balboni@ARM.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 6111334Sandreas.hansson@arm.com }; 6212341Snikos.nikoleris@arm.com 6312341Snikos.nikoleris@arm.com /** 647523SN/A * Base class for branches (PC-relative control transfers), 658851SN/A * conditional or unconditional. 668948SN/A */ 678948SN/A class BranchLikely : public PCDependentDisassembly 688851SN/A { 699095SN/A protected: 7010405Sandreas.hansson@arm.com /// target address (signed) Displacement . 718922SN/A int32_t targetOffset; 729715SN/A 739715SN/A /// Constructor. 7410713Sandreas.hansson@arm.com Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 7510713Sandreas.hansson@arm.com : PCDependentDisassembly(mnem, _machInst, __opClass), 768851SN/A targetOffset(OFFSET << 2) 778851SN/A { 788948SN/A } 798948SN/A 808915SN/A Addr branchTarget(Addr branchPC) const; 819031SN/A 829095SN/A std::string 8310405Sandreas.hansson@arm.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 849036SN/A }; 858922SN/A 869715SN/A /** 879715SN/A * Base class for jumps (register-indirect control transfers). In 8810713Sandreas.hansson@arm.com * the Mips ISA, these are always unconditional. 8910713Sandreas.hansson@arm.com */ 9010713Sandreas.hansson@arm.com class Jump : public PCDependentDisassembly 918915SN/A { 928915SN/A protected: 938948SN/A 948851SN/A /// Displacement to target address (signed). 959095SN/A int32_t disp; 9610888Sandreas.hansson@arm.com 978922SN/A public: 989715SN/A /// Constructor 999715SN/A Jump(const char *mnem, MachInst _machInst, OpClass __opClass) 1009716SN/A : PCDependentDisassembly(mnem, _machInst, __opClass), 1018851SN/A disp(OFFSET) 1027523SN/A { 1037523SN/A } 10410405Sandreas.hansson@arm.com 1059715SN/A Addr branchTarget(ExecContext *xc) const; 10610405Sandreas.hansson@arm.com 10710405Sandreas.hansson@arm.com std::string 10810405Sandreas.hansson@arm.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 10910405Sandreas.hansson@arm.com }; 11010405Sandreas.hansson@arm.com}}; 11110405Sandreas.hansson@arm.com 11210405Sandreas.hansson@arm.comoutput decoder {{ 11310405Sandreas.hansson@arm.com Addr 1149715SN/A Branch::branchTarget(Addr branchPC) const 1159715SN/A { 1162568SN/A return branchPC + 4 + disp; 11710405Sandreas.hansson@arm.com } 1182568SN/A 11910405Sandreas.hansson@arm.com Addr 1209278SN/A Jump::branchTarget(ExecContext *xc) const 1218948SN/A { 1228948SN/A Addr NPC = xc->readPC() + 4; 12310405Sandreas.hansson@arm.com uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); 1249088SN/A return (Rb & ~3) | (NPC & 1); 12510405Sandreas.hansson@arm.com } 12610405Sandreas.hansson@arm.com 12710405Sandreas.hansson@arm.com const std::string & 12810405Sandreas.hansson@arm.com PCDependentDisassembly::disassemble(Addr pc, 1298711SN/A const SymbolTable *symtab) const 1308711SN/A { 1312568SN/A if (!cachedDisassembly || 1329036SN/A pc != cachedPC || symtab != cachedSymtab) 13310405Sandreas.hansson@arm.com { 13411133Sandreas.hansson@arm.com if (cachedDisassembly) 13511133Sandreas.hansson@arm.com delete cachedDisassembly; 13611133Sandreas.hansson@arm.com 13711133Sandreas.hansson@arm.com cachedDisassembly = 13811133Sandreas.hansson@arm.com new std::string(generateDisassembly(pc, symtab)); 1393244SN/A cachedPC = pc; 1403244SN/A cachedSymtab = symtab; 1418948SN/A } 14210405Sandreas.hansson@arm.com 1433244SN/A return *cachedDisassembly; 1448975SN/A } 1459032SN/A 1463244SN/A std::string 1479091SN/A Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1489091SN/A { 14911284Sandreas.hansson@arm.com std::stringstream ss; 15010656Sandreas.hansson@arm.com 15111284Sandreas.hansson@arm.com ccprintf(ss, "%-10s ", mnemonic); 15211284Sandreas.hansson@arm.com 1539091SN/A // There's only one register arg (RA), but it could be 15412780Snikos.nikoleris@arm.com // either a source (the condition for conditional 15512780Snikos.nikoleris@arm.com // branches) or a destination (the link reg for 15612780Snikos.nikoleris@arm.com // unconditional branches) 1579612SN/A if (_numSrcRegs > 0) { 15810405Sandreas.hansson@arm.com printReg(ss, _srcRegIdx[0]); 1599033SN/A ss << ","; 1609715SN/A } 16111744Snikos.nikoleris@arm.com else if (_numDestRegs > 0) { 16211744Snikos.nikoleris@arm.com printReg(ss, _destRegIdx[0]); 1633244SN/A ss << ","; 1643244SN/A } 1653244SN/A 16611744Snikos.nikoleris@arm.com#ifdef SS_COMPATIBLE_DISASSEMBLY 16711744Snikos.nikoleris@arm.com if (_numSrcRegs == 0 && _numDestRegs == 0) { 1685197SN/A printReg(ss, 31); 1699712SN/A ss << ","; 1709712SN/A } 1719712SN/A#endif 1729712SN/A 1739712SN/A Addr target = pc + 4 + disp; 17410719SMarco.Balboni@ARM.com 17510719SMarco.Balboni@ARM.com std::string str; 17610719SMarco.Balboni@ARM.com if (symtab && symtab->findSymbol(target, str)) 17710719SMarco.Balboni@ARM.com ss << str; 17810719SMarco.Balboni@ARM.com else 17910719SMarco.Balboni@ARM.com ccprintf(ss, "0x%x", target); 18010719SMarco.Balboni@ARM.com 18110719SMarco.Balboni@ARM.com return ss.str(); 18210719SMarco.Balboni@ARM.com } 18310719SMarco.Balboni@ARM.com 18410719SMarco.Balboni@ARM.com std::string 1854912SN/A Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const 18612346Snikos.nikoleris@arm.com { 18712346Snikos.nikoleris@arm.com std::stringstream ss; 18812346Snikos.nikoleris@arm.com 18912346Snikos.nikoleris@arm.com ccprintf(ss, "%-10s ", mnemonic); 19012346Snikos.nikoleris@arm.com 19112346Snikos.nikoleris@arm.com#ifdef SS_COMPATIBLE_DISASSEMBLY 19212345Snikos.nikoleris@arm.com if (_numDestRegs == 0) { 19312345Snikos.nikoleris@arm.com printReg(ss, 31); 19412345Snikos.nikoleris@arm.com ss << ","; 19511127Sandreas.hansson@arm.com } 19611127Sandreas.hansson@arm.com#endif 19712351Snikos.nikoleris@arm.com 19812351Snikos.nikoleris@arm.com if (_numDestRegs > 0) { 19912351Snikos.nikoleris@arm.com printReg(ss, _destRegIdx[0]); 20012351Snikos.nikoleris@arm.com ss << ","; 20112351Snikos.nikoleris@arm.com } 20212351Snikos.nikoleris@arm.com 20312351Snikos.nikoleris@arm.com ccprintf(ss, "(r%d)", RB); 20412351Snikos.nikoleris@arm.com 20512351Snikos.nikoleris@arm.com return ss.str(); 20612351Snikos.nikoleris@arm.com } 20712351Snikos.nikoleris@arm.com}}; 20812351Snikos.nikoleris@arm.com 20912351Snikos.nikoleris@arm.comdef template JumpOrBranchDecode {{ 21012351Snikos.nikoleris@arm.com return (RD == 0) 21112351Snikos.nikoleris@arm.com ? (StaticInst<MipsISA> *)new %(class_name)s(machInst) 21212351Snikos.nikoleris@arm.com : (StaticInst<MipsISA> *)new %(class_name)sAndLink(machInst); 2138979SN/A}}; 2148979SN/A 21510402SN/Adef format Branch(code) {{ 21610402SN/A code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; 21710402SN/A iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), 21811126Sandreas.hansson@arm.com ('IsDirectControl', 'IsCondControl')) 21911126Sandreas.hansson@arm.com header_output = BasicDeclare.subst(iop) 22011126Sandreas.hansson@arm.com decoder_output = BasicConstructor.subst(iop) 22110719SMarco.Balboni@ARM.com decode_block = BasicDecode.subst(iop) 22211744Snikos.nikoleris@arm.com exec_output = BasicExecute.subst(iop) 22311744Snikos.nikoleris@arm.com}}; 22411744Snikos.nikoleris@arm.com 22511196Sali.jafri@arm.com 22611199Sandreas.hansson@arm.comdef format BranchLikely(code) {{ 22711196Sali.jafri@arm.com code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; 22811196Sali.jafri@arm.com iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), 22911196Sali.jafri@arm.com ('IsDirectControl', 'IsCondControl')) 23011196Sali.jafri@arm.com header_output = BasicDeclare.subst(iop) 23111196Sali.jafri@arm.com decoder_output = BasicConstructor.subst(iop) 23211196Sali.jafri@arm.com decode_block = BasicDecode.subst(iop) 23311196Sali.jafri@arm.com exec_output = BasicExecute.subst(iop) 23411196Sali.jafri@arm.com}}; 23511196Sali.jafri@arm.com 23611196Sali.jafri@arm.com 23710402SN/Adef format UncondBranch(*flags) {{ 23810402SN/A flags += ('IsUncondControl', 'IsDirectControl') 23910402SN/A (header_output, decoder_output, decode_block, exec_output) = \ 24011127Sandreas.hansson@arm.com UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) 24111127Sandreas.hansson@arm.com}}; 24211127Sandreas.hansson@arm.com 24311127Sandreas.hansson@arm.comdef format Jump(*flags) {{ 2448979SN/A flags += ('IsUncondControl', 'IsIndirectControl') 2458948SN/A (header_output, decoder_output, decode_block, exec_output) = \ 24611334Sandreas.hansson@arm.com UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) 24711334Sandreas.hansson@arm.com}}; 24810883Sali.jafri@arm.com 24911284Sandreas.hansson@arm.com 25011284Sandreas.hansson@arm.com