branch.isa revision 2107
1// -*- mode:c++ -*- 2 3// Copyright (c) 2003-2005 The Regents of The University of Michigan 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are 8// met: redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer; 10// redistributions in binary form must reproduce the above copyright 11// notice, this list of conditions and the following disclaimer in the 12// documentation and/or other materials provided with the distribution; 13// neither the name of the copyright holders nor the names of its 14// contributors may be used to endorse or promote products derived from 15// this software without specific prior written permission. 16// 17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29output header {{ 30 31 /** 32 * Base class for instructions whose disassembly is not purely a 33 * function of the machine instruction (i.e., it depends on the 34 * PC). This class overrides the disassemble() method to check 35 * the PC and symbol table values before re-using a cached 36 * disassembly string. This is necessary for branches and jumps, 37 * where the disassembly string includes the target address (which 38 * may depend on the PC and/or symbol table). 39 */ 40 class PCDependentDisassembly : public AlphaStaticInst 41 { 42 protected: 43 typedef TheISA::Addr Addr; 44 protected: 45 /// Cached program counter from last disassembly 46 mutable Addr cachedPC; 47 /// Cached symbol table pointer from last disassembly 48 mutable const SymbolTable *cachedSymtab; 49 50 /// Constructor 51 PCDependentDisassembly(const char *mnem, MachInst _machInst, 52 OpClass __opClass) 53 : AlphaStaticInst(mnem, _machInst, __opClass), 54 cachedPC(0), cachedSymtab(0) 55 { 56 } 57 58 const std::string & 59 disassemble(Addr pc, const SymbolTable *symtab) const; 60 }; 61 62 /** 63 * Base class for branches (PC-relative control transfers), 64 * conditional or unconditional. 65 */ 66 class Branch : public PCDependentDisassembly 67 { 68 protected: 69 typedef TheISA::Addr Addr; 70 /// Displacement to target address (signed). 71 int32_t disp; 72 73 /// Constructor. 74 Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 75 : PCDependentDisassembly(mnem, _machInst, __opClass), 76 disp(BRDISP << 2) 77 { 78 } 79 80 Addr branchTarget(Addr branchPC) const; 81 82 std::string 83 generateDisassembly(Addr pc, const SymbolTable *symtab) const; 84 }; 85 86 /** 87 * Base class for jumps (register-indirect control transfers). In 88 * the Alpha ISA, these are always unconditional. 89 */ 90 class Jump : public PCDependentDisassembly 91 { 92 protected: 93 typedef TheISA::Addr Addr; 94 95 /// Displacement to target address (signed). 96 int32_t disp; 97 98 public: 99 /// Constructor 100 Jump(const char *mnem, MachInst _machInst, OpClass __opClass) 101 : PCDependentDisassembly(mnem, _machInst, __opClass), 102 disp(BRDISP) 103 { 104 } 105 106 Addr branchTarget(ExecContext *xc) const; 107 108 std::string 109 generateDisassembly(Addr pc, const SymbolTable *symtab) const; 110 }; 111}}; 112 113output decoder {{ 114 Addr 115 Branch::branchTarget(Addr branchPC) const 116 { 117 return branchPC + 4 + disp; 118 } 119 120 Addr 121 Jump::branchTarget(ExecContext *xc) const 122 { 123 Addr NPC = xc->readPC() + 4; 124 uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); 125 return (Rb & ~3) | (NPC & 1); 126 } 127 128 const std::string & 129 PCDependentDisassembly::disassemble(Addr pc, 130 const SymbolTable *symtab) const 131 { 132 if (!cachedDisassembly || 133 pc != cachedPC || symtab != cachedSymtab) 134 { 135 if (cachedDisassembly) 136 delete cachedDisassembly; 137 138 cachedDisassembly = 139 new std::string(generateDisassembly(pc, symtab)); 140 cachedPC = pc; 141 cachedSymtab = symtab; 142 } 143 144 return *cachedDisassembly; 145 } 146 147 std::string 148 Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const 149 { 150 std::stringstream ss; 151 152 ccprintf(ss, "%-10s ", mnemonic); 153 154 // There's only one register arg (RA), but it could be 155 // either a source (the condition for conditional 156 // branches) or a destination (the link reg for 157 // unconditional branches) 158 if (_numSrcRegs > 0) { 159 printReg(ss, _srcRegIdx[0]); 160 ss << ","; 161 } 162 else if (_numDestRegs > 0) { 163 printReg(ss, _destRegIdx[0]); 164 ss << ","; 165 } 166 167#ifdef SS_COMPATIBLE_DISASSEMBLY 168 if (_numSrcRegs == 0 && _numDestRegs == 0) { 169 printReg(ss, 31); 170 ss << ","; 171 } 172#endif 173 174 Addr target = pc + 4 + disp; 175 176 std::string str; 177 if (symtab && symtab->findSymbol(target, str)) 178 ss << str; 179 else 180 ccprintf(ss, "0x%x", target); 181 182 return ss.str(); 183 } 184 185 std::string 186 Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const 187 { 188 std::stringstream ss; 189 190 ccprintf(ss, "%-10s ", mnemonic); 191 192#ifdef SS_COMPATIBLE_DISASSEMBLY 193 if (_numDestRegs == 0) { 194 printReg(ss, 31); 195 ss << ","; 196 } 197#endif 198 199 if (_numDestRegs > 0) { 200 printReg(ss, _destRegIdx[0]); 201 ss << ","; 202 } 203 204 ccprintf(ss, "(r%d)", RB); 205 206 return ss.str(); 207 } 208}}; 209 210def template JumpOrBranchDecode {{ 211 return (RA == 31) 212 ? (StaticInst *)new %(class_name)s(machInst) 213 : (StaticInst *)new %(class_name)sAndLink(machInst); 214}}; 215 216def format CondBranch(code) {{ 217 code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; 218 iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), 219 ('IsDirectControl', 'IsCondControl')) 220 header_output = BasicDeclare.subst(iop) 221 decoder_output = BasicConstructor.subst(iop) 222 decode_block = BasicDecode.subst(iop) 223 exec_output = BasicExecute.subst(iop) 224}}; 225 226let {{ 227def UncondCtrlBase(name, Name, base_class, npc_expr, flags): 228 # Declare basic control transfer w/o link (i.e. link reg is R31) 229 nolink_code = 'NPC = %s;\n' % npc_expr 230 nolink_iop = InstObjParams(name, Name, base_class, 231 CodeBlock(nolink_code), flags) 232 header_output = BasicDeclare.subst(nolink_iop) 233 decoder_output = BasicConstructor.subst(nolink_iop) 234 exec_output = BasicExecute.subst(nolink_iop) 235 236 # Generate declaration of '*AndLink' version, append to decls 237 link_code = 'Ra = NPC & ~3;\n' + nolink_code 238 link_iop = InstObjParams(name, Name + 'AndLink', base_class, 239 CodeBlock(link_code), flags) 240 header_output += BasicDeclare.subst(link_iop) 241 decoder_output += BasicConstructor.subst(link_iop) 242 exec_output += BasicExecute.subst(link_iop) 243 244 # need to use link_iop for the decode template since it is expecting 245 # the shorter version of class_name (w/o "AndLink") 246 247 return (header_output, decoder_output, 248 JumpOrBranchDecode.subst(nolink_iop), exec_output) 249}}; 250 251def format UncondBranch(*flags) {{ 252 flags += ('IsUncondControl', 'IsDirectControl') 253 (header_output, decoder_output, decode_block, exec_output) = \ 254 UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) 255}}; 256 257def format Jump(*flags) {{ 258 flags += ('IsUncondControl', 'IsIndirectControl') 259 (header_output, decoder_output, decode_block, exec_output) = \ 260 UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) 261}}; 262 263 264