12100SN/A// -*- mode:c++ -*- 22083SN/A 35268Sksewell@umich.edu// Copyright (c) 2007 MIPS Technologies, Inc. 45268Sksewell@umich.edu// All rights reserved. 55268Sksewell@umich.edu// 65268Sksewell@umich.edu// Redistribution and use in source and binary forms, with or without 75268Sksewell@umich.edu// modification, are permitted provided that the following conditions are 85268Sksewell@umich.edu// met: redistributions of source code must retain the above copyright 95268Sksewell@umich.edu// notice, this list of conditions and the following disclaimer; 105268Sksewell@umich.edu// redistributions in binary form must reproduce the above copyright 115268Sksewell@umich.edu// notice, this list of conditions and the following disclaimer in the 125268Sksewell@umich.edu// documentation and/or other materials provided with the distribution; 135268Sksewell@umich.edu// neither the name of the copyright holders nor the names of its 145268Sksewell@umich.edu// contributors may be used to endorse or promote products derived from 155268Sksewell@umich.edu// this software without specific prior written permission. 165268Sksewell@umich.edu// 175268Sksewell@umich.edu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 185268Sksewell@umich.edu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 195268Sksewell@umich.edu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 205268Sksewell@umich.edu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 215268Sksewell@umich.edu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 225268Sksewell@umich.edu// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 235268Sksewell@umich.edu// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 245268Sksewell@umich.edu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 255268Sksewell@umich.edu// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 265268Sksewell@umich.edu// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 275268Sksewell@umich.edu// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 285268Sksewell@umich.edu// 295268Sksewell@umich.edu// Authors: Korey Sewell 302706Sksewell@umich.edu 312089SN/A//////////////////////////////////////////////////////////////////// 322022SN/A// 332089SN/A// Control transfer instructions 342022SN/A// 352022SN/A 362022SN/Aoutput header {{ 372083SN/A 382239SN/A#include <iostream> 394661Sksewell@umich.edu using namespace std; 402239SN/A 412083SN/A /** 422083SN/A * Base class for instructions whose disassembly is not purely a 432083SN/A * function of the machine instruction (i.e., it depends on the 442083SN/A * PC). This class overrides the disassemble() method to check 452083SN/A * the PC and symbol table values before re-using a cached 462083SN/A * disassembly string. This is necessary for branches and jumps, 472083SN/A * where the disassembly string includes the target address (which 482083SN/A * may depend on the PC and/or symbol table). 492083SN/A */ 502089SN/A class PCDependentDisassembly : public MipsStaticInst 512083SN/A { 522083SN/A protected: 532083SN/A /// Cached program counter from last disassembly 542083SN/A mutable Addr cachedPC; 552089SN/A 562083SN/A /// Cached symbol table pointer from last disassembly 572083SN/A mutable const SymbolTable *cachedSymtab; 582083SN/A 592083SN/A /// Constructor 602083SN/A PCDependentDisassembly(const char *mnem, MachInst _machInst, 612083SN/A OpClass __opClass) 622089SN/A : MipsStaticInst(mnem, _machInst, __opClass), 632083SN/A cachedPC(0), cachedSymtab(0) 642022SN/A { 652083SN/A } 662022SN/A 672083SN/A const std::string & 682083SN/A disassemble(Addr pc, const SymbolTable *symtab) const; 692083SN/A }; 702022SN/A 712083SN/A /** 722083SN/A * Base class for branches (PC-relative control transfers), 732083SN/A * conditional or unconditional. 742083SN/A */ 752083SN/A class Branch : public PCDependentDisassembly 762083SN/A { 772083SN/A protected: 782089SN/A /// target address (signed) Displacement . 792104SN/A int32_t disp; 802083SN/A 812083SN/A /// Constructor. 822083SN/A Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 832083SN/A : PCDependentDisassembly(mnem, _machInst, __opClass), 842104SN/A disp(OFFSET << 2) 852089SN/A { 862239SN/A //If Bit 17 is 1 then Sign Extend 872239SN/A if ( (disp & 0x00020000) > 0 ) { 882239SN/A disp |= 0xFFFE0000; 892239SN/A } 902089SN/A } 912089SN/A 9212616Sgabeblack@google.com MipsISA::PCState branchTarget( 9312616Sgabeblack@google.com const MipsISA::PCState &branchPC) const override; 942089SN/A 959552Sandreas.hansson@arm.com /// Explicitly import the otherwise hidden branchTarget 969552Sandreas.hansson@arm.com using StaticInst::branchTarget; 979552Sandreas.hansson@arm.com 9812616Sgabeblack@google.com std::string generateDisassembly( 9912616Sgabeblack@google.com Addr pc, const SymbolTable *symtab) const override; 1002089SN/A }; 1012089SN/A 1022089SN/A /** 1032083SN/A * Base class for jumps (register-indirect control transfers). In 1042089SN/A * the Mips ISA, these are always unconditional. 1052083SN/A */ 1062083SN/A class Jump : public PCDependentDisassembly 1072083SN/A { 1082083SN/A protected: 1092083SN/A 1102083SN/A /// Displacement to target address (signed). 1112083SN/A int32_t disp; 1122083SN/A 1132239SN/A uint32_t target; 1142239SN/A 1152083SN/A public: 1162083SN/A /// Constructor 1172083SN/A Jump(const char *mnem, MachInst _machInst, OpClass __opClass) 1182083SN/A : PCDependentDisassembly(mnem, _machInst, __opClass), 1192239SN/A disp(JMPTARG << 2) 1202083SN/A { 1212083SN/A } 1222083SN/A 12312616Sgabeblack@google.com MipsISA::PCState branchTarget(ThreadContext *tc) const override; 1242083SN/A 1259552Sandreas.hansson@arm.com /// Explicitly import the otherwise hidden branchTarget 1269552Sandreas.hansson@arm.com using StaticInst::branchTarget; 1279552Sandreas.hansson@arm.com 12812616Sgabeblack@google.com std::string generateDisassembly( 12912616Sgabeblack@google.com Addr pc, const SymbolTable *symtab) const override; 1302083SN/A }; 1312022SN/A}}; 1322022SN/A 1332022SN/Aoutput decoder {{ 1347720Sgblack@eecs.umich.edu MipsISA::PCState 1357720Sgblack@eecs.umich.edu Branch::branchTarget(const MipsISA::PCState &branchPC) const 1362083SN/A { 1377720Sgblack@eecs.umich.edu MipsISA::PCState target = branchPC; 1387720Sgblack@eecs.umich.edu target.advance(); 1397720Sgblack@eecs.umich.edu target.npc(branchPC.pc() + sizeof(MachInst) + disp); 1407720Sgblack@eecs.umich.edu target.nnpc(target.npc() + sizeof(MachInst)); 1417720Sgblack@eecs.umich.edu return target; 1422083SN/A } 1432083SN/A 1447720Sgblack@eecs.umich.edu MipsISA::PCState 1452687Sksewell@umich.edu Jump::branchTarget(ThreadContext *tc) const 1462083SN/A { 1477720Sgblack@eecs.umich.edu MipsISA::PCState target = tc->pcState(); 1487720Sgblack@eecs.umich.edu Addr pc = target.pc(); 1497720Sgblack@eecs.umich.edu target.advance(); 1507720Sgblack@eecs.umich.edu target.npc((pc & 0xF0000000) | disp); 1517720Sgblack@eecs.umich.edu target.nnpc(target.npc() + sizeof(MachInst)); 1527720Sgblack@eecs.umich.edu return target; 1532083SN/A } 1542083SN/A 1552083SN/A const std::string & 1562083SN/A PCDependentDisassembly::disassemble(Addr pc, 1572083SN/A const SymbolTable *symtab) const 1582083SN/A { 1592083SN/A if (!cachedDisassembly || 1602083SN/A pc != cachedPC || symtab != cachedSymtab) 1612022SN/A { 1622083SN/A if (cachedDisassembly) 1632083SN/A delete cachedDisassembly; 1642083SN/A 1652083SN/A cachedDisassembly = 1662083SN/A new std::string(generateDisassembly(pc, symtab)); 1672083SN/A cachedPC = pc; 1682083SN/A cachedSymtab = symtab; 1692022SN/A } 1702083SN/A 1712083SN/A return *cachedDisassembly; 1722083SN/A } 1732083SN/A 1742083SN/A std::string 1752083SN/A Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1762083SN/A { 1772083SN/A std::stringstream ss; 1782083SN/A 1792083SN/A ccprintf(ss, "%-10s ", mnemonic); 1802083SN/A 1812083SN/A // There's only one register arg (RA), but it could be 1822083SN/A // either a source (the condition for conditional 1832083SN/A // branches) or a destination (the link reg for 1842083SN/A // unconditional branches) 1852239SN/A if (_numSrcRegs == 1) { 1862083SN/A printReg(ss, _srcRegIdx[0]); 1872686Sksewell@umich.edu ss << ", "; 1882239SN/A } else if(_numSrcRegs == 2) { 1892239SN/A printReg(ss, _srcRegIdx[0]); 1902686Sksewell@umich.edu ss << ", "; 1912239SN/A printReg(ss, _srcRegIdx[1]); 1922686Sksewell@umich.edu ss << ", "; 1932103SN/A } 1942103SN/A 1952103SN/A Addr target = pc + 4 + disp; 1962103SN/A 1972103SN/A std::string str; 1982103SN/A if (symtab && symtab->findSymbol(target, str)) 1992103SN/A ss << str; 2002103SN/A else 2012103SN/A ccprintf(ss, "0x%x", target); 2022103SN/A 2032103SN/A return ss.str(); 2042103SN/A } 2052103SN/A 2062103SN/A std::string 2072083SN/A Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const 2082083SN/A { 2092083SN/A std::stringstream ss; 2102083SN/A 2112083SN/A ccprintf(ss, "%-10s ", mnemonic); 2122083SN/A 2135269Sksewell@umich.edu if ( strcmp(mnemonic,"jal") == 0 ) { 2142239SN/A Addr npc = pc + 4; 2152239SN/A ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); 2162239SN/A } else if (_numSrcRegs == 0) { 2172239SN/A std::string str; 2182239SN/A if (symtab && symtab->findSymbol(disp, str)) 2192239SN/A ss << str; 2202239SN/A else 2212239SN/A ccprintf(ss, "0x%x", disp); 2222239SN/A } else if (_numSrcRegs == 1) { 2232239SN/A printReg(ss, _srcRegIdx[0]); 2242239SN/A } else if(_numSrcRegs == 2) { 2252239SN/A printReg(ss, _srcRegIdx[0]); 2262686Sksewell@umich.edu ss << ", "; 2272239SN/A printReg(ss, _srcRegIdx[1]); 2282083SN/A } 2292083SN/A 2302083SN/A return ss.str(); 2312083SN/A } 2322022SN/A}}; 2332022SN/A 2344661Sksewell@umich.edudef format Branch(code, *opt_flags) {{ 2357792Sgblack@eecs.umich.edu not_taken_code = 'NNPC = NNPC; NPC = NPC;' 2362686Sksewell@umich.edu 2372686Sksewell@umich.edu #Build Instruction Flags 2382686Sksewell@umich.edu #Use Link & Likely Flags to Add Link/Condition Code 2392686Sksewell@umich.edu inst_flags = ('IsDirectControl', ) 2402686Sksewell@umich.edu for x in opt_flags: 2412686Sksewell@umich.edu if x == 'Link': 2427792Sgblack@eecs.umich.edu code += 'R31 = NNPC;\n' 2432686Sksewell@umich.edu elif x == 'Likely': 2447792Sgblack@eecs.umich.edu not_taken_code = 'NNPC = NPC; NPC = PC;' 2454661Sksewell@umich.edu inst_flags += ('IsCondDelaySlot', ) 2462686Sksewell@umich.edu else: 2472686Sksewell@umich.edu inst_flags += (x, ) 2482686Sksewell@umich.edu 2492935Sksewell@umich.edu #Take into account uncond. branch instruction 2504661Sksewell@umich.edu if 'cond = 1' in code: 2514661Sksewell@umich.edu inst_flags += ('IsUncondControl', ) 2522935Sksewell@umich.edu else: 2532686Sksewell@umich.edu inst_flags += ('IsCondControl', ) 2542101SN/A 2552123SN/A #Condition code 2567720Sgblack@eecs.umich.edu code = ''' 2577720Sgblack@eecs.umich.edu bool cond; 2587720Sgblack@eecs.umich.edu %(code)s 2597720Sgblack@eecs.umich.edu if (cond) { 2607792Sgblack@eecs.umich.edu NNPC = NPC + disp; 2617720Sgblack@eecs.umich.edu } else { 2627720Sgblack@eecs.umich.edu %(not_taken_code)s 2637720Sgblack@eecs.umich.edu } 2647720Sgblack@eecs.umich.edu ''' % { "code" : code, "not_taken_code" : not_taken_code } 2652101SN/A 2663951Sgblack@eecs.umich.edu iop = InstObjParams(name, Name, 'Branch', code, inst_flags) 2672047SN/A header_output = BasicDeclare.subst(iop) 2682047SN/A decoder_output = BasicConstructor.subst(iop) 2692047SN/A decode_block = BasicDecode.subst(iop) 2702047SN/A exec_output = BasicExecute.subst(iop) 2712022SN/A}}; 2722047SN/A 2734661Sksewell@umich.edudef format DspBranch(code, *opt_flags) {{ 2747792Sgblack@eecs.umich.edu not_taken_code = 'NNPC = NNPC; NPC = NPC;' 2754661Sksewell@umich.edu 2764661Sksewell@umich.edu #Build Instruction Flags 2774661Sksewell@umich.edu #Use Link & Likely Flags to Add Link/Condition Code 2784661Sksewell@umich.edu inst_flags = ('IsDirectControl', ) 2794661Sksewell@umich.edu for x in opt_flags: 2804661Sksewell@umich.edu if x == 'Link': 2817792Sgblack@eecs.umich.edu code += 'R32 = NNPC;' 2824661Sksewell@umich.edu elif x == 'Likely': 2837792Sgblack@eecs.umich.edu not_taken_code = 'NNPC = NPC, NPC = PC;' 2844661Sksewell@umich.edu inst_flags += ('IsCondDelaySlot', ) 2854661Sksewell@umich.edu else: 2864661Sksewell@umich.edu inst_flags += (x, ) 2874661Sksewell@umich.edu 2884661Sksewell@umich.edu #Take into account uncond. branch instruction 2894661Sksewell@umich.edu if 'cond = 1' in code: 2904661Sksewell@umich.edu inst_flags += ('IsUncondControl', ) 2914661Sksewell@umich.edu else: 2924661Sksewell@umich.edu inst_flags += ('IsCondControl', ) 2934661Sksewell@umich.edu 2944661Sksewell@umich.edu #Condition code 2957720Sgblack@eecs.umich.edu code = ''' 2967720Sgblack@eecs.umich.edu bool cond; 2977720Sgblack@eecs.umich.edu uint32_t dspctl = DSPControl; 2987720Sgblack@eecs.umich.edu %(code)s 2997720Sgblack@eecs.umich.edu if (cond) { 3007792Sgblack@eecs.umich.edu NNPC = NPC + disp; 3017720Sgblack@eecs.umich.edu } else { 3027720Sgblack@eecs.umich.edu %(not_taken_code)s 3037720Sgblack@eecs.umich.edu } 3047720Sgblack@eecs.umich.edu ''' % { "code" : code, "not_taken_code" : not_taken_code } 3054661Sksewell@umich.edu 3064661Sksewell@umich.edu iop = InstObjParams(name, Name, 'Branch', code, inst_flags) 3074661Sksewell@umich.edu header_output = BasicDeclare.subst(iop) 3084661Sksewell@umich.edu decoder_output = BasicConstructor.subst(iop) 3094661Sksewell@umich.edu decode_block = BasicDecode.subst(iop) 3104661Sksewell@umich.edu exec_output = BasicExecute.subst(iop) 3114661Sksewell@umich.edu}}; 3124661Sksewell@umich.edu 3132686Sksewell@umich.edudef format Jump(code, *opt_flags) {{ 3142686Sksewell@umich.edu #Build Instruction Flags 3152686Sksewell@umich.edu #Use Link Flag to Add Link Code 3162686Sksewell@umich.edu inst_flags = ('IsIndirectControl', 'IsUncondControl') 3172686Sksewell@umich.edu for x in opt_flags: 3182686Sksewell@umich.edu if x == 'Link': 3197720Sgblack@eecs.umich.edu code = ''' 3207792Sgblack@eecs.umich.edu R31 = NNPC; 3217720Sgblack@eecs.umich.edu ''' + code 3222686Sksewell@umich.edu elif x == 'ClearHazards': 3232686Sksewell@umich.edu code += '/* Code Needed to Clear Execute & Inst Hazards */\n' 3242686Sksewell@umich.edu else: 3252686Sksewell@umich.edu inst_flags += (x, ) 3262104SN/A 3273951Sgblack@eecs.umich.edu iop = InstObjParams(name, Name, 'Jump', code, inst_flags) 3282089SN/A header_output = BasicDeclare.subst(iop) 3292089SN/A decoder_output = BasicConstructor.subst(iop) 3302089SN/A decode_block = BasicDecode.subst(iop) 3312089SN/A exec_output = BasicExecute.subst(iop) 3322089SN/A}}; 3332083SN/A 3342239SN/A 3352123SN/A 3362123SN/A 337