base_dyn_inst_impl.hh revision 2678
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Kevin Lim 29 */ 30 31#include <iostream> 32#include <set> 33#include <string> 34#include <sstream> 35 36#include "base/cprintf.hh" 37#include "base/trace.hh" 38 39#include "arch/faults.hh" 40#include "cpu/exetrace.hh" 41#include "mem/request.hh" 42 43#include "cpu/base_dyn_inst.hh" 44#include "cpu/o3/alpha_impl.hh" 45#include "cpu/o3/alpha_cpu.hh" 46//#include "cpu/ozone/simple_impl.hh" 47//#include "cpu/ozone/ozone_impl.hh" 48 49using namespace std; 50using namespace TheISA; 51 52#define NOHASH 53#ifndef NOHASH 54 55#include "base/hashmap.hh" 56 57unsigned int MyHashFunc(const BaseDynInst *addr) 58{ 59 unsigned a = (unsigned)addr; 60 unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; 61 62 return hash; 63} 64 65typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> 66my_hash_t; 67 68my_hash_t thishash; 69#endif 70 71template <class Impl> 72BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC, 73 Addr pred_PC, InstSeqNum seq_num, 74 FullCPU *cpu) 75 : staticInst(machInst), traceData(NULL), cpu(cpu)/*, xc(cpu->xcBase())*/ 76{ 77 seqNum = seq_num; 78 79 PC = inst_PC; 80 nextPC = PC + sizeof(MachInst); 81 predPC = pred_PC; 82 83 initVars(); 84} 85 86template <class Impl> 87BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst) 88 : staticInst(_staticInst), traceData(NULL) 89{ 90 seqNum = 0; 91 initVars(); 92} 93 94template <class Impl> 95void 96BaseDynInst<Impl>::initVars() 97{ 98 req = NULL; 99 memData = NULL; 100 effAddr = 0; 101 physEffAddr = 0; 102 storeSize = 0; 103 104 readyRegs = 0; 105 106 // May want to turn this into a bit vector or something. 107 completed = false; 108 resultReady = false; 109 canIssue = false; 110 issued = false; 111 executed = false; 112 canCommit = false; 113 committed = false; 114 squashed = false; 115 squashedInIQ = false; 116 squashedInLSQ = false; 117 squashedInROB = false; 118 eaCalcDone = false; 119 memOpDone = false; 120 lqIdx = -1; 121 sqIdx = -1; 122 reachedCommit = false; 123 124 blockingInst = false; 125 recoverInst = false; 126 127 iqEntry = false; 128 robEntry = false; 129 130 serializeBefore = false; 131 serializeAfter = false; 132 serializeHandled = false; 133 134 // Eventually make this a parameter. 135 threadNumber = 0; 136 137 // Also make this a parameter, or perhaps get it from xc or cpu. 138 asid = 0; 139 140 // Initialize the fault to be unimplemented opcode. 141// fault = new UnimplementedOpcodeFault; 142 fault = NoFault; 143 144 ++instcount; 145 146 if (instcount > 1500) { 147 cpu->dumpInsts(); 148#ifdef DEBUG 149 dumpSNList(); 150#endif 151 assert(instcount <= 1500); 152 } 153 154 DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", 155 seqNum, instcount); 156 157#ifdef DEBUG 158 cpu->snList.insert(seqNum); 159#endif 160} 161 162template <class Impl> 163BaseDynInst<Impl>::~BaseDynInst() 164{ 165 if (req) { 166 delete req; 167 } 168 169 if (memData) { 170 delete [] memData; 171 } 172 173 if (traceData) { 174 delete traceData; 175 } 176 177 fault = NoFault; 178 179 --instcount; 180 181 DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", 182 seqNum, instcount); 183#ifdef DEBUG 184 cpu->snList.erase(seqNum); 185#endif 186} 187 188#ifdef DEBUG 189template <class Impl> 190void 191BaseDynInst<Impl>::dumpSNList() 192{ 193 std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin(); 194 195 int count = 0; 196 while (sn_it != cpu->snList.end()) { 197 cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it)); 198 count++; 199 sn_it++; 200 } 201} 202#endif 203 204template <class Impl> 205void 206BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags) 207{ 208 // This is the "functional" implementation of prefetch. Not much 209 // happens here since prefetches don't affect the architectural 210 // state. 211/* 212 // Generate a MemReq so we can translate the effective address. 213 MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); 214 req->asid = asid; 215 216 // Prefetches never cause faults. 217 fault = NoFault; 218 219 // note this is a local, not BaseDynInst::fault 220 Fault trans_fault = cpu->translateDataReadReq(req); 221 222 if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { 223 // It's a valid address to cacheable space. Record key MemReq 224 // parameters so we can generate another one just like it for 225 // the timing access without calling translate() again (which 226 // might mess up the TLB). 227 effAddr = req->vaddr; 228 physEffAddr = req->paddr; 229 memReqFlags = req->flags; 230 } else { 231 // Bogus address (invalid or uncacheable space). Mark it by 232 // setting the eff_addr to InvalidAddr. 233 effAddr = physEffAddr = MemReq::inval_addr; 234 } 235 236 if (traceData) { 237 traceData->setAddr(addr); 238 } 239*/ 240} 241 242template <class Impl> 243void 244BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags) 245{ 246 // Need to create a MemReq here so we can do a translation. This 247 // will casue a TLB miss trap if necessary... not sure whether 248 // that's the best thing to do or not. We don't really need the 249 // MemReq otherwise, since wh64 has no functional effect. 250/* 251 MemReqPtr req = new MemReq(addr, thread->getXCProxy(), size, flags); 252 req->asid = asid; 253 254 fault = cpu->translateDataWriteReq(req); 255 256 if (fault == NoFault && !(req->flags & UNCACHEABLE)) { 257 // Record key MemReq parameters so we can generate another one 258 // just like it for the timing access without calling translate() 259 // again (which might mess up the TLB). 260 effAddr = req->vaddr; 261 physEffAddr = req->paddr; 262 memReqFlags = req->flags; 263 } else { 264 // ignore faults & accesses to uncacheable space... treat as no-op 265 effAddr = physEffAddr = MemReq::inval_addr; 266 } 267 268 storeSize = size; 269 storeData = 0; 270*/ 271} 272 273/** 274 * @todo Need to find a way to get the cache block size here. 275 */ 276template <class Impl> 277Fault 278BaseDynInst<Impl>::copySrcTranslate(Addr src) 279{ 280/* 281 MemReqPtr req = new MemReq(src, thread->getXCProxy(), 64); 282 req->asid = asid; 283 284 // translate to physical address 285 Fault fault = cpu->translateDataReadReq(req); 286 287 if (fault == NoFault) { 288 thread->copySrcAddr = src; 289 thread->copySrcPhysAddr = req->paddr; 290 } else { 291 thread->copySrcAddr = 0; 292 thread->copySrcPhysAddr = 0; 293 } 294 return fault; 295*/ 296 return NoFault; 297} 298 299/** 300 * @todo Need to find a way to get the cache block size here. 301 */ 302template <class Impl> 303Fault 304BaseDynInst<Impl>::copy(Addr dest) 305{ 306/* 307 uint8_t data[64]; 308 FunctionalMemory *mem = thread->mem; 309 assert(thread->copySrcPhysAddr); 310 MemReqPtr req = new MemReq(dest, thread->getXCProxy(), 64); 311 req->asid = asid; 312 313 // translate to physical address 314 Fault fault = cpu->translateDataWriteReq(req); 315 316 if (fault == NoFault) { 317 Addr dest_addr = req->paddr; 318 // Need to read straight from memory since we have more than 8 bytes. 319 req->paddr = thread->copySrcPhysAddr; 320 mem->read(req, data); 321 req->paddr = dest_addr; 322 mem->write(req, data); 323 } 324 return fault; 325*/ 326 return NoFault; 327} 328 329template <class Impl> 330void 331BaseDynInst<Impl>::dump() 332{ 333 cprintf("T%d : %#08d `", threadNumber, PC); 334 cout << staticInst->disassemble(PC); 335 cprintf("'\n"); 336} 337 338template <class Impl> 339void 340BaseDynInst<Impl>::dump(std::string &outstring) 341{ 342 std::ostringstream s; 343 s << "T" << threadNumber << " : 0x" << PC << " " 344 << staticInst->disassemble(PC); 345 346 outstring = s.str(); 347} 348 349#if 0 350template <class Impl> 351Fault 352BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes) 353{ 354 Fault fault; 355 356 // check alignments, even speculative this test should always pass 357 if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) { 358 for (int i = 0; i < nbytes; i++) 359 ((char *) p)[i] = 0; 360 361 // I added the following because according to the comment above, 362 // we should never get here. The comment lies 363#if 0 364 panic("unaligned access. Cycle = %n", curTick); 365#endif 366 return NoFault; 367 } 368 369 MemReqPtr req = new MemReq(addr, thread, nbytes); 370 switch(cmd) { 371 case Read: 372 fault = spec_mem->read(req, (uint8_t *)p); 373 break; 374 375 case Write: 376 fault = spec_mem->write(req, (uint8_t *)p); 377 if (fault != NoFault) 378 break; 379 380 specMemWrite = true; 381 storeSize = nbytes; 382 switch(nbytes) { 383 case sizeof(uint8_t): 384 *(uint8_t)&storeData = (uint8_t *)p; 385 break; 386 case sizeof(uint16_t): 387 *(uint16_t)&storeData = (uint16_t *)p; 388 break; 389 case sizeof(uint32_t): 390 *(uint32_t)&storeData = (uint32_t *)p; 391 break; 392 case sizeof(uint64_t): 393 *(uint64_t)&storeData = (uint64_t *)p; 394 break; 395 } 396 break; 397 398 default: 399 fault = genMachineCheckFault(); 400 break; 401 } 402 403 trace_mem(fault, cmd, addr, p, nbytes); 404 405 return fault; 406} 407 408#endif 409 410template <class Impl> 411void 412BaseDynInst<Impl>::markSrcRegReady() 413{ 414 if (++readyRegs == numSrcRegs()) { 415 canIssue = true; 416 } 417} 418 419template <class Impl> 420void 421BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx) 422{ 423 ++readyRegs; 424 425 _readySrcRegIdx[src_idx] = true; 426 427 if (readyRegs == numSrcRegs()) { 428 canIssue = true; 429 } 430} 431 432template <class Impl> 433bool 434BaseDynInst<Impl>::eaSrcsReady() 435{ 436 // For now I am assuming that src registers 1..n-1 are the ones that the 437 // EA calc depends on. (i.e. src reg 0 is the source of the data to be 438 // stored) 439 440 for (int i = 1; i < numSrcRegs(); ++i) { 441 if (!_readySrcRegIdx[i]) 442 return false; 443 } 444 445 return true; 446} 447 448// Forward declaration 449template class BaseDynInst<AlphaSimpleImpl>; 450 451template <> 452int 453BaseDynInst<AlphaSimpleImpl>::instcount = 0; 454/* 455// Forward declaration 456template class BaseDynInst<SimpleImpl>; 457 458template <> 459int 460BaseDynInst<SimpleImpl>::instcount = 0; 461 462// Forward declaration 463template class BaseDynInst<OzoneImpl>; 464 465template <> 466int 467BaseDynInst<OzoneImpl>::instcount = 0; 468*/ 469