1// -*- mode:c++ -*- 2 3// Copyright (c) 2007 MIPS Technologies, Inc. 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// 29// Authors: Korey Sewell 30 31//////////////////////////////////////////////////////////////////// 32// 33// Control transfer instructions 34// 35 36output header {{ 37 38#include <iostream> 39 using namespace std; 40 41 /** 42 * Base class for instructions whose disassembly is not purely a 43 * function of the machine instruction (i.e., it depends on the 44 * PC). This class overrides the disassemble() method to check 45 * the PC and symbol table values before re-using a cached 46 * disassembly string. This is necessary for branches and jumps, 47 * where the disassembly string includes the target address (which 48 * may depend on the PC and/or symbol table). 49 */ 50 class PCDependentDisassembly : public MipsStaticInst 51 { 52 protected: 53 /// Cached program counter from last disassembly 54 mutable Addr cachedPC; 55 56 /// Cached symbol table pointer from last disassembly 57 mutable const SymbolTable *cachedSymtab; 58 59 /// Constructor 60 PCDependentDisassembly(const char *mnem, MachInst _machInst, 61 OpClass __opClass) 62 : MipsStaticInst(mnem, _machInst, __opClass), 63 cachedPC(0), cachedSymtab(0) 64 { 65 } 66 67 const std::string & 68 disassemble(Addr pc, const SymbolTable *symtab) const; 69 }; 70 71 /** 72 * Base class for branches (PC-relative control transfers), 73 * conditional or unconditional. 74 */ 75 class Branch : public PCDependentDisassembly 76 { 77 protected: 78 /// target address (signed) Displacement . 79 int32_t disp; 80 81 /// Constructor. 82 Branch(const char *mnem, MachInst _machInst, OpClass __opClass) 83 : PCDependentDisassembly(mnem, _machInst, __opClass), 84 disp(OFFSET << 2) 85 { 86 //If Bit 17 is 1 then Sign Extend 87 if ( (disp & 0x00020000) > 0 ) { 88 disp |= 0xFFFE0000; 89 } 90 } 91 92 MipsISA::PCState branchTarget( 93 const MipsISA::PCState &branchPC) const override; 94 95 /// Explicitly import the otherwise hidden branchTarget 96 using StaticInst::branchTarget; 97 98 std::string generateDisassembly( 99 Addr pc, const SymbolTable *symtab) const override; 100 }; 101 102 /** 103 * Base class for jumps (register-indirect control transfers). In 104 * the Mips ISA, these are always unconditional. 105 */ 106 class Jump : public PCDependentDisassembly 107 { 108 protected: 109 110 /// Displacement to target address (signed). 111 int32_t disp; 112 113 uint32_t target; 114 115 public: 116 /// Constructor 117 Jump(const char *mnem, MachInst _machInst, OpClass __opClass) 118 : PCDependentDisassembly(mnem, _machInst, __opClass), 119 disp(JMPTARG << 2) 120 { 121 } 122 123 MipsISA::PCState branchTarget(ThreadContext *tc) const override; 124 125 /// Explicitly import the otherwise hidden branchTarget 126 using StaticInst::branchTarget; 127 128 std::string generateDisassembly( 129 Addr pc, const SymbolTable *symtab) const override; 130 }; 131}}; 132 133output decoder {{ 134 MipsISA::PCState 135 Branch::branchTarget(const MipsISA::PCState &branchPC) const 136 { 137 MipsISA::PCState target = branchPC; 138 target.advance(); 139 target.npc(branchPC.pc() + sizeof(MachInst) + disp); 140 target.nnpc(target.npc() + sizeof(MachInst)); 141 return target; 142 } 143 144 MipsISA::PCState 145 Jump::branchTarget(ThreadContext *tc) const 146 { 147 MipsISA::PCState target = tc->pcState(); 148 Addr pc = target.pc(); 149 target.advance(); 150 target.npc((pc & 0xF0000000) | disp); 151 target.nnpc(target.npc() + sizeof(MachInst)); 152 return target; 153 } 154 155 const std::string & 156 PCDependentDisassembly::disassemble(Addr pc, 157 const SymbolTable *symtab) const 158 { 159 if (!cachedDisassembly || 160 pc != cachedPC || symtab != cachedSymtab) 161 { 162 if (cachedDisassembly) 163 delete cachedDisassembly; 164 165 cachedDisassembly = 166 new std::string(generateDisassembly(pc, symtab)); 167 cachedPC = pc; 168 cachedSymtab = symtab; 169 } 170 171 return *cachedDisassembly; 172 } 173 174 std::string 175 Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const 176 { 177 std::stringstream ss; 178 179 ccprintf(ss, "%-10s ", mnemonic); 180 181 // There's only one register arg (RA), but it could be 182 // either a source (the condition for conditional 183 // branches) or a destination (the link reg for 184 // unconditional branches) 185 if (_numSrcRegs == 1) { 186 printReg(ss, _srcRegIdx[0]); 187 ss << ", "; 188 } else if(_numSrcRegs == 2) { 189 printReg(ss, _srcRegIdx[0]); 190 ss << ", "; 191 printReg(ss, _srcRegIdx[1]); 192 ss << ", "; 193 } 194 195 Addr target = pc + 4 + disp; 196 197 std::string str; 198 if (symtab && symtab->findSymbol(target, str)) 199 ss << str; 200 else 201 ccprintf(ss, "0x%x", target); 202 203 return ss.str(); 204 } 205 206 std::string 207 Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const 208 { 209 std::stringstream ss; 210 211 ccprintf(ss, "%-10s ", mnemonic); 212 213 if ( strcmp(mnemonic,"jal") == 0 ) { 214 Addr npc = pc + 4; 215 ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); 216 } else if (_numSrcRegs == 0) { 217 std::string str; 218 if (symtab && symtab->findSymbol(disp, str)) 219 ss << str; 220 else 221 ccprintf(ss, "0x%x", disp); 222 } else if (_numSrcRegs == 1) { 223 printReg(ss, _srcRegIdx[0]); 224 } else if(_numSrcRegs == 2) { 225 printReg(ss, _srcRegIdx[0]); 226 ss << ", "; 227 printReg(ss, _srcRegIdx[1]); 228 } 229 230 return ss.str(); 231 } 232}}; 233 234def format Branch(code, *opt_flags) {{ 235 not_taken_code = 'NNPC = NNPC; NPC = NPC;' 236 237 #Build Instruction Flags 238 #Use Link & Likely Flags to Add Link/Condition Code 239 inst_flags = ('IsDirectControl', ) 240 for x in opt_flags: 241 if x == 'Link': 242 code += 'R31 = NNPC;\n' 243 elif x == 'Likely': 244 not_taken_code = 'NNPC = NPC; NPC = PC;' 245 inst_flags += ('IsCondDelaySlot', ) 246 else: 247 inst_flags += (x, ) 248 249 #Take into account uncond. branch instruction 250 if 'cond = 1' in code: 251 inst_flags += ('IsUncondControl', ) 252 else: 253 inst_flags += ('IsCondControl', ) 254 255 #Condition code 256 code = ''' 257 bool cond; 258 %(code)s 259 if (cond) { 260 NNPC = NPC + disp; 261 } else { 262 %(not_taken_code)s 263 } 264 ''' % { "code" : code, "not_taken_code" : not_taken_code } 265 266 iop = InstObjParams(name, Name, 'Branch', code, inst_flags) 267 header_output = BasicDeclare.subst(iop) 268 decoder_output = BasicConstructor.subst(iop) 269 decode_block = BasicDecode.subst(iop) 270 exec_output = BasicExecute.subst(iop) 271}}; 272 273def format DspBranch(code, *opt_flags) {{ 274 not_taken_code = 'NNPC = NNPC; NPC = NPC;' 275 276 #Build Instruction Flags 277 #Use Link & Likely Flags to Add Link/Condition Code 278 inst_flags = ('IsDirectControl', ) 279 for x in opt_flags: 280 if x == 'Link': 281 code += 'R32 = NNPC;' 282 elif x == 'Likely': 283 not_taken_code = 'NNPC = NPC, NPC = PC;' 284 inst_flags += ('IsCondDelaySlot', ) 285 else: 286 inst_flags += (x, ) 287 288 #Take into account uncond. branch instruction 289 if 'cond = 1' in code: 290 inst_flags += ('IsUncondControl', ) 291 else: 292 inst_flags += ('IsCondControl', ) 293 294 #Condition code 295 code = ''' 296 bool cond; 297 uint32_t dspctl = DSPControl; 298 %(code)s 299 if (cond) { 300 NNPC = NPC + disp; 301 } else { 302 %(not_taken_code)s 303 } 304 ''' % { "code" : code, "not_taken_code" : not_taken_code } 305 306 iop = InstObjParams(name, Name, 'Branch', code, inst_flags) 307 header_output = BasicDeclare.subst(iop) 308 decoder_output = BasicConstructor.subst(iop) 309 decode_block = BasicDecode.subst(iop) 310 exec_output = BasicExecute.subst(iop) 311}}; 312 313def format Jump(code, *opt_flags) {{ 314 #Build Instruction Flags 315 #Use Link Flag to Add Link Code 316 inst_flags = ('IsIndirectControl', 'IsUncondControl') 317 for x in opt_flags: 318 if x == 'Link': 319 code = ''' 320 R31 = NNPC; 321 ''' + code 322 elif x == 'ClearHazards': 323 code += '/* Code Needed to Clear Execute & Inst Hazards */\n' 324 else: 325 inst_flags += (x, ) 326 327 iop = InstObjParams(name, Name, 'Jump', code, inst_flags) 328 header_output = BasicDeclare.subst(iop) 329 decoder_output = BasicConstructor.subst(iop) 330 decode_block = BasicDecode.subst(iop) 331 exec_output = BasicExecute.subst(iop) 332}}; 333 334 335 336 337