branch.isa revision 2123
111308Santhony.gutierrez@amd.com// -*- mode:c++ -*- 211308Santhony.gutierrez@amd.com 311308Santhony.gutierrez@amd.com//////////////////////////////////////////////////////////////////// 411308Santhony.gutierrez@amd.com// 511308Santhony.gutierrez@amd.com// Control transfer instructions 611308Santhony.gutierrez@amd.com// 711308Santhony.gutierrez@amd.com 811308Santhony.gutierrez@amd.comoutput header {{ 911308Santhony.gutierrez@amd.com 1011308Santhony.gutierrez@amd.com /** 1111308Santhony.gutierrez@amd.com * Base class for instructions whose disassembly is not purely a 1211308Santhony.gutierrez@amd.com * function of the machine instruction (i.e., it depends on the 1311308Santhony.gutierrez@amd.com * PC). This class overrides the disassemble() method to check 1411308Santhony.gutierrez@amd.com * the PC and symbol table values before re-using a cached 1511308Santhony.gutierrez@amd.com * disassembly string. This is necessary for branches and jumps, 1611308Santhony.gutierrez@amd.com * where the disassembly string includes the target address (which 1711308Santhony.gutierrez@amd.com * may depend on the PC and/or symbol table). 1811308Santhony.gutierrez@amd.com */ 1911308Santhony.gutierrez@amd.com class PCDependentDisassembly : public MipsStaticInst 2011308Santhony.gutierrez@amd.com { 2111308Santhony.gutierrez@amd.com protected: 2211308Santhony.gutierrez@amd.com /// Cached program counter from last disassembly 2311308Santhony.gutierrez@amd.com mutable Addr cachedPC; 2411308Santhony.gutierrez@amd.com 2511308Santhony.gutierrez@amd.com /// Cached symbol table pointer from last disassembly 2611308Santhony.gutierrez@amd.com mutable const SymbolTable *cachedSymtab; 2711308Santhony.gutierrez@amd.com 2811308Santhony.gutierrez@amd.com /// Constructor 2911308Santhony.gutierrez@amd.com PCDependentDisassembly(const char *mnem, MachInst _machInst, 3011308Santhony.gutierrez@amd.com OpClass __opClass) 3111308Santhony.gutierrez@amd.com : MipsStaticInst(mnem, _machInst, __opClass), 3211308Santhony.gutierrez@amd.com cachedPC(0), cachedSymtab(0) 3311308Santhony.gutierrez@amd.com { 3411308Santhony.gutierrez@amd.com } 3511308Santhony.gutierrez@amd.com 3611308Santhony.gutierrez@amd.com const std::string & 3711308Santhony.gutierrez@amd.com disassemble(Addr pc, const SymbolTable *symtab) const; 3811308Santhony.gutierrez@amd.com }; 3911308Santhony.gutierrez@amd.com 4011308Santhony.gutierrez@amd.com /** 4111308Santhony.gutierrez@amd.com * Base class for branches (PC-relative control transfers), 4211308Santhony.gutierrez@amd.com * conditional or unconditional. 4311308Santhony.gutierrez@amd.com */ 4411308Santhony.gutierrez@amd.com class Branch : public PCDependentDisassembly 4511308Santhony.gutierrez@amd.com { 4611308Santhony.gutierrez@amd.com protected: 4711308Santhony.gutierrez@amd.com /// target address (signed) Displacement . 4811308Santhony.gutierrez@amd.com int32_t disp; 4911308Santhony.gutierrez@amd.com 5011308Santhony.gutierrez@amd.com /// Constructor. 5111308Santhony.gutierrez@amd.com Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 5211308Santhony.gutierrez@amd.com : PCDependentDisassembly(mnem, _machInst, __opClass), 5311308Santhony.gutierrez@amd.com disp(OFFSET << 2) 5411308Santhony.gutierrez@amd.com { 5511641Salexandru.dutu@amd.com } 5611641Salexandru.dutu@amd.com 5711641Salexandru.dutu@amd.com Addr branchTarget(Addr branchPC) const; 5811641Salexandru.dutu@amd.com 5911641Salexandru.dutu@amd.com std::string 6011641Salexandru.dutu@amd.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 6111641Salexandru.dutu@amd.com }; 6211641Salexandru.dutu@amd.com 6311641Salexandru.dutu@amd.com /** 6411641Salexandru.dutu@amd.com * Base class for branch likely branches (PC-relative control transfers), 6511641Salexandru.dutu@amd.com */ 6611641Salexandru.dutu@amd.com class BranchLikely : public PCDependentDisassembly 6711641Salexandru.dutu@amd.com { 6811641Salexandru.dutu@amd.com protected: 6911641Salexandru.dutu@amd.com /// target address (signed) Displacement . 7011641Salexandru.dutu@amd.com int32_t disp; 7111641Salexandru.dutu@amd.com 7211641Salexandru.dutu@amd.com /// Constructor. 7311641Salexandru.dutu@amd.com Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 7411641Salexandru.dutu@amd.com : PCDependentDisassembly(mnem, _machInst, __opClass), 7511641Salexandru.dutu@amd.com disp(OFFSET << 2) 7611308Santhony.gutierrez@amd.com { 7711308Santhony.gutierrez@amd.com } 7811308Santhony.gutierrez@amd.com 7911308Santhony.gutierrez@amd.com Addr branchTarget(Addr branchPC) const; 8011308Santhony.gutierrez@amd.com 8111308Santhony.gutierrez@amd.com std::string 8211308Santhony.gutierrez@amd.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 8311308Santhony.gutierrez@amd.com }; 8411308Santhony.gutierrez@amd.com 8511308Santhony.gutierrez@amd.com /** 8611308Santhony.gutierrez@amd.com * Base class for jumps (register-indirect control transfers). In 8711308Santhony.gutierrez@amd.com * the Mips ISA, these are always unconditional. 8811308Santhony.gutierrez@amd.com */ 8911308Santhony.gutierrez@amd.com class Jump : public PCDependentDisassembly 9011308Santhony.gutierrez@amd.com { 9111308Santhony.gutierrez@amd.com protected: 9211308Santhony.gutierrez@amd.com 9311308Santhony.gutierrez@amd.com /// Displacement to target address (signed). 9411308Santhony.gutierrez@amd.com int32_t disp; 9511308Santhony.gutierrez@amd.com 9611308Santhony.gutierrez@amd.com public: 9711308Santhony.gutierrez@amd.com /// Constructor 9811308Santhony.gutierrez@amd.com Jump(const char *mnem, MachInst _machInst, OpClass __opClass) 9911308Santhony.gutierrez@amd.com : PCDependentDisassembly(mnem, _machInst, __opClass), 10011308Santhony.gutierrez@amd.com disp(OFFSET) 10111308Santhony.gutierrez@amd.com { 10211308Santhony.gutierrez@amd.com } 10311308Santhony.gutierrez@amd.com 10411308Santhony.gutierrez@amd.com Addr branchTarget(ExecContext *xc) const; 10511308Santhony.gutierrez@amd.com 10611308Santhony.gutierrez@amd.com std::string 10711534Sjohn.kalamatianos@amd.com generateDisassembly(Addr pc, const SymbolTable *symtab) const; 10811308Santhony.gutierrez@amd.com }; 10911308Santhony.gutierrez@amd.com}}; 11011308Santhony.gutierrez@amd.com 11111308Santhony.gutierrez@amd.comoutput decoder {{ 11211308Santhony.gutierrez@amd.com Addr 11311308Santhony.gutierrez@amd.com Branch::branchTarget(Addr branchPC) const 11411308Santhony.gutierrez@amd.com { 11511534Sjohn.kalamatianos@amd.com return branchPC + 4 + disp; 11611308Santhony.gutierrez@amd.com } 11711308Santhony.gutierrez@amd.com 11811534Sjohn.kalamatianos@amd.com Addr 11911534Sjohn.kalamatianos@amd.com BranchLikely::branchTarget(Addr branchPC) const 12011308Santhony.gutierrez@amd.com { 12111534Sjohn.kalamatianos@amd.com return branchPC + 4 + disp; 12211308Santhony.gutierrez@amd.com } 12311308Santhony.gutierrez@amd.com 12411308Santhony.gutierrez@amd.com Addr 12511308Santhony.gutierrez@amd.com Jump::branchTarget(ExecContext *xc) const 12611308Santhony.gutierrez@amd.com { 12711308Santhony.gutierrez@amd.com Addr NPC = xc->readPC() + 4; 12811308Santhony.gutierrez@amd.com uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); 12911308Santhony.gutierrez@amd.com return (Rb & ~3) | (NPC & 1); 13011308Santhony.gutierrez@amd.com } 13111308Santhony.gutierrez@amd.com 13211308Santhony.gutierrez@amd.com const std::string & 13311308Santhony.gutierrez@amd.com PCDependentDisassembly::disassemble(Addr pc, 13411308Santhony.gutierrez@amd.com const SymbolTable *symtab) const 13511308Santhony.gutierrez@amd.com { 13611308Santhony.gutierrez@amd.com if (!cachedDisassembly || 13711308Santhony.gutierrez@amd.com pc != cachedPC || symtab != cachedSymtab) 13811308Santhony.gutierrez@amd.com { 13911308Santhony.gutierrez@amd.com if (cachedDisassembly) 14011308Santhony.gutierrez@amd.com delete cachedDisassembly; 14111308Santhony.gutierrez@amd.com 14211308Santhony.gutierrez@amd.com cachedDisassembly = 14311308Santhony.gutierrez@amd.com new std::string(generateDisassembly(pc, symtab)); 14411308Santhony.gutierrez@amd.com cachedPC = pc; 14511308Santhony.gutierrez@amd.com cachedSymtab = symtab; 14611308Santhony.gutierrez@amd.com } 14711308Santhony.gutierrez@amd.com 14811308Santhony.gutierrez@amd.com return *cachedDisassembly; 14911308Santhony.gutierrez@amd.com } 15011308Santhony.gutierrez@amd.com 15111639Salexandru.dutu@amd.com std::string 15211308Santhony.gutierrez@amd.com Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const 15311639Salexandru.dutu@amd.com { 15411639Salexandru.dutu@amd.com std::stringstream ss; 15511639Salexandru.dutu@amd.com 15611639Salexandru.dutu@amd.com ccprintf(ss, "%-10s ", mnemonic); 15711308Santhony.gutierrez@amd.com 15811308Santhony.gutierrez@amd.com // There's only one register arg (RA), but it could be 15911308Santhony.gutierrez@amd.com // either a source (the condition for conditional 16011639Salexandru.dutu@amd.com // branches) or a destination (the link reg for 16111308Santhony.gutierrez@amd.com // unconditional branches) 16211308Santhony.gutierrez@amd.com if (_numSrcRegs > 0) { 16311308Santhony.gutierrez@amd.com printReg(ss, _srcRegIdx[0]); 16411308Santhony.gutierrez@amd.com ss << ","; 16511308Santhony.gutierrez@amd.com } 16611308Santhony.gutierrez@amd.com else if (_numDestRegs > 0) { 16711308Santhony.gutierrez@amd.com printReg(ss, _destRegIdx[0]); 16811308Santhony.gutierrez@amd.com ss << ","; 16911308Santhony.gutierrez@amd.com } 17011308Santhony.gutierrez@amd.com 17111308Santhony.gutierrez@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY 17211308Santhony.gutierrez@amd.com if (_numSrcRegs == 0 && _numDestRegs == 0) { 17311308Santhony.gutierrez@amd.com printReg(ss, 31); 17411308Santhony.gutierrez@amd.com ss << ","; 17511308Santhony.gutierrez@amd.com } 17611308Santhony.gutierrez@amd.com#endif 17711308Santhony.gutierrez@amd.com 17811308Santhony.gutierrez@amd.com Addr target = pc + 4 + disp; 17911308Santhony.gutierrez@amd.com 18011308Santhony.gutierrez@amd.com std::string str; 18111308Santhony.gutierrez@amd.com if (symtab && symtab->findSymbol(target, str)) 18211308Santhony.gutierrez@amd.com ss << str; 18311308Santhony.gutierrez@amd.com else 18411308Santhony.gutierrez@amd.com ccprintf(ss, "0x%x", target); 18511308Santhony.gutierrez@amd.com 18611308Santhony.gutierrez@amd.com return ss.str(); 18711308Santhony.gutierrez@amd.com } 18811308Santhony.gutierrez@amd.com 18911639Salexandru.dutu@amd.com std::string 19011639Salexandru.dutu@amd.com BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const 19111639Salexandru.dutu@amd.com { 19211639Salexandru.dutu@amd.com std::stringstream ss; 19311639Salexandru.dutu@amd.com 19411639Salexandru.dutu@amd.com ccprintf(ss, "%-10s ", mnemonic); 19511639Salexandru.dutu@amd.com 19611639Salexandru.dutu@amd.com // There's only one register arg (RA), but it could be 19711639Salexandru.dutu@amd.com // either a source (the condition for conditional 19811639Salexandru.dutu@amd.com // branches) or a destination (the link reg for 19911639Salexandru.dutu@amd.com // unconditional branches) 20011308Santhony.gutierrez@amd.com if (_numSrcRegs > 0) { 20111639Salexandru.dutu@amd.com printReg(ss, _srcRegIdx[0]); 20211308Santhony.gutierrez@amd.com ss << ","; 20311308Santhony.gutierrez@amd.com } 20411639Salexandru.dutu@amd.com else if (_numDestRegs > 0) { 20511308Santhony.gutierrez@amd.com printReg(ss, _destRegIdx[0]); 20611639Salexandru.dutu@amd.com ss << ","; 20711308Santhony.gutierrez@amd.com } 20811639Salexandru.dutu@amd.com 20911308Santhony.gutierrez@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY 21011639Salexandru.dutu@amd.com if (_numSrcRegs == 0 && _numDestRegs == 0) { 21111308Santhony.gutierrez@amd.com printReg(ss, 31); 21211639Salexandru.dutu@amd.com ss << ","; 21311639Salexandru.dutu@amd.com } 21411639Salexandru.dutu@amd.com#endif 21511639Salexandru.dutu@amd.com 21611639Salexandru.dutu@amd.com Addr target = pc + 4 + disp; 21711308Santhony.gutierrez@amd.com 21811639Salexandru.dutu@amd.com std::string str; 21911639Salexandru.dutu@amd.com if (symtab && symtab->findSymbol(target, str)) 22011308Santhony.gutierrez@amd.com ss << str; 22111308Santhony.gutierrez@amd.com else 22211308Santhony.gutierrez@amd.com ccprintf(ss, "0x%x", target); 22311308Santhony.gutierrez@amd.com 22411308Santhony.gutierrez@amd.com return ss.str(); 22511308Santhony.gutierrez@amd.com } 22611308Santhony.gutierrez@amd.com 22711639Salexandru.dutu@amd.com std::string 22811308Santhony.gutierrez@amd.com Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const 22911639Salexandru.dutu@amd.com { 23011308Santhony.gutierrez@amd.com std::stringstream ss; 23111639Salexandru.dutu@amd.com 23211308Santhony.gutierrez@amd.com ccprintf(ss, "%-10s ", mnemonic); 23311308Santhony.gutierrez@amd.com 23411639Salexandru.dutu@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY 23511308Santhony.gutierrez@amd.com if (_numDestRegs == 0) { 23611639Salexandru.dutu@amd.com printReg(ss, 31); 23711308Santhony.gutierrez@amd.com ss << ","; 23811639Salexandru.dutu@amd.com } 23911308Santhony.gutierrez@amd.com#endif 24011308Santhony.gutierrez@amd.com 24111639Salexandru.dutu@amd.com if (_numDestRegs > 0) { 24211308Santhony.gutierrez@amd.com printReg(ss, _destRegIdx[0]); 24311308Santhony.gutierrez@amd.com ss << ","; 24411639Salexandru.dutu@amd.com } 24511639Salexandru.dutu@amd.com 24611308Santhony.gutierrez@amd.com ccprintf(ss, "(r%d)", RB); 24711308Santhony.gutierrez@amd.com 24811308Santhony.gutierrez@amd.com return ss.str(); 24911308Santhony.gutierrez@amd.com } 25011308Santhony.gutierrez@amd.com}}; 25111308Santhony.gutierrez@amd.com 25211308Santhony.gutierrez@amd.comdef format Branch(code,*flags) {{ 25311308Santhony.gutierrez@amd.com #Add Link Code if Link instruction 25411308Santhony.gutierrez@amd.com strlen = len(name) 25511308Santhony.gutierrez@amd.com if name[strlen-2:] == 'al': 25611308Santhony.gutierrez@amd.com code += 'R31 = NNPC;\n' 25711308Santhony.gutierrez@amd.com 25811308Santhony.gutierrez@amd.com #Condition code 25911308Santhony.gutierrez@amd.com code = 'bool cond;\n' + code 26011308Santhony.gutierrez@amd.com code += 'if (cond) {\n' 26111308Santhony.gutierrez@amd.com #code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n' 26211308Santhony.gutierrez@amd.com #code += ' NPC = NPC; \n' 26311308Santhony.gutierrez@amd.com code += ' NNPC = NPC + disp;\n' 26411308Santhony.gutierrez@amd.com code += '} \n' 26511308Santhony.gutierrez@amd.com 26611308Santhony.gutierrez@amd.com iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), 26711308Santhony.gutierrez@amd.com ('IsDirectControl', 'IsCondControl')) 26811308Santhony.gutierrez@amd.com 26911308Santhony.gutierrez@amd.com header_output = BasicDeclare.subst(iop) 27011308Santhony.gutierrez@amd.com decoder_output = BasicConstructor.subst(iop) 27111308Santhony.gutierrez@amd.com decode_block = BasicDecode.subst(iop) 27211308Santhony.gutierrez@amd.com exec_output = BasicExecute.subst(iop) 27311308Santhony.gutierrez@amd.com}}; 27411308Santhony.gutierrez@amd.com 27511308Santhony.gutierrez@amd.com 27611308Santhony.gutierrez@amd.comdef format BranchLikely(code,*flags) {{ 27711308Santhony.gutierrez@amd.com #Add Link Code if Link instruction 27811308Santhony.gutierrez@amd.com strlen = len(name) 27911308Santhony.gutierrez@amd.com if name[strlen-3:] == 'all': 28011308Santhony.gutierrez@amd.com code += 'R31 = NNPC;\n' 28111308Santhony.gutierrez@amd.com 28211308Santhony.gutierrez@amd.com #Condition code 28311308Santhony.gutierrez@amd.com code = 'bool cond;\n' + code 28411308Santhony.gutierrez@amd.com code += 'if (cond) {' 28511308Santhony.gutierrez@amd.com #code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n' 28611308Santhony.gutierrez@amd.com #code += 'NPC = NPC; \n' 28711308Santhony.gutierrez@amd.com code += 'NNPC = NPC + disp;\n' 28811308Santhony.gutierrez@amd.com code += '} \n' 28911308Santhony.gutierrez@amd.com 29011308Santhony.gutierrez@amd.com 29111308Santhony.gutierrez@amd.com iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), 29211308Santhony.gutierrez@amd.com ('IsDirectControl', 'IsCondControl','IsCondDelaySlot')) 29311534Sjohn.kalamatianos@amd.com 29411308Santhony.gutierrez@amd.com header_output = BasicDeclare.subst(iop) 29511534Sjohn.kalamatianos@amd.com decoder_output = BasicConstructor.subst(iop) 29611308Santhony.gutierrez@amd.com decode_block = BasicDecode.subst(iop) 29711308Santhony.gutierrez@amd.com exec_output = BasicExecute.subst(iop) 29811308Santhony.gutierrez@amd.com}}; 29911308Santhony.gutierrez@amd.com 30011308Santhony.gutierrez@amd.comdef format Jump(code,*flags) {{ 30111308Santhony.gutierrez@amd.com #Add Link Code if Link instruction 30211308Santhony.gutierrez@amd.com strlen = len(name) 30311308Santhony.gutierrez@amd.com if strlen >= 3 and name[2:3] == 'al': 30411308Santhony.gutierrez@amd.com code = 'R31 = NNPC;\n' + code 30511308Santhony.gutierrez@amd.com 30611308Santhony.gutierrez@amd.com iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\ 30711308Santhony.gutierrez@amd.com ('IsIndirectControl', 'IsUncondControl')) 30811308Santhony.gutierrez@amd.com 30911308Santhony.gutierrez@amd.com header_output = BasicDeclare.subst(iop) 31011308Santhony.gutierrez@amd.com decoder_output = BasicConstructor.subst(iop) 31111308Santhony.gutierrez@amd.com decode_block = BasicDecode.subst(iop) 31211308Santhony.gutierrez@amd.com exec_output = BasicExecute.subst(iop) 31311308Santhony.gutierrez@amd.com}}; 31411308Santhony.gutierrez@amd.com 31511308Santhony.gutierrez@amd.com 31611308Santhony.gutierrez@amd.com 31711308Santhony.gutierrez@amd.com 31811308Santhony.gutierrez@amd.com